Qt z-order 研究
当用一个label 盖压另一个label 时, 遇到了一些问题, 就是达不到自己的期望操作.
所以认真研究了一下z-order 序
下面程序可以揭示qt z-order 是如何实现的? 背后的道理是什么?
QtWidget 下有三个函数与z-order 相关,
raise(),lower(),stackUnder(),
看一下raise() 在assistant 文档中的描述(要学会用assistant,因为头文件中没写), 其它2个类似
[slot] void QWidget::raise()
Raises this widget to the top of the parent widget's stack.
After this call the widget will be visually in front of any overlapping sibling widgets.
Note: When using activateWindow(), you can call this function to ensure that the window is stacked on top.
See also lower() and stackUnder().
提升这个控件到父控件堆栈的顶部. 调用该函数后,这个控件将是可见的,在其它兄弟控件的顶部.
注意: 当使用activateWindow(), 你可以调用这个函数保证窗口在堆栈顶部.
另两个函数是保证在堆栈底部和某控件下方.
从这些描述中我们看到, z 序是通过父控件的堆栈来维护的. 什么意思呢? 网上有人言, 这个堆栈序就是QObjectList 顺序.
现在做一下测试: 证明确实如此:
本人精心打造如下测试程序,从测试程序中学到了:
1. qt 中的z-order 是如何实现的, 我们如何控制z-order
2. 如何获取object 上的指定事件. 可以通过安装eventfilter, 过滤(找到obj,event)我们感兴趣的事件.
3. qt stylesheet 及 align 的数学(可借助qtcreator)
主题文件: mainwindow.h, mainwindow.cpp
$ cat mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QLabel>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow(){};
QWidget* cwidget;
QLabel* label1;
QLabel* label2;
QLabel* label3;
bool eventFilter(QObject *obj, QEvent * ev); //过滤鼠标双击事件
private:
void printStackOrder();
};
#endif // MAINWINDOW_H
$ cat mainwindow.cpp
#include "mainwindow.h"
#include <QDebug>
#include <QEvent>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(500,500); // 重新设置窗口大小
cwidget = new QWidget;
this->setCentralWidget(cwidget); //QMainWindow 都有一个CentralWidget
//创建3个label, 其父对象为cwidget
label1 = new QLabel(cwidget);
label1->setObjectName("label1");
label1->setText("label1");
label1->setAlignment(Qt::AlignHCenter|Qt::AlignTop);
label1->setStyleSheet("font:20pt;background-color: red;");
label1->setGeometry(0,0,300,300);
label2 = new QLabel(cwidget);
label2->setObjectName("label2");
label2->setText("label2");
label2->setAlignment(Qt::AlignHCenter|Qt::AlignTop);
label2->setStyleSheet("font:20pt;background-color: green;");
label2->setGeometry(100,100,300,300);
label3 = new QLabel(cwidget);
label3->setObjectName("label3");
label3->setText("label3");
label3->setAlignment(Qt::AlignHCenter|Qt::AlignTop);
label3->setStyleSheet("font:20pt;background-color: blue;");
label3->setGeometry(200,200,300,300);
label1->installEventFilter(this); //过滤本窗口上的事件
label2->installEventFilter(this);
label3->installEventFilter(this);
qDebug()<<"label1:"<<label1;
qDebug()<<"label2:"<<label2;
qDebug()<<"label3:"<<label3;
printStackOrder();
}
void MainWindow::printStackOrder()
{
QObjectList list = cwidget->children(); //获取centralWidget 的子对象列表
QList<QObject*>::iterator it;
qDebug()<<"-----begin-----";
for(it=list.begin(); it!=list.end(); it++)
{
qDebug()<<"obj:name"<<(*it)->objectName();
}
}
bool MainWindow::eventFilter(QObject *obj, QEvent * ev)
{
// qDebug()<<"event happen! obj:"<<obj; //所有过滤的obj 及事件都会到这里来
if (ev->type() == QEvent::MouseButtonDblClick) // 你要过滤的对象的事件类型,过滤鼠标双击事件
{
if (obj == label1) // 你要过滤的对象
{
qDebug()<<"lablel1 double cliked!";
printStackOrder();
label1->raise();
printStackOrder();
return true; // 注意这里一定要返回true,表示事件处理就结束了.
}
else if (obj == label2) // 你要过滤的对象
{
qDebug()<<"lablel2 double cliked!";
label2->raise();
printStackOrder();
return true;
}
else if (obj == label3) // 你要过滤的对象
{
qDebug()<<"lablel3 double cliked!";
label3->raise();
printStackOrder();
return true;
}
}
return false; // 返回false表示不过滤,事件还按默认的方式处理
}
辅助文件:main.cpp, project 文件
$ cat main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
MainWindow *mainw = new MainWindow;
mainw->show();
return app.exec();
}
cat z-order.pro
######################################################################
# Automatically generated by qmake (3.1) Sun Apr 10 10:44:08 2022
######################################################################
TEMPLATE = app
TARGET = z-order
INCLUDEPATH += .
QT+=widgets
# You can make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# Please consult the documentation of the deprecated API in order to know
# how to port your code away from it.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# Input
HEADERS += mainwindow.h
SOURCES += main.cpp mainwindow.cpp
附图1: 开始时的z-order 序
双击label1后:
运行结果:
./z-order
label1: QLabel(0x55adcf593e40, name="label1")
label2: QLabel(0x55adcf515710, name="label2")
label3: QLabel(0x55adcf50d320, name="label3")
-----begin-----
obj:name "label1"
obj:name "label2"
obj:name "label3" // 开始时的z-order 序, 按label创建顺序, label3在尾部,有最高显示级别
lablel1 double cliked!
-----begin-----
obj:name "label2"
obj:name "label3"
obj:name "" //多出一个空obj
obj:name "label1" //双击label, 提升label1 z-order序, 此时其处于堆栈尾部,有最高显示级别.