Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: serega-5508 от Апрель 02, 2011, 23:41



Название: изменение размера фигур
Отправлено: serega-5508 от Апрель 02, 2011, 23:41
Вопрос такой, я рисую на прямоугольник на QGraphicsScene. Могу его перемещать по сцене (QGraphicsView). А вот как мне сделать так, чтобы я мог изменять размер этого прямоугольника, когда подвозу курсор к углу прямоугольника???


Название: Re: изменение размера фигур
Отправлено: madRoger от Апрель 03, 2011, 01:52
Я наследовался от QGraphicsItem. Переопределял mousePressEvent, mouseMoveEvent. Отслеживал нажатие клавиши мыши и перемещение при нажатой клавише. Далее рассчитывал изменение координат и строил матрицу трансформации.
Для изменения размеров самого итема использовал QGraphicsItem::setTransform.
Можно также использовать QGraphicsItem::setScale.


Название: Re: изменение размера фигур
Отправлено: serega-5508 от Апрель 05, 2011, 23:29
madRoger, можете представить свой код или скинуть посмотреть прогу?

у кого-нибудь есть ещё варианты и хоть часть кода?


Название: Re: изменение размера фигур
Отправлено: madRoger от Апрель 06, 2011, 00:10
.h
Код:
#include <QGraphicsItem>

class MyItem : public QGraphicsItem
{
public:
   enum PointType { None,
   ResizeLeftTop, ResizeTop, ResizeRightTop,
   ResizeLeft, ResizeRight, ResizeLeftBottom,
   ResizeBottom, ResizeRightBottom, Rotate, Move
   };

  MyItem( QGraphicsItem* parent = 0 );
  QRectF boundingRect() const;
  void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                QWidget *widget);
private:
  PointType pointTypeAtPos( const QPointF &pos ) const;
  void setCursorShape( const QPointF &pos );

   qreal w,h;

  PointType pointType;
  QPointF startItemPoint;
  QPointF startMousePoint;
  qreal kx,ky,alpha;
  qreal kx0,ky0,alpha0;
  QTransform transform, transform_inv;

protected:
  void mousePressEvent( QGraphicsSceneMouseEvent *event );
  void mouseMoveEvent ( QGraphicsSceneMouseEvent *event );
  void hoverMoveEvent ( QGraphicsSceneHoverEvent *event );
};
.cpp
Код:

#include <QtGui>
#include "item.h"

MyItem::MyItem( QGraphicsItem * parent )
  : QGraphicsItem( parent )
{
  setFlags( QGraphicsItem::ItemIsSelectable );

  w = 50;
  h = 50;
  pointType = None;
  kx=ky=1.0;
  alpha=0.0;

  setAcceptHoverEvents ( true );
 }

QRectF MyItem::boundingRect() const
{
  const qreal border = 5;
  return QRectF( -w/2-border, -h/2-border, w+2*border, h+2*border );
}

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                QWidget *widget)
{
  Q_UNUSED(option);
  Q_UNUSED(widget);
  painter->drawRect( -w/2, -h/2,  w, h );
}

void MyItem::mousePressEvent( QGraphicsSceneMouseEvent *event )
{
  QGraphicsItem::mousePressEvent( event );

  if( !isSelected() ) return;

  if(event->button() == Qt::LeftButton)
  {
    startMousePoint      = event->scenePos();
    startItemPoint       = scenePos();
    pointType            = pointTypeAtPos( event->pos() );
    setCursorShape( event->pos() );
    kx0 = kx;
    ky0 = ky;
    alpha0 = alpha;

    QPointF p0;
    switch( pointType )
    { case( ResizeLeftTop ):     p0 = QPointF(  w/2,  h/2 ); break;
      case( ResizeTop ):         p0 = QPointF(    0,  h/2 ); break;
      case( ResizeRightTop ):    p0 = QPointF( -w/2,  h/2 ); break;
      case( ResizeLeft ):        p0 = QPointF(  w/2,    0 ); break;
      case( ResizeRight ):       p0 = QPointF( -w/2,    0 ); break;
      case( ResizeLeftBottom ):  p0 = QPointF(  w/2, -h/2 ); break;
      case( ResizeBottom ):      p0 = QPointF(    0, -h/2 ); break;
      case( ResizeRightBottom ): p0 = QPointF( -w/2, -h/2 ); break;
      default:;
    }
    p0 = mapToScene( p0 );

    transform.reset();
    transform.rotateRadians( -alpha0 );
    transform.translate( -p0.x(), -p0.y() );

    transform_inv = transform.inverted();
  }
}

void MyItem::mouseMoveEvent( QGraphicsSceneMouseEvent *event )
{
  QGraphicsItem::mouseMoveEvent( event );

  if( !isSelected() ) return;

  if( pointType == None ) return;

  if( pointType == Move )
  {
    QPointF p = startItemPoint + event->scenePos() - startMousePoint;
    setPos( mapToParent( mapFromScene( p ) ) );
    return;
  }

  if( pointType != Rotate )
  {
    QPointF pm = transform.map( startMousePoint );
    QPointF pi = transform.map( startItemPoint );
    QPointF pp = transform.map( event->scenePos() );

    qreal kxx = pp.x() / pm.x();
    qreal kyy = pp.y() / pm.y();

    switch( pointType )
    { case( ResizeTop ):
      case( ResizeBottom ):
        kxx = 1;
        break;
      case( ResizeLeft ):
      case( ResizeRight ):
        kyy = 1;
        break;
      default:;
    }

    kx = kx0 * kxx;
    ky = ky0 * kyy;

    qreal xx = pi.x() * kxx;
    qreal yy = pi.y() * kyy;

    QTransform tr;
    tr.rotateRadians( alpha0 );
    tr.scale( kx,ky );

    setTransform( tr );
    setPos( mapToParent( mapFromScene( transform_inv.map( QPointF(xx,yy) ) ) ) );
    return;
  }

  if( pointType == Rotate )
  {
    QPointF p1 = transform.map( startMousePoint );
    QPointF p2 = transform.map( event->scenePos() );

    alpha = alpha0 + atan2( p2.y(), p2.x() ) - atan2( p1.y(), p1.x() );

    QTransform tr;
    tr.rotateRadians( alpha );
    tr.scale( kx,ky );
    setTransform( tr );
    return;
  }
}

void MyItem::hoverMoveEvent ( QGraphicsSceneHoverEvent * event )
{
  if(isSelected())
  {
    setCursorShape( event->pos() );
  } else
  { setCursor(Qt::ArrowCursor);
  }
}

void MyItem::setCursorShape( const QPointF &pos )
{
  switch( pointTypeAtPos( pos ) )
  {
   case( ResizeLeftTop ):     setCursor(Qt::SizeFDiagCursor); break;
   case( ResizeTop ):         setCursor(Qt::SizeVerCursor);   break;
   case( ResizeRightTop ):    setCursor(Qt::SizeBDiagCursor); break;
   case( ResizeLeft ):        setCursor(Qt::SizeHorCursor);   break;
   case( ResizeRight ):       setCursor(Qt::SizeHorCursor);   break;
   case( ResizeLeftBottom ):  setCursor(Qt::SizeBDiagCursor); break;
   case( ResizeBottom ):      setCursor(Qt::SizeVerCursor);   break;
   case( ResizeRightBottom ): setCursor(Qt::SizeFDiagCursor); break;
   case( Rotate ):            setCursor(Qt::SizeAllCursor);   break;
   case( Move ):              setCursor(Qt::OpenHandCursor);  break;
   default:
    setCursor(Qt::ArrowCursor);
  }
}

inline static qreal norm( qreal x, qreal y )
{
  return sqrt( x*x + y*y );
}

MyItem::PointType MyItem::pointTypeAtPos(  const QPointF &pos  ) const
{
  qreal x   = pos.x();
  qreal y   = pos.y();
  qreal dx  = w/50;
  qreal dy  = h/50;
  qreal dxy = qMax( dx,dy );

  if( norm( -w/2-x, -h/2-y ) < dxy ) return ResizeLeftTop;
  if( norm(  w/2-x, -h/2-y ) < dxy ) return ResizeRightTop;
  if( norm( -w/2-x,  h/2-y ) < dxy ) return ResizeLeftBottom;
  if( norm(  w/2-x,  h/2-y ) < dxy ) return ResizeRightBottom;

  if( fabs( -w/2-x ) < dx ) return ResizeLeft;
  if( fabs(  w/2-x ) < dx ) return ResizeRight;
  if( fabs( -h/2-y ) < dy ) return ResizeTop;
  if( fabs(  h/2-y ) < dy ) return ResizeBottom;

  if( fabs( -w/2-x+2*dx ) < dx ) return Rotate;
  if( fabs(  w/2-x-2*dx ) < dx ) return Rotate;
  if( fabs( -h/2-y+2*dy ) < dy ) return Rotate;
  if( fabs(  h/2-y-2*dy ) < dy ) return Rotate;

  return Move;
}

Реализация немного специфична т.к. писал под конкретную задачу.  Но суть та же. Еще есть поддержка вращения.


Название: Re: изменение размера фигур
Отправлено: serega-5508 от Апрель 06, 2011, 00:41
madRoger, спасибо. посмотрю, если возникнут вопросы, обращусь!