Z-Order
Z-Order指的是三维坐标系中的Z轴顺序,而在系统视图中,X轴和Y轴往往表示平面的宽高方向(可以理解为显示器的宽高),而Z轴表示屏幕到视线的方向,如下图所示:

所以Z轴的坐标会影响人看到的东西,在X和Y坐标一样,且大小一致的两个Item中哪个能被用户看到,取决于Z轴的坐标,Z轴值大的覆盖小的。
QML Z-Order
QML中Item有一个属性z,该属性能够控制Item的Z轴值,具体介绍可以参考官网Item
QWidget Z-Order
QWidget中并没有关于Z-Order的属性,经过一些测试后发现虽然QWidget没有关于Z-Order的属性,但是其通过其他方式实现了。
一开始查找资料的时候只发现以下三个接口:
// 将当前Widget放到父窗口组件堆栈中的w窗口的下面(在视觉效果上就是Widget被w窗口掩盖)
void QWidget::stackUnder(QWidget *w)
// 将当前Widget上升到父窗口组件堆栈的顶部(在视觉效果上会掩盖住同堆栈内的其他Widget)
void QWidget::raise()
// 将当前Widget降低到父窗口组件堆栈的底部(在视觉效果上会被同堆栈内的其他Widget掩盖)
void QWidget::lower()
从这些接口的注释可以看出child widget在父窗口对象中是用一个堆栈维护的,这里我就联想到QObject对象会维护一个QObjectList,在析构的时候先行析构child object。难道这个QObjectList和Z-Order有关系?那就测试一下吧:
测试方法是两个子窗口通过鼠标双击调用raise()实现以下效果:
看一下主要代码:
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
for (int i = 0; i < 2; i++) {
widgets[i] = new ChildWidget(this);
widgets[i]->setText(QString("order%1").arg(i));
widgets[i]->setObjectName(QString("order%1").arg(i));
connect(widgets[i], &ChildWidget::sigDBClicked, this, &Widget::onChildDbClicked);
}
widgets[0]->setStyleSheet("background: red;");
widgets[0]->move(10, 10);
widgets[1]->setStyleSheet("background: black;");
widgets[1]->move(210, 50);
qDebug() << "----------";
for (auto obj : this->children()) {
qDebug() << obj;
}
qDebug() << "----------";
}
// slot
void Widget::onChildDbClicked()
{
qDebug() << "----------";
static_cast<ChildWidget*>(sender())->raise();
for (auto obj : this->children()) {
qDebug() << obj;
}
qDebug() << "----------";
}
通过gif和代码可以看出raise()函数修改的父窗口组件堆栈其实就是父Object的children。那么parent Widget在显示child Widgets时就是通过QObjectList来处理的,先添加的child Widget会被后添加的parent Widget覆盖。
总结
- QWidget的视觉Z-Order可以通过stackUnder、lower、raise三个函数来修改
- 初始化的Z-Order和添加child Widget的先后有关