Qt/Utilities/HandleItem

From ProgrammingExamples
< Qt
Jump to: navigation, search

HandleItem.cpp

#include <QApplication>
 
#include "form.h"
 
int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  Form form;
 
  form.show();
  return app.exec();
}

form.h

#ifndef FORM_H
#define FORM_H
 
#include "ui_form.h"
 
class Form : public QWidget, private Ui::Form
{
    Q_OBJECT
 
public slots:
 
public:
    Form(QWidget *parent = 0);
 
};
 
#endif

form.cpp

#include <QtGui>
 
#include "form.h"
#include "HandleItem.h"
 
#include <iostream>
 
Form::Form(QWidget *parent) : QWidget(parent)
{
  setupUi(this);
 
  QGraphicsScene* scene = new QGraphicsScene( 0, 0, 200, 200 );
  QGraphicsRectItem *rectItem = new QGraphicsRectItem( QRect( 10, 10, 50, 100 ), 0, scene );
 
  // The center handle must know about all of the other handles so it can translate them with the object
  HandleItem *topHandle = new HandleItem( rectItem, scene, Qt::red, HandleItem::TopHandle );
  HandleItem *rightHandle = new HandleItem( rectItem, scene, Qt::red, HandleItem::RightHandle );
  HandleItem *leftHandle = new HandleItem( rectItem, scene, Qt::red, HandleItem::LeftHandle );
  HandleItem *bottomHandle = new HandleItem( rectItem, scene, Qt::red, HandleItem::BottomHandle );
  HandleItem *centerHandle = new HandleItem( rectItem, scene, Qt::red, HandleItem::CenterHandle, QList<HandleItem*>() << topHandle << rightHandle << leftHandle << bottomHandle );
 
  this->graphicsView->setScene( scene );
 
}

HandleItem.h

#ifndef HANDLEITEM_H
#define HANDLEITEM_H
 
#include <QGraphicsItem>
#include <QGraphicsRectItem>
 
class HandleItem;
 
class HandleItem : public QGraphicsItem
{
public:
 
  enum HandleRole
  {
    CenterHandle,
    RightHandle,
    TopHandle,
    LeftHandle,
    BottomHandle
  };
 
  HandleItem( QGraphicsRectItem *item, QGraphicsScene *scene, QColor color, HandleRole role = CenterHandle, QList<HandleItem*> handles = QList<HandleItem*>() );
 
  void paint( QPainter *paint, const QStyleOptionGraphicsItem *option, QWidget *widget );
  QRectF boundingRect() const;
 
protected:
  void mousePressEvent( QGraphicsSceneMouseEvent *event );
  void mouseReleaseEvent( QGraphicsSceneMouseEvent *event );
 
  QVariant itemChange( GraphicsItemChange change, const QVariant &data );
 
private:
  QGraphicsRectItem *m_item;
 
  HandleRole m_role;
  QColor m_color;
 
  QList<HandleItem*> m_handles;
 
  bool m_pressed;
};
 
#endif // HANDLEITEM_H

HandleItem.cpp

#include "HandleItem.h"
 
#include <QPainter>
#include <QPointF>
 
#include <cmath>
#include <iostream>
 
HandleItem::HandleItem( QGraphicsRectItem *item, QGraphicsScene *scene, QColor color, HandleItem::HandleRole role, QList<HandleItem*> handles ) : QGraphicsItem( 0, scene )
{
  m_role = role;
  m_color = color;
 
  m_item = item;
  m_handles = handles;
 
  m_pressed = false;
  setZValue( 100 );
 
  setFlag( ItemIsMovable );
  setFlag(ItemSendsGeometryChanges);
}
 
void HandleItem::paint( QPainter *paint, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
  paint->setPen( m_color );
  paint->setBrush( m_color );
 
  QRectF rect = boundingRect();
  QVector<QPointF> points;
 
  switch( m_role )
  {
  case RightHandle:
    points << rect.center()+QPointF(3,0) << rect.center()+QPointF(-3,-5) << rect.center()+QPointF(-3,5);
    paint->drawConvexPolygon( QPolygonF(points) );
    break;
  case LeftHandle:
    points << rect.center()+QPointF(-3,0) << rect.center()+QPointF(3,-5) << rect.center()+QPointF(3,5);
    paint->drawConvexPolygon( QPolygonF(points) );
    break;
  case TopHandle:
    points << rect.center()+QPointF(0,-3) << rect.center()+QPointF(-5,3) << rect.center()+QPointF(5,3);
    paint->drawConvexPolygon( QPolygonF(points) );
    break;
  case BottomHandle:
    points << rect.center()+QPointF(0,3) << rect.center()+QPointF(-5,-3) << rect.center()+QPointF(5,-3);
    paint->drawConvexPolygon( QPolygonF(points) );
    break;
  }
}
 
 
QRectF HandleItem::boundingRect() const
{
  switch( m_role )
  {
  case LeftHandle:
    {
    QPointF point(m_item->boundingRect().left() - pos().x(), m_item->boundingRect().top() + m_item->boundingRect().height()/2);
    return QRectF( point-QPointF(3, 5), QSize( 6, 10 ) );
    }
  case RightHandle:
    {
    QPointF point(m_item->boundingRect().right() - pos().x(), m_item->boundingRect().top() + m_item->boundingRect().height()/2);
    return QRectF( point-QPointF(3, 5), QSize( 6, 10 ) );
    }
  case TopHandle:
    {
    QPointF point(m_item->boundingRect().left() + m_item->boundingRect().width()/2, m_item->boundingRect().top() - pos().y());
    return QRectF( point-QPointF(5, 3), QSize( 10, 6 ) );
    }
  case BottomHandle:
    {
    QPointF point(m_item->boundingRect().left() + m_item->boundingRect().width()/2, m_item->boundingRect().bottom() - pos().y());
    return QRectF( point-QPointF(5, 3), QSize( 10, 6 ) );
    }
  }
 
  return QRectF();
}
 
QVariant HandleItem::itemChange( GraphicsItemChange change, const QVariant &data )
{
  if( change == ItemPositionChange && m_pressed )
  {
 
    QPointF movement;
    QPointF newData = data.toPointF();
    QRectF newRect = m_item->rect();
 
    switch( m_role )
    {
    case LeftHandle:
      {
      // Prevent the rectangle from collapsing.
      //if( fabs(movement.x()) <= 5 )
      if(m_item->rect().width() < 5)
        {
        std::cout << "too small! " << std::endl;
        return QGraphicsItem::itemChange( change, newData );
        }
 
      // Snap the movement to the X direction
      newData.setY(0);
 
      movement = newData - pos();
      // Resize the rectangle
      newRect.setLeft(m_item->rect().left() + movement.x());
 
      m_item->setRect(newRect);
 
      break;
      }
    case RightHandle:
      {
      // Prevent the rectangle from collapsing.
      //if( fabs(movement.x()) <= 5 )
      //if(m_item->rect().width() < 5)
      if(m_item->rect().width() + movement.x() < 5)
	{
	std::cout << "too small! " << std::endl;
	return QGraphicsItem::itemChange( change, newData );
	}
 
      // Snap the movement to the X direction
      newData.setY(0);
 
      movement = newData - pos();
      // Resize the rectangle
      newRect.setRight(m_item->rect().right() + movement.x());
 
      m_item->setRect(newRect);
 
      break;
      }
    case TopHandle:
      {
      // Prevent the rectangle from collapsing.
      //if( fabs(movement.x()) <= 5 )
      if(m_item->rect().height() < 5)
        {
        std::cout << "too small! " << std::endl;
        return QGraphicsItem::itemChange( change, newData );
        }
 
      // Snap the movement to the Y direction
      newData.setX(0);
 
      movement = newData - pos();
      // Resize the rectangle
      newRect.setTop(m_item->rect().top() + movement.y());
 
      m_item->setRect(newRect);
 
      break;
      }
    case BottomHandle:
      {
      // Prevent the rectangle from collapsing.
      //if( fabs(movement.x()) <= 5 )
      if(m_item->rect().height() < 5)
        {
        std::cout << "too small! " << std::endl;
        return QGraphicsItem::itemChange( change, newData );
        }
 
      // Snap the movement to the Y direction
      newData.setX(0);
 
      movement = newData - pos();
      // Resize the rectangle
      newRect.setBottom(m_item->rect().bottom() + movement.y());
 
      m_item->setRect(newRect);
 
      break;
      }
    } // end switch
 
    return QGraphicsItem::itemChange( change, newData);
  } // end if pressed
 
  return QGraphicsItem::itemChange( change, data );
}
 
void HandleItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
{
  m_pressed = true;  
  QGraphicsItem::mousePressEvent( event );
}
 
void HandleItem::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )
{
  m_pressed = false;
  QGraphicsItem::mouseReleaseEvent( event );
}

form.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QGraphicsView" name="graphicsView">
   <property name="geometry">
    <rect>
     <x>80</x>
     <y>50</y>
     <width>256</width>
     <height>192</height>
    </rect>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
 
PROJECT(HandleItem)
 
FIND_PACKAGE(Qt4 REQUIRED)
INCLUDE(${QT_USE_FILE})
 
QT4_WRAP_UI(UISrcs form.ui)
QT4_WRAP_CPP(MOCSrcs form.h)
 
include_directories(${include_directories} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
 
ADD_EXECUTABLE(HandleItem main.cpp HandleItem.cpp form.cpp ${MOCSrcs} ${UISrcs})
TARGET_LINK_LIBRARIES(HandleItem ${QT_LIBRARIES})