QWidget mapToGlobal 和 mapToParent

写在前面

最近一个任务需要在界面(主窗口,顶级窗口,暂称为 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】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章