Qt Doc.есть хорошее введение в фильтры событий: Система событий - Фильтры событий , включая небольшой пример.
Я упускаю две важные вещи в вопросе OP:
- Как создается
QDialog
? - Где установлен фильтр событий (в
MyButton
)?
Кроме того, кажется, что OPне знать о QWidget::mapToGlobal()
:
Переводит координату виджета pos в глобальные экранные координаты.Например, mapToGlobal(QPoint(0,0))
даст глобальные координаты верхнего левого пикселя виджета.
Что касается mapToGlobal
, в SO уже есть хотя бы еще один Q / A:
SO: Qt - Определить абсолютный виджет и положение курсора
Однако я сделал MCVE , чтобы продемонстрировать решение - testQButtonGlobalPos.cc
:
#include <QtWidgets>
class WidgetPosFilter: public QObject {
private:
QWidget &qWidget;
public:
WidgetPosFilter(
QWidget &qWidget, QObject *pQParent = nullptr):
QObject(pQParent), qWidget(qWidget)
{ }
virtual ~WidgetPosFilter() = default;
WidgetPosFilter(const WidgetPosFilter&) = delete;
WidgetPosFilter& operator=(const WidgetPosFilter&) = delete;
protected:
virtual bool eventFilter(QObject *pQbj, QEvent *pQEvent) override;
};
bool WidgetPosFilter::eventFilter(
QObject *pQObj, QEvent *pQEvent)
{
if (pQEvent->type() == QEvent::Move) {
qDebug() << "QWidget Pos.:"
<< "local:" << qWidget.pos()
<< "global:" << qWidget.mapToGlobal(QPoint(0, 0));
}
return QObject::eventFilter(pQObj, pQEvent);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup UI of main window
QPushButton qBtnOpenDlg(
QString::fromUtf8("Open new dialog..."));
qBtnOpenDlg.show();
// setup UI of dialog
QDialog qDlg(&qBtnOpenDlg);
QVBoxLayout qVBox;
QDialogButtonBox qDlgBtns;
QPushButton qBtn(QString::fromUtf8("The Button"));
qDlgBtns.addButton(&qBtn, QDialogButtonBox::AcceptRole);
qVBox.addWidget(&qDlgBtns);
qDlg.setLayout(&qVBox);
WidgetPosFilter qBtnPosFilter(qBtn);
// install signal handlers
QObject::connect(&qBtnOpenDlg, &MyButton::clicked,
[&](bool) { qDlg.show(); });
qDlg.installEventFilter(&qBtnPosFilter);
// runtime loop
return app.exec();
}
Проект Qt для сборки - testQButtonGlobalPos.pro
:
SOURCES = testQButtonGlobalPos.cc
QT += widgets
Скомпилировано и протестировано в cygwin64 в Windows 10:
$ qmake-qt5 testQButtonGlobalPos.pro
$ make && ./testQButtonGlobalPos
Qt Version: 5.9.4
QWidget Pos.: local: QPoint(0,0) global: QPoint(11,11)
QWidget Pos.: local: QPoint(83,0) global: QPoint(2690,68)
QWidget Pos.: local: QPoint(83,0) global: QPoint(98,45)
QWidget Pos.: local: QPoint(83,0) global: QPoint(2658,42)
QWidget Pos.: local: QPoint(83,0) global: QPoint(5218,46)
QWidget Pos.: local: QPoint(83,0) global: QPoint(3097,219)
QWidget Pos.: local: QPoint(83,0) global: QPoint(2251,197)
Каждыйиз строк, начинающихся с QWidget Pos.:
(кроме первых двух), появились после Я переместил диалог на новую позицию.Первые две строки были напечатаны, когда я открыл диалог.Итак, первое, кажется, отражает промежуточное состояние, когда диалог еще не был размещен на рабочем столе.
Примечания:
Основной принцип фильтров событий состоит из объекта, который обрабатывает отфильтрованные события в своем виртуальном / переопределенном методе eventFilter()
.Для этого у объекта должен быть класс, производный от QObject
.Подход ОП, имеющий class MyButton: public QPushButton
, будет достаточным.Однако, на самом деле, любой класс, производный от QObject
, также может это сделать (как показано в моем примере).
Чтобы заставить работать объект фильтра событий, важно установить еговызывая QObject::installEventFilter()
для объекта для наблюдения.В моем случае это была QDialog qDlg
, к которой принадлежит кнопка в квесте.
Из любопытства я попробовал альтернативу: переопределить QWidget::moveEvent()
в class MyButton: public QPushButton
.Это не обеспечило то, что OP / I намеревался.MyButton::moveEvent()
был вызван один раз, когда QDialog qDlg
был открыт.Перемещение диалога мышью не вызывало его снова.Кажется, что события перемещения принимаются QDialog
, но не распространяются далее на дочерние виджеты.Это настолько разумно, что перемещение всего диалогового окна не меняет его внутреннюю планировку.Следовательно, подход OP с использованием фильтра событий для этого был правильным путем.