Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: DarkHobbit от Март 08, 2014, 12:09



Название: [Решено] Drag-n-drop QGraphicsItem по одной координате. Сцена "съезжает"
Отправлено: DarkHobbit от Март 08, 2014, 12:09
Добрый день.
Мне потребовалось перетаскивать графические элементы не по двум координатам (как это делается по умолчанию, например, в примере chip),  а только по одной (двигаю флажки вдоль оси OX). Я перекрыл обработку событий от мыши, в первую очередь, mouseMoveEvent. Вот слегка почищенный код класса Flag (наследника QGraphicsItem):
Код
C
Flag::Flag(const QString& name, const QColor& color):
   _name(name), _color(color)
{
   setFlags(ItemIsSelectable | ItemIsMovable);
   setAcceptHoverEvents(true);
}
 
void Flag::paint(QPainter *p, const QStyleOptionGraphicsItem *item, QWidget *widget)
{
   int height = FLAG_HEIGHT;
   int dX = -FLAG_WIDTH;
   p->setPen(_color);
   p->drawLine(0, 1, 0, FLAG_HEIGHT);
   p->drawLine(0, FLAG_HEIGHT, dX, FLAG_HEIGHT-FLAG_SUBHEIGHT/2);
   p->drawLine(dX, FLAG_HEIGHT-FLAG_SUBHEIGHT/2, 0, FLAG_HEIGHT-FLAG_SUBHEIGHT);
}
 
QRectF Flag::boundingRect() const
{
   return QRectF(-FLAG_WIDTH+1, 2, FLAG_WIDTH, FLAG_HEIGHT);
}
 
void Flag::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
   QGraphicsItem::mousePressEvent(event);
   update();
}
 
void Flag::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
   // Set new position
   int newX = event->scenePos().x();
   setPos(newX, 1);
}
 
void Flag::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
   QGraphicsItem::mouseReleaseEvent(event);
}
Вот фрагменты конструктора главного окна:
Код
C
   view = new QGraphicsView(ui->frame);
   QVBoxLayout *layout = new QVBoxLayout;
   layout->addWidget(view);
   ui->frame->setLayout(layout);
...
   QGraphicsScene* scene = new QGraphicsScene;
   view->setScene(scene);
...
   Flag* flag = new Flag("magenta", Qt::magenta);
   view->scene()->addItem(flag);
   flag = new Flag("black", Qt::black);
   view->scene()->addItem(flag);
   flag->setPos(80, 0);
При запуске программы на экране появляются два флажка. Я действительно могу их перетаскивать мышью, но при этом второй флаг "съезжает" в другую сторону. Судя по более сложному примеру, в котором были не только флажки, сдвигается вся сцена.
Насколько я могу судить, это связано с тем, что в начале работы у сцены нулевая ширина, по мере вызова setPos для элементов она расширяется, и Qt пытается его отцентровать относительно QGrapgicsView, через который идёт отображение.
Я сделал временное решение. В том же конструкторе главного окна сделал принудительную установку размера сцены по виджету:
Код
C
   int w = view->width();
   int h = view->height();
   scene->setSceneRect(-w/2, -h/2, w, h);
Вроде бы проблема ушла. Но мне интуиция подсказывает, что это костыль, который может к тому же отказать при каком-нибудь "хитром" ресайзе, хотя пока я такого не добился.
Есть ли более нормальное решение? Например, как-то отключить эту автоматическую центровку вообще...
Проблема проверена на Qt 4.6 и 4.8.4 в Windows и Linux.
Спасибо.


Название: Re: Drag-n-drop QGraphicsItem по одной координате. Сцена "съезжает"
Отправлено: Hrundel от Март 09, 2014, 02:52
Насколько я могу судить, это связано с тем, что в начале работы у сцены нулевая ширина, по мере вызова setPos для элементов она расширяется, и Qt пытается его отцентровать относительно QGrapgicsView, через который идёт отображение.

При нулевых параметрах сцена автоматически устанавливает ширину.

Я сделал временное решение. В том же конструкторе главного окна сделал принудительную установку размера сцены по виджету:
Вроде бы проблема ушла. Но мне интуиция подсказывает, что это костыль, который может к тому же отказать при каком-нибудь "хитром" ресайзе, хотя пока я такого не добился.
Есть ли более нормальное решение? Например, как-то отключить эту автоматическую центровку вообще...

Правильное решение. Это не костыль - это так и должно быть. Дальше просто программно обрабатывать boundingRect для сцены.

А, вообще, решение нужно разрабатывать исходя из задачи. Флажки должны передвигаться в ограниченном или "неограниченном" пространстве?
Для "неограниченных" пространств, наверное лучше использовать QGLWidget. Для ограниченых - задать ширину и высоту сцены (как уже и сделано), на памяти это не отразится не взирая на размеры.


Название: Re: Drag-n-drop QGraphicsItem по одной координате. Сцена "съезжает"
Отправлено: DarkHobbit от Март 22, 2014, 15:40
Спасибо, успокоили.