Qt 当窗口移动时,如何获取小部件的新坐标?

Qt 当窗口移动时,如何获取小部件的新坐标?,qt,qevent,Qt,Qevent,我有一个这样的小对话框: 当我将对话框移动到桌面上的另一个位置时,如何获取对话框中元素的新全局坐标(例如,在本例中为“确定”按钮的左上角)? 假设我有一个子类MyButton作为OK按钮,我想为这个类使用QEvent,我在这个类中工作,而不是在QMainWindow中。 bool MyButton::eventFilter( QObject *p_obj, QEvent *p_event ) { if ( p_event->type() == QEvent::Move )

我有一个这样的小对话框:

当我将对话框移动到桌面上的另一个位置时,如何获取对话框中元素的新全局坐标(例如,在本例中为“确定”按钮的左上角)? 假设我有一个子类MyButton作为OK按钮,我想为这个类使用QEvent,我在这个类中工作,而不是在QMainWindow中。

bool MyButton::eventFilter( QObject *p_obj, QEvent *p_event )
{     
  if ( p_event->type() == QEvent::Move )
  {
     QPoint point = this->contentsRect().topLeft();
     point = mapToGlobal( point );
     qDebug() << point;
  }
  return QWidget::eventFilter( p_obj, p_event );
}

Qt文件。对事件过滤器有一个很好的介绍:包括一个小示例

在OP的问题上,我遗漏了两件重要的事情:

  • 如何构造
    QDialog
  • 事件过滤器(在
    MyButton
    中)安装在哪里
  • 此外,OP似乎不知道:

    将小部件坐标pos转换为全局屏幕坐标。例如,
    mapToGlobal(QPoint(0,0))
    将给出小部件左上像素的全局坐标

    关于
    mapToGlobal
    ,SO中至少还有一个其他Q/A:

    但是,我做了一个示例来演示一个解决方案—
    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();
    }
    
    在Windows 10上编译并测试:

    $qmake-qt5 testQButtonGlobalPos.pro
    $make&./testQButtonGlobalPos
    Qt版本:5.9.4
    QWidget位置:本地:QPoint(0,0)全局:QPoint(11,11)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2690,68)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(98,45)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2658,42)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(5218,46)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(3097219)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2251197)
    
    在我将对话框移动到新位置后,以
    QWidget Pos.:
    开头的每一行(前两行除外)都出现了。当我打开对话框时,前两行被打印出来了。所以,第一个对话框似乎反映了对话框尚未定位在桌面上时的中间状态

    注意事项:

  • 事件过滤器的基本原理由一个对象组成,该对象在其虚拟/重写方法中处理过滤的事件。为此,对象必须具有从
    QObject
    派生的类。OP的方法,有一个
    类MyButton:public QPushButton
    就足够了。然而,实际上,从
    QObject
    派生的任何类都可以做到这一点(如我的示例所示)

  • 要使事件筛选器对象正常工作,安装它并调用对象进行监视是很重要的。在我的例子中,这就是quest中的按钮所属的
    QDialog qDlg

  • 出于好奇,我尝试了另一种选择:重写
    类MyButton:public QPushButton
    中的。这并没有提供OP/I的意图。当打开
    QDialog qDlg
    时,调用了一次
    MyButton::moveEvent()
    。用鼠标移动对话框时不会再次调用它。移动事件似乎由
    QDialog
    接收,但不会进一步传播到子窗口小部件。这是合理的,因为移动整个对话框窗口不会改变其内部布局。因此,OP为此使用事件过滤器的方法是正确的


  • Qt文件。对事件过滤器有一个很好的介绍:包括一个小示例

    在OP的问题上,我遗漏了两件重要的事情:

  • 如何构造
    QDialog
  • 事件过滤器(在
    MyButton
    中)安装在哪里
  • 此外,OP似乎不知道:

    将小部件坐标pos转换为全局屏幕坐标。例如,
    mapToGlobal(QPoint(0,0))
    将给出小部件左上像素的全局坐标

    关于
    mapToGlobal
    ,SO中至少还有一个其他Q/A:

    但是,我做了一个示例来演示一个解决方案—
    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();
    }
    
    在Windows 10上编译并测试:

    $qmake-qt5 testQButtonGlobalPos.pro
    $make&./testQButtonGlobalPos
    Qt版本:5.9.4
    QWidget位置:本地:QPoint(0,0)全局:QPoint(11,11)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2690,68)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(98,45)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2658,42)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(5218,46)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(3097219)
    QWidget位置:本地:QPoint(83,0)全局:QPoint(2251197)
    
    在我将对话框移动到新位置后,以
    QWidget Pos.:
    开头的每一行(前两行除外)都出现了。当我打开对话框时,前两行被打印出来了。所以,第一个对话框似乎反映了对话框尚未定位在桌面上时的中间状态

    注意事项:

  • 事件过滤器的基本原理由一个对象组成,该对象在其虚拟/重写方法中处理过滤的事件。为此,对象必须具有从
    QObject
    派生的类。OP的方法,有一个
    类MyButton:public QPushButton
    就足够了。然而,实际上,从
    QObject
    派生的任何类都可以做到这一点(如我的示例所示)

  • 要使事件筛选器对象正常工作,安装它并调用对象进行监视是很重要的。在我的例子中,这就是quest中的按钮所属的
    QDialog qDlg

  • 出于好奇,我尝试了另一种选择:重写
    类MyButton:public QPushButton
    中的。这并没有提供OP/I的意图。当打开
    QDialog qDlg
    时,调用了一次
    MyButton::moveEvent()
    。用鼠标移动对话框时不会再次调用它。移动事件似乎由
    QDialog