Qt 当窗口移动时,如何获取小部件的新坐标?
我有一个这样的小对话框: 当我将对话框移动到桌面上的另一个位置时,如何获取对话框中元素的新全局坐标(例如,在本例中为“确定”按钮的左上角)? 假设我有一个子类MyButton作为OK按钮,我想为这个类使用QEvent,我在这个类中工作,而不是在QMainWindow中。Qt 当窗口移动时,如何获取小部件的新坐标?,qt,qevent,Qt,Qevent,我有一个这样的小对话框: 当我将对话框移动到桌面上的另一个位置时,如何获取对话框中元素的新全局坐标(例如,在本例中为“确定”按钮的左上角)? 假设我有一个子类MyButton作为OK按钮,我想为这个类使用QEvent,我在这个类中工作,而不是在QMainWindow中。 bool MyButton::eventFilter( QObject *p_obj, QEvent *p_event ) { if ( p_event->type() == QEvent::Move )
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
中)安装在哪里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
派生的任何类都可以做到这一点(如我的示例所示)QDialog qDlg
类MyButton:public QPushButton
中的。这并没有提供OP/I的意图。当打开QDialog qDlg
时,调用了一次MyButton::moveEvent()
。用鼠标移动对话框时不会再次调用它。移动事件似乎由QDialog
接收,但不会进一步传播到子窗口小部件。这是合理的,因为移动整个对话框窗口不会改变其内部布局。因此,OP为此使用事件过滤器的方法是正确的Qt文件。对事件过滤器有一个很好的介绍:包括一个小示例 在OP的问题上,我遗漏了两件重要的事情:
QDialog
MyButton
中)安装在哪里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
派生的任何类都可以做到这一点(如我的示例所示)QDialog qDlg
类MyButton:public QPushButton
中的。这并没有提供OP/I的意图。当打开QDialog qDlg
时,调用了一次MyButton::moveEvent()
。用鼠标移动对话框时不会再次调用它。移动事件似乎由QDialog