Название: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 10:40
Не удается заставить правильно перемещаться визир. Визир (QFrame) находится в виджете GraphicDisplay, точнее список визиров. C++ (Qt) /// Класс для переопределения виджета каждого визира class VFFrame: public QFrame { Q_OBJECT private: QPoint _move_point; ///< точка целеуказания, куда необходимо двигать signals: void moveVF(); public: void setMovePoint(const QPoint& pnt) { _move_point = pnt; } }; /// Передвижение визира вслед за мышью void VFFrame::mouseMoveEvent(QMouseEvent* events) { QFrame::mouseMoveEvent(events); emit moveVF(); if(!_is_left_pressed) return; if(_vf_shape == QFrame::VLine) setGeometry(_move_point.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) setGeometry(x(), _move_point.y(), width(), height()); } /// Отпускание кнопки мыши void VFFrame::mouseReleaseEvent(QMouseEvent* events) { QFrame::mouseReleaseEvent(events); emit moveVF(); if(!_is_left_pressed) return; _is_left_pressed = false; if(_vf_shape == QFrame::VLine) setGeometry(_move_point.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) setGeometry(x(), _move_point.y(), width(), height()); _is_viewfinder = false; } /// Изменение размеров окна void VFFrame::resizeEvent(QResizeEvent* events) { if(_vf_shape == QFrame::VLine) setGeometry(x(), 0, 16, parentWidget() -> height()); else if(_vf_shape == QFrame::HLine) setGeometry(0, y(), parentWidget() -> width(), 16); } /// Класс для отображения параметров по времени или по расстоянию class GraphicDisplay : public QDialog, public Ui::GraphicDisplayClass { Q_OBJECT private: QList<VFFrame*> viewfinderList; ///< список всех визиров QPoint _move_pointVF; ///< точка, куда следует перемещаться визир void connectViewfinder(); void disconnectViewfinder(); private slots: void setMovePoint(); }; /// Проверка на попадание фокуса на визир bool GraphicDisplay::isViewfinder(const QPoint& pos) { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { _move_pointVF = pos; return true; } return false; } /// Подсоединение сигнала void GraphicDisplay::connectViewfinder() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { connect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint())); break; } } /// Разъединение сигнала void GraphicDisplay::disconnectViewfinder() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { disconnect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint())); break; } } /// Нажатие на кнопку - рисование "резиновой ленты" void GraphicDisplay::mousePressEvent(QMouseEvent* events) { QWidget::mousePressEvent(events); if(isViewfinder(events -> pos())) { connectViewfinder(); return; } // .................................... } /// Переопределение функции передвижения мыши void GraphicDisplay::mouseMoveEvent(QMouseEvent* events) { if(isViewfinder(events -> pos())) return; // ............................................. } /// Возвращение прежнего вида курсору и изменение масштаба void GraphicDisplay::mouseReleaseEvent(QMouseEvent* events) { if(isViewfinder(events -> pos())) { disconnectViewfinder(); return; } // .................................................................... }
Смысл в том, что во время движения в координату _move_point записывается предыдущее значение, т.к. движение мыша функций GraphicDisplay попадает позже, чем в движение мыша функций VFFrame. Как все-таки добиться эффекта, чтобы в функцию setMovePoint класса VFFrame передавалось значение events -> pos() класса GraphicDisplay?
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 13:02
Есть хоть какие-нибудь идеи, как можно откорректировать код? Ну хоть подтолкните, пожалуйста, на мысль, как выправить код. Как сделать перемещение визира плавным, а не скачкообразным?
Название: Re: Перемещение QFrame
Отправлено: spectre71 от Июль 24, 2009, 13:15
Есть хоть какие-нибудь идеи, как можно откорректировать код? Ну хоть подтолкните, пожалуйста, на мысль, как выправить код. Как сделать перемещение визира плавным, а не скачкообразным?
Из твоего описания и кода непонятно что ты хочешь сделать! Например говоришь о "_move_point", а в твоем коде она нигде не изменяется.
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 13:50
setMovePoint() ее меняет. Мне необходимо, чтобы движение визира шло плавно, а не скачками назад-вперед. Вот так изменяет setMovePoint: C++ (Qt) // in header private slots: void setMovePoint(); /// Слот установки экранных координат во фрейм визира void GraphicDisplay::setMovePoint() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { pf -> setMovePoint(_move_pointVF); break; } }
Название: Re: Перемещение QFrame
Отправлено: ufna от Июль 24, 2009, 13:54
а в целом код данного куска можешь выложить? или это комм. тайна?
скачки взад-вперед происходят видимо по причинетого, что функция, идущей второй, кидает виджет на бывшее значение. Вывод - нужно из первого эвента менять некий флаг во втором или еще что, запрещающий "кидать назад".
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 14:12
Так я все, что относится к этому коду и выложил. Все, что идет далее в функция QGraphicDisplay::mouse....Event - Это масштабирование самого графика.
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 14:16
Вот еще раз код: C++ (Qt) /// Класс для переопределения виджета каждого визира class VFFrame: public QFrame { Q_OBJECT private: Shape _vf_shape; ///< форма визира (вертикальный или горизонтальный) bool _is_left_pressed; ///< флаг указания нажатия на левую кнопку мыши bool _is_viewfinder; ///< флаг сигнализации о наведении курсора мыши на визир QPoint _move_point; ///< точка целеуказания, куда необходимо двигать signals: void moveVF(); protected: virtual void mousePressEvent(QMouseEvent* events); virtual void mouseMoveEvent(QMouseEvent* events); virtual void mouseReleaseEvent(QMouseEvent* events); virtual void resizeEvent(QResizeEvent* events); virtual void enterEvent(QEvent* events) { _is_viewfinder = true; } virtual void leaveEvent(QEvent* events) { _is_viewfinder = false; } public: VFFrame(QWidget *parent, const Shape shape = QFrame::VLine); virtual ~VFFrame() {} void setShape(const Shape shape) { setFrameShape(shape); _vf_shape = shape; } bool isViewfinder() const { return _is_viewfinder; } void setMovePoint(const QPoint& pnt) { _move_point = pnt; } }; /// Переопределение нажатия на лекую кнопку мыши void VFFrame::mousePressEvent(QMouseEvent* events) { QFrame::mousePressEvent(events); emit moveVF(); switch(events -> button()) { case Qt::LeftButton: ///< если нажата левая кнопка мыши _is_left_pressed = true; break; } } /// Передвижение визира вслед за мышью void VFFrame::mouseMoveEvent(QMouseEvent* events) { QFrame::mouseMoveEvent(events); emit moveVF(); if(!_is_left_pressed) return; if(_vf_shape == QFrame::VLine) setGeometry(_move_point.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) setGeometry(x(), _move_point.y(), width(), height()); } /// Отпускание кнопки мыши void VFFrame::mouseReleaseEvent(QMouseEvent* events) { QFrame::mouseReleaseEvent(events); emit moveVF(); if(!_is_left_pressed) return; _is_left_pressed = false; if(_vf_shape == QFrame::VLine) setGeometry(_move_point.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) setGeometry(x(), _move_point.y(), width(), height()); _is_viewfinder = false; } /// Слот установки экранных координат во фрейм визира void GraphicDisplay::setMovePoint() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { pf -> setMovePoint(_move_pointVF); break; } } /// Проверка на попадание фокуса на визир bool GraphicDisplay::isViewfinder(const QPoint& pos) { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { _move_pointVF = pos; return true; } return false; } /// Подсоединение сигнала void GraphicDisplay::connectViewfinder() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { connect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint())); break; } } /// Разъединение сигнала void GraphicDisplay::disconnectViewfinder() { foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { disconnect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint())); break; } } /// Копирование визиров void GraphicDisplay::copyingViewfinder(QMouseEvent* events) { if(events -> button() != Qt::LeftButton || events -> modifiers() != Qt::ControlModifier) return; foreach(VFFrame* pf, viewfinderList) if(pf -> isViewfinder()) { appendViewfinder(pf -> frameShape()); break; } } /// Нажатие на кнопку - рисование "резиновой ленты" void GraphicDisplay::mousePressEvent(QMouseEvent* events) { QWidget::mousePressEvent(events); if(isViewfinder(events -> pos())) { copyingViewfinder(events); connectViewfinder(); return; } // ................... } /// Переопределение функции передвижения мыши void GraphicDisplay::mouseMoveEvent(QMouseEvent* events) { if(isViewfinder(events -> pos())) return; // ...................... } /// Возвращение прежнего вида курсору и изменение масштаба void GraphicDisplay::mouseReleaseEvent(QMouseEvent* events) { if(isViewfinder(events -> pos())) { disconnectViewfinder(); return; } }
Название: Re: Перемещение QFrame
Отправлено: spectre71 от Июль 24, 2009, 14:45
Не стал особо разбираться, но если правильно понял, то установка новых координат происходит по сигналу moveVF. Так почему бы не передавать через него необходимую координату?
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 15:17
Понял правильно. Беда в том, что правильные координаты в функция mouse....Event класса GraphicDisplay!
Название: Re: Перемещение QFrame
Отправлено: ufna от Июль 24, 2009, 15:38
а почему нельзя сделать VFFrame доступ к GraphicDisplay? А в нем функцию, которая из отданных в него координат мыши вернет правильные координаты. Или наоборот, я не вникал кто чем двигает.
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 15:49
Корректные координаты доступны в защищенных функциях mouse....Event класса GraphicDisplay. Каким образом организовать доступ? Если бы знал, сам бы сделал, не спрашивая! :)
Название: Re: Перемещение QFrame
Отправлено: ufna от Июль 24, 2009, 15:55
имхо, можно так: визир (это такая линия типа?) при нажатии на него делает grabMouse(); после этого, перемещение его идет только в его собственном мув эвенте. Подстройка идет под координаты мыши однозначно.
зачем в принципе в этом должен учавствовать GraphicDisplay?
и еще - можешь скомпилированный вариант выложить, чтобы увидеть как оно в деле? Еще есть идея, но вначале хочется убедиться.
либо так - в сиих функциях у визира не делается ничего, кроме установки внутрь себя флажка нажат/не нажат. А график дисплей в своем мув эвенте обращается к объекту визира (пусть заимеет на него указатель, если нету), смотрит на этот флажок, и если он "тру", то переносит визир куда нужно.
Название: Re: Перемещение QFrame
Отправлено: spectre71 от Июль 24, 2009, 16:04
Понял правильно. Беда в том, что правильные координаты в функция mouse....Event класса GraphicDisplay!
Если сделаешь GraphicDisplay доступным для VFFrame: 1) получашь mouse координаты mouseEvent у VFFrame - gpos= e->globalPos (). 2) pos = GraphicDisplay->mapFromGlobal(gpos)
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 16:17
Рисунок того, как это выглядит, можно посмотреть здесь: http://www.forum.crossplatform.ru/index.php?showtopic=3093&st=0&gopid=22586&#entry22586
ufna, ты ведь там зарегистрирован. Мог бы посмотреть тему! :)
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 16:21
Если сделаешь GraphicDisplay доступным для VFFrame: 1) получашь mouse координаты mouseEvent у VFFrame - gpos= e->globalPos (). 2) pos = GraphicDisplay->mapFromGlobal(gpos)
А можно поподробнее пункты? Прости. пока не врубился как сделать!
Название: Re: Перемещение QFrame
Отправлено: spectre71 от Июль 24, 2009, 16:39
void VFFrame::mouseMoveEvent(QMouseEvent* events) { QFrame::mouseMoveEvent(events); QPoint gpos= events->globalPos (). QPoint pos = GraphicDisplay->mapFromGlobal(gpos) ; // pos - mouse pos in GraphicDisplay emit moveVF(); if(!_is_left_pressed) return; if(_vf_shape == QFrame::VLine) setGeometry(_move_point.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) setGeometry(x(), _move_point.y(), width(), height()); }
pos - mouse позиция относительно GraphicDisplay. Далее делай с ней что хочешь
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 16:50
Спасибо.
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 24, 2009, 17:50
Подсказанное решение практически полностью подходит. Ни слоты не нужны, ничего. СПАСИБО ОГРОМНОЕ!!!
Единственное, все-таки курсор идет слегка левее визира. Но основная проблема, по сути, решена. Есть ли возможность попасть ровно под курсор?
Название: Re: Перемещение QFrame
Отправлено: AD от Июль 27, 2009, 10:16
Сделал вариант, который "почти" правильный! :) C++ (Qt) /// Переопределение нажатия на лекую кнопку мыши void VFFrame::mousePressEvent(QMouseEvent* events) { QFrame::mousePressEvent(events); switch(events -> button()) { case Qt::LeftButton: ///< если нажата левая кнопка мыши _is_left_pressed = true; break; } if(!_is_left_pressed) return; QPoint gpos(events -> globalPos()); QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos)); if(_vf_shape == QFrame::VLine) pos.setX(pos.x() - _DELTA_COORD), setGeometry(pos.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) pos.setY(pos.y() - _DELTA_COORD), setGeometry(x(), pos.y(), width(), height()); } /// Передвижение визира вслед за мышью void VFFrame::mouseMoveEvent(QMouseEvent* events) { QFrame::mouseMoveEvent(events); if(!_is_left_pressed) return; QPoint gpos(events -> globalPos()); QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos)); if(_vf_shape == QFrame::VLine) pos.setX(pos.x() - _DELTA_COORD), setGeometry(pos.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) pos.setY(pos.y() - _DELTA_COORD), setGeometry(x(), pos.y(), width(), height()); } /// Отпускание кнопки мыши void VFFrame::mouseReleaseEvent(QMouseEvent* events) { QFrame::mouseReleaseEvent(events); if(!_is_left_pressed) return; _is_left_pressed = false; QPoint gpos(events -> globalPos()); QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos)); if(_vf_shape == QFrame::VLine) pos.setX(pos.x() - _DELTA_COORD), setGeometry(pos.x(), y(), width(), height()); else if(_vf_shape == QFrame::HLine) pos.setY(pos.y() - _DELTA_COORD), setGeometry(x(), pos.y(), width(), height()); _is_viewfinder = false; }
Это "почти" состоит в том, что я из координаты вычитаю константу. У меня она равна 20. А есть возможность сделать без таких хаков? Заранее благодарен.
Название: Re: Перемещение QFrame
Отправлено: BRE от Июль 27, 2009, 10:18
Это "почти" состоит в том, что я из координаты вычитаю константу. У меня она равна 20. А есть возможность сделать без таких хаков? Заранее благодарен.
http://www.forum.crossplatform.ru/index.php?showtopic=3093&view=findpost&p=22694
|