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】

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