У меня имеется QFrame (визир) c формой QFrame::VLine. Я переопределяю QFrame, т.е. создал потомка от QFrame. Этот QFrame находится на виджете. У виджета определены функции нажатия, движения и отпускания мыши. У QFrame тоже определены. Как заставить QFrame передвинуться и встать на нужное новое место? При этом хотелось бы, чтобы функции передвижения мыши не вызывались. Я правильно понимаю, что в переопределенном виджете надо как-то перехватывать фокус при наведении на визир и ставить флаг игнорирования, а в функциях переопределения мыши виджета проверять флаг игнора? Какую виртуальную функцию виджета надо перехватить при наведении фокуса на визир?
Вот функции мыша визира:
class VFFrame: public QFrame
{
//.....................
bool _is_left_pressed; ///< флаг указания нажатия на левую кнопку мыши
//.....................
virtual void mousePressEvent(QMouseEvent* events);
virtual void mouseMoveEvent(QMouseEvent* events);
virtual void mouseReleaseEvent(QMouseEvent* events);
};
/// Переопределение нажатия на лекую кнопку мыши
void VFFrame::mousePressEvent(QMouseEvent* events)
{
QFrame::mousePressEvent(events);
switch(events -> button())
{
case Qt::LeftButton: ///< если нажата левая кнопка мыши
_is_left_pressed = true;
break;
}
}
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
QFrame::mouseMoveEvent(events);
if(!_is_left_pressed) return;
move(events -> pos());
}
/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
QFrame::mouseReleaseEvent(events);
if(!_is_left_pressed) return;
_is_left_pressed = false;
setGeometry(events -> pos().x(), y(), width(), height());
}
/// Создание и отображение вертикального визира
void GraphicDisplay::verticalViewfinder()
{
if(v_viewfinderAction -> isChecked())
{
VFFrame* finder(new VFFrame(paramsDisplay, QFrame::VLine));
gridLayout -> addWidget(finder, 0, 0, 1, 1);
}
}
Еще вопрос: если я внес визир в компоновщик:
gridLayout -> addWidget(finder, 0, 0, 1, 1);
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
// ........................................
move(events -> pos());
}
void VFFrame::mouseMoveEvent(QMouseEvent* events) { // ........................................ move(events -> pos()); }
/// Создание и отображение вертикального визира
void GraphicDisplay::verticalViewfinder()
{
if(v_viewfinderAction -> isChecked())
{
VFFrame* finder(new VFFrame(paramsDisplay, QFrame::VLine));
finder -> setGeometry(140, 140, 16, 400);
//gridLayout -> addWidget(finder, 0, 0, 1, 1);
}
}
AD,
что мешает сделать его членом класса виджета но не давать ему parenta он как окно будет самостоятельным и взаимосвязь будет на уровне членов класса.
в конце концов можно где нить выше по иеррархии отдать указатель на визор виджету.
ну как бы тут вариантов куча.
Ну с этим вроде разобрался. Я не понимаю двух вещей. Как заставить принимать размеры визира во вертикали те же, что и окна? И как указать мыши, что мы в данной точке сфокусированы на визире, а не на виджете (у QEvent нет функции pos())?
AD,
какие-то концептуальные непонимания.
resizeEvent() виджета переопредели в нем напиши визиру принять высоту виджета и всё.
Блин, ну не очень понял, как эти функции применить.... Ладно.... разберусь.
А как заставить визир двигаться только по горизонтали, например?
Движение визира сделал так, но нет пока, что четкого следования за указателем мыши. Кто подскажет, в чем ошибка?
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
QFrame::mouseMoveEvent(events);
if(!_is_left_pressed) return;
if(_vf_shape == QFrame::VLine)
move(_move_point.x(), y());
else if(_vf_shape == QFrame::HLine)
move(x(), _move_point.y());
}
/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
QFrame::mouseReleaseEvent(events);
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);
}
/// Проверка на попадание фокуса на визир
bool GraphicDisplay::isViewfinder(const QPoint& pos) const
{
foreach(VFFrame* pf, viewfinderList)
if(pf -> isViewfinder())
{
pf -> setMovePoint(pos);
return true;
}
return false;
}
/// Нажатие на кнопку - рисование "резиновой ленты"
void GraphicDisplay::mousePressEvent(QMouseEvent* events)
{
QWidget::mousePressEvent(events);
if(isViewfinder(events -> pos())) return;
// .....................................................
}
/// Переопределение функции передвижения мыши
void GraphicDisplay::mouseMoveEvent(QMouseEvent* events)
{
if(isViewfinder(events -> pos())) return;
// ........................................
update();
}
/// Возвращение прежнего вида курсору и изменение масштаба
void GraphicDisplay::mouseReleaseEvent(QMouseEvent* events)
{
if(isViewfinder(events -> pos())) return;
// ............................
}
Движение визира происходит дерганиями, что не соответствует тому, чего хочется получить./// Класс для переопределения виджета каждого визира
class VFFrame: public QFrame
{
QPoint _move_point; ///< точка целеуказания, куда необходимо двигать
public:
void setMovePoint(const QPoint& pnt) { _move_point = pnt; }
};
Судя по всему, это происходит потому, что вначале попадаем в функцию
void VFFrame::mousePressEvent(QMouseEvent* events), а потом уже в void GraphicDisplay::mousePressEvent(QMouseEvent* events) (для остальных аналогично). А как сделать наоборот? Т.е. чтобы вначале попадали в GraphicDisplay::mousePressEvent, а потом уже в VFFrame::mousePressEvent?
Кто-нибудь может хоть подсказать в какую сторону смотреть?
Попробовал решить указанную выше проблему слотов-сигналов. Не очень удалось. Не могу понять, как мне выйти на нужную координату:
/// Класс для переопределения виджета каждого визира
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; }
// ....................................................................
}
Буду рад за любой совет. Уже полторы недели с этим мучаюсь!
вот рисунок визира:
[attachment=719:uti.JPG]
не, просто хочется глянуть в динамике что происходит. В какой момент и что. Я словами плохо объясню что хочу увидеть )
кстати, на прог орге совет дали сводящийся вот к чему - в визире ты узнаешь глобальные координаты, затем - переводишь их в систему координат график дисплея. Хотя мне кажется тут ненмого в другом дело.
я бы советовал перевести управление движением с визира на дисплей, воспользовавшись переменной-стейтом нажат/не нажат в визире.
я сии визиры делаю вообще не отдельными виджетами, а объектами дисплея через QRect и ручную отрисовку. Там тогда все становится очень простым, точным и удобным.
P.S. - я оба форума не особо разделяю, тему видел в обоих, ответил просто в том, в который зашел когда было время посмотреть подробнее
Подсказанное решение практически полностью подходит. Ни слоты не нужны, ничего.
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
QFrame::mouseMoveEvent(events);
QPoint gpos(events -> globalPos());
QPoint pos(_graph -> mapFromGlobal(gpos));
if(!_is_left_pressed) return;
if(_vf_shape == QFrame::VLine)
setGeometry(/*_move_point.x()*/pos.x(), y(), width(), height());
else if(_vf_shape == QFrame::HLine)
setGeometry(x(), /*_move_point.y()*/pos.y(), width(), height());
}
а если добавить к X просто некоторую константу?
Сделал вариант, который "почти" правильный!
/// Переопределение нажатия на лекую кнопку мыши
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;
}
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)