Russian Qt Forum
Ноябрь 23, 2024, 03:54 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [Решено] Drag-n-drop QGraphicsItem по одной координате. Сцена "съезжает"  (Прочитано 3550 раз)
DarkHobbit
Самовар
**
Offline Offline

Сообщений: 197


Просмотр профиля
« : Март 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.
Спасибо.
« Последнее редактирование: Март 22, 2014, 15:40 от DarkHobbit » Записан

Мои проекты на Qt: DoubleContact, LInvert
Hrundel
Гость
« Ответ #1 : Март 09, 2014, 02:52 »

Насколько я могу судить, это связано с тем, что в начале работы у сцены нулевая ширина, по мере вызова setPos для элементов она расширяется, и Qt пытается его отцентровать относительно QGrapgicsView, через который идёт отображение.

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

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

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

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

Сообщений: 197


Просмотр профиля
« Ответ #2 : Март 22, 2014, 15:40 »

Спасибо, успокоили.
Записан

Мои проекты на Qt: DoubleContact, LInvert
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.079 секунд. Запросов: 22.