目录
一、模态和非模态
枚举类WindowModality用于指定窗口的模态行为。模态是指阻止其他窗口获取输入。
widget通过setWindowModality()来设置自己的模态属性。
注意:模态中的阻塞只是说阻塞其他窗口获取事件输入,而不是阻塞整个应用的执行。
常量 | 值 | 描述 |
---|---|---|
Qt::NonModal | 0 | 非模态,普通的新建窗口都是非模态的。 |
Qt::WindowModal | 1 | 窗口模态,只要记住3点:1、如果widget没有parent,那窗口模态就无意义了,相当于非模态。2、模态窗口会阻塞其最高祖先往下的整棵窗口树。3、模态窗口不会阻塞其子窗口。具体解释看下图。 |
Qt::ApplicationModal | 2 | 应用模态,会阻塞整个应用的所有窗口 |
二、窗口属性浅析
WindowType是qt的一个枚举类,里面包含了各种类型,这些类型用于指定QWidget的各种窗口属性,这些属性决定窗口的外观。
WindowFlags是一个WindowType中各种类型的组合类,用于设置给QWidget,可以说WindowFlags就是QWidget的窗口属性。QWidget可以通过windowFlags()来获取窗口属性,用setWindowFlags()来设置窗口属性,setWindowFlag(a0, on=True)来设置或取消某个属性a0,on=True是设置属性,on=False是取消属性。
窗口属性这一块可能并不常用,但是在某些情况下,它们是必须的。其中有些类型是否有用还取决于操作系统底层窗口管理器是否支持。
完整列表见:WindowType完整列表
下面列举和说明一些常用类型:
常量 | 值 | 描述 |
---|---|---|
Qt::Widget | 0x00000000 | 这是所有QWidget都拥有的的默认属性 |
Qt::Window | 0x00000001 | 使widget成为一个窗口。widget要显示出来,不管是自己单独作为一个窗口,还是嵌入父widget依托父widget的窗口,都必须有一个窗口。所以如果widget有父widget的话,是可以取消这个属性的,没有就无法取消这个属性,很好理解,没有窗口,widget就没地方显示。 |
Qt::Dialog | 0x00000002 | Window | 使widget成为一个对话框样式的窗口,仅此而已。要注意,对话框和模态可没啥关系,这是两个概念。 |
Qt::Popup | 0x00000008 | Window | 使widget作为一个顶层窗口弹出,并且不管widget有没有parent,它都将作为模态窗口阻塞其他窗口(一般模态窗口只能阻塞父窗口)。窗口没有标题栏,如果要关闭窗口的话,只能代码关闭,或者点击外部区域,使qt的窗口失焦,那弹出窗口自动关闭 |
Qt::Tool | Popup | Dialog | 使widget作为一个tool窗口(有标题栏)弹出,widget基本算是一个独立的窗口,即不会失焦自动退出,也不会阻塞其他窗口;如果widget有parent的话,widget窗口永远显示在parent窗口之上。 |
Qt::FramelessWindowHint | 0x00000800 | 使窗口无边框、无标题栏。我们都知道,windows系统本身的标题栏是不怎么好看而且无法定制样式的,为了做一些比较好看的标题栏,就可以使用这个type来得到一个无边框的窗口,然后自己定制一个标题栏。 |
Qt::WindowMinimizeButtonHint | 0x00004000 | 标题栏上添加一个最小化按钮,windows系统默认就有这个按钮,有些平台是没有的;Windows系统可以通过取消这个类型来禁用最小化按钮,没法完全不显示。如果同时禁用Qt::WindowMaximizeButtonHint那最小化和最大化按钮就都不显示。 |
Qt::WindowMaximizeButtonHint | 0x00008000 | 标题栏上添加一个最大化按钮,windows系统默认就有这个按钮,有些平台是没有的;Windows系统可以通过取消这个类型来禁用最大化按钮,没法完全不显示。如果同时禁用Qt::WindowMinimizeButtonHint那最小化和最大化按钮就都不显示。 |
Qt::WindowMinMaxButtonsHint | WindowMinimizeButtonHint | WindowMaximizeButtonHint | 标题栏上添加一个最大化按钮和一个最小化按钮,windows系统默认就有这两个按钮,有些平台是没有的;Windows系统可以通过取消这个类型来不显示最小化按钮和最大化按钮 |
Qt::WindowCloseButtonHint | 0x08000000 | 标题栏上添加一个关闭按钮,windows系统默认就有这个按钮,有些平台是没有的;Windows系统可以通过取消这个类型来禁用关闭按钮,没法完全不显示 |
Qt::WindowStaysOnTopHint | 0x00040000 | 窗口置顶 |
Qt::WindowStaysOnBottomHint | 0x04000000 | 窗口置底 |
三、创建子窗口
方式1:
def showChild(self):
child = Child()
child.show()
这种方式其实child并不是parent的子窗口,因为parent和child没有任何关联,当showChild执行完毕后,依据python的内存回收机制,child会被立即回收,体现在界面上就是子窗口一闪而过
方式2:
def showChild(self):
self.child = Child()
self.child.show()
这种方式child仍然不是parent的子窗口,直观体现就是设置self.child.setWindowModality(Qt.WindowModal)并不能阻塞parent事件,只不过parent通过成员变量持有了Child,Child不会被回收,所以child是能够正常显示的。而当再次调用showChild的时候,会重新实例化一个新的Child,原来的会被回收。
方式3:
def showChild(self):
child = Child(self)
child.show()
这种方式child才真正是parent的子窗口,child设置Qt.WindowModal可以阻塞parent事件,而且在任务栏上是没有child的图标的(子窗口在任务栏上是没有图标的,真正的独立主窗口才有)。
这时child.parent()指向parent,parent.children()也包含child。因为这些都是pyqt内部实现的,并不会因为child.close()而取消,所以需要重写child的close函数,
def close(self) -> bool:
self.setParent(None)
self.deleteLater()
return super(Child, self).close()
来断开child和parent的连接,否则每次打开child都会实例化一个新的对象,旧的child又无法回收,造成内存泄露。