写在前面
最近一个任务需要在界面(主窗口,顶级窗口,暂称为 c )中某个子控件(暂称为 a )位置显示一个自定义窗口(暂称为 b ),使用到了QWidget 的 mapToGlobal 和 mapToParent,做下简单总结。从QWidget 的 pos 说起。
一 QWidget
QWidget 是 Qt 中 GUI 对象的基类。 QWidget 的 pos 属性介绍如下:
This property holds the position of the widget within its parent widget
If the widget is a window, the position is that of the widget on the desktop, including its frame.
When changing the position, the widget, if visible, receives a move event (moveEvent()) immediately. If the widget is not currently visible, it is guaranteed to receive an event before it is shown.
By default, this property contains a position that refers to the origin.
Warning: Calling move() or setGeometry() inside moveEvent() can lead to infinite recursion.
See the Window Geometry documentation for an overview of geometry issues with windows.Access functions:
QPoint pos() const
void move(int x, int y)
void move(const QPoint &)
即 pos 函数获得的是控件相对于父控件坐标系的位置。move 函数也是如此。
二 mapToGlobal
QPoint QWidget::mapToGlobal(const QPoint &pos) const
Translates the widget coordinate pos to global screen coordinates. For example, mapToGlobal(QPoint(0,0)) would give the global coordinates of the top-left pixel of the widget.
初期方案中,将弹出的自定义窗口 b 设置为没有 parent,伪代码如下:
auto pos = a.pos();
auto p = a.parent.mapToGlobal(pos);
b.move(p);
b.show();
即直接从 a 的 parent 的坐标系中的坐标转换为 global 坐标系中坐标即可。
三 mapToParent
QPoint QWidget::mapToParent(const QPoint &pos) const
Translates the widget coordinate pos to a coordinate in the parent widget.
Same as mapToGlobal() if the widget has no parent.
任务后期发现,当自定义窗口 b 没有 parent 时, b的隐藏时机比较复杂,很难控制,所以改为将 b 的 parent 设置为主窗口 c 。然后发现 b 显示位置乱了。
其实此时 b 的 move 操作 是针对其 parent c 的坐标系来说的。那么问题变为:求解 a.parent 的坐标系的坐标 a.pos() 转换到 c 的坐标系的坐标是多少?伪代码如下:
auto pos = a.pos();
auto coordinate = dynamic_cast<QWidget*>(a.parent);
while (coordinate)
{
pos = coordinate.mapToParent(pos);
coordinate = dynamic_cast<QWidget*>(coordinate.parent);
}
b.move(pos);
b.show();
即不停的依靠 parent 转换 pos。此处注意,parent() 是 QObject 的函数,其返回值是 QObject*,而我们只需要调用mapToParent()函数,它是 QWidget 的函数,所以只需转换为 QWidget* 即可。向下转换用 dynamic_cast (C++ 语法)。
四 总结
总体来说 move 和 pos 都是相对于其父控件坐标系来说的,如果无parent (parent = 0),就是 global 坐标系。
move前, 先将坐标转换到对应坐标系的坐标。
五 参考
【参考Qt5.9.2 Assistant】