8-窗口、窗口控件、对话框以及相关功能类-对话框QDialog

对话框QDialog

对话框(QDialog)是顶层窗口,主要用于短期任务和与用户的简短通信。所谓的顶层窗口,就是可以显示在所有窗口的最前面(也有另一种说法,是指没有父类的窗口)

例如,有些警告窗口始终显示在屏幕顶端,直到被用户关闭。QDialog 虽然是顶层窗口,但是也可以有父类窗口。

和一般具有父类窗口的控件(如 QLabel)不同,QDialog 可以显示在屏幕的任何位置,而有父类的 QLabel 只能在父窗口范围之内显示。

如果 QDialog 有父类,则其启动默认位置在父窗口的中间,并共享父类的任务栏条目,否则默认启动位置在屏幕中间。既可以在初始化过程中传递父类,也可以使用 setParent0函数修改对话框的所有权。

对话框窗口是一个用来完成简单任务或者和用户进行临时交互的顶层窗口,通常用于输人信息、确认信息或者提示信息。QDialog 类是所有对话框窗口类的基类,继承自QDialog 的类有:

  • QAbstractPrintDialog
  • QPageSetupDialog
  • QPrintDialog
  • QPrintPreviewDialog
  • QColorDialog
  • QErrorMessage
  • QFileDialog
  • QFontDialog
  • QInputDialog
  • QMessageBox
  • QProgressDialog
  • QWizard

按照运行时是否可以和其他窗口进行交互操作,对话框分为模式(或模态)对话框和非模式对话框。

对于带有模式的对话框,只有在关闭该对话框的情况下才可以对其他窗口进行操作;而对于非模式对话框,在没有关闭对话框的情况下,既可以对该对话框进行操作,也可以对其他窗口进行操作,例如记事本中的查询对话框和替换对话框就是非模式对话框。

为方便编程,PySide6 提供了一些常用的标准对话框,例如文件打开保存对话框QFileDialog、字体 对话框 QFontDialog、颜色 对话框 QColorDialog、信息对话框QMessageBox等,用户可以直接调用这些对话框,而无须再为这些对话框编写代码。

对话框在操作系统的管理器中没有独立的任务栏,而是共享父窗口的任务栏,无论对话框是否处于活跃状态,对话框都将位于父窗口之上,除非关闭或隐藏对话框。

对话框模式modal概念

使用对话框会弹出一个窗口,这就涉及多窗口对焦点控制权的问题。例如,弹窗警告会阻止用户对程序的其他操作,除非关闭弹窗,利用查找功能进行查找的时候也可以对文档进行编辑。在 Qt 中解决这个问题的方法叫作模式对话框(Modal Dialog)和非模式Modeless Dialog)对话框。可以简单地理解为前一个场景是模式对话框,后一个场景是非模式对话框。

模式对话框会禁止对该程序的其他可见窗口操作。例如,打开文件的对话框就属于模式对话框,会阻止对程序进行其他操作。

模式对话框包含两个,分别是 ApplicationModal默认)和WindowModal。

  • ApplicationModal: 用户必须先完成与对话框的交互并关闭它,然后才能访问应用程序中的任何其他窗口。
  • WindowModal:仅阻止访问与该对话框关联的窗口,从而允许用户继续使用应用程序中的其他窗口。

模式对话框可以通过 setWindowModality()函数设置,该函数支持的 3 个参数如表所示。

参数描述
Qt.NonModal0该窗口不是模式窗口,不会阻止对其他窗口的访问
Qt.WindowModal1该窗口是单个窗口层次结构的模式,并阻止访问其父窗口、所有祖父母窗口,以及其父窗口和祖父母窗口的所有同级
Qt.ApplicationModal2该窗口是模式窗口,阻止与程序相关的所有其他窗口的访问

显示模式对话框最常见的方法是调用 exec()函数(这是使用 Qt 的 C++方法,在 PyQ5/PySide 2 中是 exec()函数,在 PyQt 5/PySide 2 中对应 exec_()函数)。

exec()函数将对话框显示为模式对话框,在用户将它关闭之前,该对话框一直处于阻塞状态。也就是说,如果对话框是 ApplicationModal(默认值),则用户在关闭对话框之前无法与同一应用程序中的任何其他窗口进行交互;如果对话框是 WindowModal,则在打开对话框时仅阻止与父窗口的交互。

当用户关闭对话框时,exec()函数将提供返回1, Dialog.Rejected)或Dialog.Accepted在默认情况下,关闭对话框只返回 0。

  • 如果要返回 1,则可以新建一个名字为OK 的按钮,并与槽函数 Dialog.accept 连接。
  • 同样,也可以新建一个 Cancel 按钮,并与槽函数 Dialogreject 连接,或者可以使用槽函数 Dialog.done 自定义返回值。

返回值只适用于模式对话框,非模式对话框没有返回值。也可以重新实现方法 accept()、reject()或done()来修改对话框的关闭行为。

另外,按 Esc 键也会调用 reiect()函数。也可以先调用 setModal(True)或 setWindowModality(),然后使用 show()函数,与exec()函数不同,使用 show()函数立即将控制权返回给调用者。

另外,show()函数在默认情况下会开启非模式对话框,因此需要提前设置setModal(True)或setWindowModality(),而 setModal(True)从本质来说又等于setWindowModality(Qt.ApplicationModal)

如果同时使用 show()和 setModal(True)来执行较长的操作,则必须在处理期间定期调用QCoreApplication.processEvents(),从而方便用户与对话框进行交互


非模式对话框是指在同一个应用程序中,对话框和程序的其他窗口是独立的。一些典型的应用场景是 Word 中的"查找和替换"对话框,既可以查找文字,又可以编辑文字对话框和主程序可以很好地进行交互。
使用 show()函数显示无模式对话框时,该对话框立即将控制权返回给调用者。如果在隐藏对话框后调用 show()函数,那么该对话框将恢复到原始位置,要恢复到用户上次的位置,可以先在 closeEvent()函数中保存位置信息,然后在show0函数之前将对话框移至该位置。

对话框的显示方法和默认模式

显示对话框的方法有show()、open()和exec()三种。

  • 如果对话框已经有模式特性,则用show()方法显示的对话框具有模式特性
  • 如果对话框没有模式特性,则用show()方法显示的对话框没有模式特性
  • 无论对话框是否有模式特性,用open()或exec()方法显示的对话框都是模式对话框,其中用open()方法显示的对话框默认是窗口模式,用exec()方法显示的对话框默认是应用程序模式。

当程序执行到show()或open()方法时,显示对话框后会继续执行后续的代码;用exec()方法显示对话框时,需关闭对话框后才执行exec()语句的后续代码。

show()、open()和exec()三种显示对话框的方法不会改变对话框的模式属性的值。

对话框QDialog

QDialog类是对话框窗口的基类。继承的子类有QWizard,QProgressDialog,QMessageBox,QInputDialog,QFontDialog,QErrorMessage,QColorDialog,QPrintPreviewDialog,QPageSetupDialog,QAbstractPrintDialog,QPrintDialog,QFileDialog

利用QDialog类,用户可以创建自己的对话框,在对话框上放置控件,实现特定的目的。

QDialog 是从 QWidget 类继承而来的,用QDialog 类创建一般对话框实例的方法如下,其中parent是QDialog 对话框的父窗口,Qt.WindowFlags的取值参考QWidget窗口讲解部分。通常将QDialog对话框作为顶层窗口使用,在主程序界面中进行调用。

from PySide6.QtWidgets import QDialog

QDialog(parent: Union[PySide6.QtWidgets.QWidget,NoneType]=None,f: PySide6.QtCore.Qt.WindowType=Default(Qt.WindowFlags))-> None
对话框QDialog官方说明

对话框窗口是一个顶级窗口,主要用于短期任务和与用户的简短通信。Q对话框可以是模态的,也可以是非模态的。QDialog可以提供一个返回值,并且可以有默认按钮。QDialog也可以使用setSizeGripEnabled在右下角有一个QSizeGrip。

请注意,QDialog以及任何其他类型为Qt::Dialog的小部件使用的父小部件与Qt中的其他类略有不同。对话框始终是一个顶级小部件,但如果它有一个父级,它的默认位置将集中在父级的顶级小部件的顶部如果它本身不是顶级的。它还将共享父级的任务栏条目。

使用setParent函数的重载来更改QDialog小部件的所有权。此功能允许您显式设置重排序小部件的窗口标志;使用重载函数将清除指定窗口小部件的窗口系统属性的窗口标志特别是它将重置Dialog标志。

对话框的父级关系并不意味着对话框将始终堆叠在父窗口的顶部。要确保对话框始终处于顶部,请使对话框处于模态状态。这也适用于对话框本身的子窗口。要确保对话框的子窗口位于对话框的顶部,请使子窗口也处于模态状态。

模式对话框

模式对话框是一种阻止输入到同一应用程序中其他可见窗口的对话框。用于向用户请求文件名或用于设置应用程序首选项的对话框通常是模态的。对话框可以是应用程序模式默认或窗口模式。

打开应用程序模式对话框时,用户必须完成与对话框的交互并关闭对话框,然后才能访问应用程序中的任何其他窗口。窗口模式对话框仅阻止访问与该对话框关联的窗口,允许用户继续使用应用程序中的其他窗口。

显示模式对话框最常见的方法是调用其exec函数。当用户关闭对话框时,exec将提供一个有用的返回值。要关闭对话框并返回适当的值,您必须将默认按钮连接到accept插槽,例如将OK按钮连接到reject插槽。或者,您可以使用Accepted或Rejected调用done插槽。

另一种方法是调用setModaltrue或setWindowModality,然后调用show。与exec不同,show会立即将控制权返回给调用者。调用setModaltrue对于进度对话框特别有用,在进度对话框中,用户必须能够与对话框交互,例如取消长时间运行的操作。如果同时使用show和setModaltrue来执行长操作,则必须在处理过程中定期调用processEvents,以便用户能够与对话框交互。请参阅QProgress对话框。

无模型对话框

无模式对话框是一种独立于同一应用程序中的其他窗口进行操作的对话框。文字处理器中的查找和替换对话框通常是无模式的,以允许用户与应用程序的主窗口和对话框进行交互。

使用show显示无模型对话框,该对话框会立即将控制权返回给调用方。

如果在隐藏对话框后调用show函数,则对话框将显示在其原始位置。这是因为窗口管理器决定了程序员没有明确放置的窗口的位置。要保留用户移动的对话框的位置,请将其位置保存在closeEvent处理程序中,然后将对话框移动到该位置,然后再次显示。

默认按钮

对话框的默认按钮是用户按下Enter返回时按下的按钮。此按钮用于表示用户接受对话框的设置并希望关闭对话框。使用setDefault、isDefault和autoDefault来设置和控制对话框的默认按钮。

关闭快捷键

如果用户在对话框中按下Esc键,则会调用reject。这将导致窗口关闭:关闭事件不能被忽略。

可扩展性

可扩展性是以两种方式显示对话框的能力:显示最常用选项的部分对话框和显示所有选项的完整对话框。通常,一个可扩展的对话框最初会显示为部分对话框,但带有"更多"切换按钮。如果用户按下"更多"按钮,对话框将展开。扩展示例展示了如何使用Qt实现可扩展对话框。

返回值模式对话框

模式对话框通常用于需要返回值的情况,例如指示用户是按"确定"还是按"取消"。可以通过调用accept或reject插槽来关闭对话框,exec将根据情况返回accept或Rejected。exec调用返回对话框的结果。如果对话框没有被销毁,那么result也可以获得结果。

为了修改对话框的关闭行为,可以重新实现函数accept、reject或done。closeEvent函数只应重新实现以保留对话框的位置或覆盖标准的关闭或拒绝行为。

代码示例
  • 模式对话框:

    def countWords(self):
    
        dialog = WordCountDialog(self)
        dialog.setWordCount(document().wordCount())
        dialog.exec()
    
  • 无模式对话框:

    def find(self):
    
        if not findDialog:
            findDialog = FindDialog(self)
            findDialog.findNext.connect(self.findNext)
    
        findDialog.show()
        findDialog.raise()
        findDialog.activateWindow()
    
对话框QDialog的属性
属性描述访问功能
modal: bool此属性保存show()是否应以模态或非模态的方式弹出对话框。
默认情况下,此属性为false,show()将以无模式状态弹出对话框。将此属性设置为true相当于将windowModality设置为ApplicationModal。
exec()将忽略此属性的值,并始终以模态形式弹出对话框。
setModal(modal)
sizeGripEnabled:bool此属性用于确定是否启用尺寸夹点。
启用此属性时,QSizeGrip将放置在对话框的右下角。默认情况下,尺寸夹点处于禁用状态。
isSizeGripEnabled()

setSizeGripEnabled(arg__1)
对话框QDialog的常用方法

自定义对话框QDialog,主要方法介绍如下。

  • 对话框的模式特性设置。

    对话框的模式特性可以用setModal(bool)或setWindowModality(Qt.WindowModality)方法设置,其中枚举参数Qt.WindowModality 可以取:

    PySide6.QtCore.Qt.WindowModality

    • Qt.NonModal(非模式,可以和程序的其他窗口进行交互操作)
    • Qt.WindowModal(窗口模式,在未关闭当前对话框时,该窗口是单一窗口层次结构的模态窗口,并阻塞其父窗口、所有祖父级窗口以及其父和祖父级窗口的所有兄弟窗口的输入。)
    • Qt.ApplicationModal(应用程序模式,在未关闭当前对话框时,将阻止与任何其他窗口的交互操作)
     - 用windowModality()方法可以获取窗口的模式特性;
     - 用isModel()方法可以获取窗口是否有模式特性;
     - 用setModal(True)方法设置模式特性,默认是窗口模式。
    
  • 对话框的显示方法和默认模式

    • 显示对话框的方法有show()、open()和exec()三种。

      • 如果对话框已经有模式特性,则用show()方法显示的对话框具有模式特性
      • 如果对话框没有模式特性,则用show()方法显示的对话框没有模式特性
      • 无论对话框是否有模式特性,用open()或exec()方法显示的对话框都是模式对话框,其中用open()方法显示的对话框默认是窗口模式,用exec()方法显示的对话框默认是应用程序模式。

      当程序执行到show()或open()方法时,显示对话框后,会继续执行后续的代码,而用exec()方法显示对话框时,需关闭对话框后才执行exec()语句的后续代码。

      show()、open()和exec()三种显示对话框的方法不会改变对话框的模式属性的值。

  • 对话框的返回值。

    这里所说的返回值不是在对话框的控件中输入的值,而是指对话框被隐藏或删除时返回的一个整数,用这个整数表示用户对对话框的操作。

    通常对话框上有"确定"按钮(或OK按钮)、"应用"按钮(或Apply按钮)和"取消"按钮(或Cancel按钮)。单击"确定"按钮表示接受和使用对话框中输入的值,单击"取消"按钮表示放弃或不使用对话框中输人的值。

    为了区分客户选择了哪个按钮,可以为对话框设个返回值,例如用1表示单击"确定"按钮,用0表示单击"放弃"按钮,用2表示单击"应用"按钮。QDialog定义了两个枚举类型常量QDialog.Accepted和QDialog.Rejected,这两个常量的值分别是1和0。

    可以用setResult(result:int)方法为对话框设置一个返回值,用result()方法获取对话框的返回值,

    例如单击"确认"按钮时,隐藏对话框,并把对话框的返回值设置成 setResult(QDialog.Accepted);

    单击"取消"按钮时,隐藏对话框,并把对话框的返回值设置成setResult(QDialog.Rejected)。

  • 隐藏对话框

    • accept()方法可以隐藏对话框,并把对话框的返回值设置成 QDialog.Accepted;
    • reject()方法会隐藏对话框,并把对话框的返回值设置成 QDialog.Rejected;
    • done(int)方法会隐藏对话框,并把对话框的返回值设置成int。其实accept()方法调用的就是done(QDialog.Accepted)方法,reject()方法调用的就是done(QDialog.Rejected)方法。
    • 如果对话框是用exec()方法显示的,则exec()方法会返回对话框的值,而show()和open()方法不会返回对话框的值。

自定义对话框QDialog 的常用方法如表所示:

QDialog的方法及参数类型返回值的类型说 明
[slot]open()None以模式方法显示对话框
[slot]exec()int以模式方法显示对话框,并返回对话框的值
[slot]accept()None隐藏对话框,并将返回值设置成 QDialog.Accepted,同时发送 accepted()和 finished(int)信号
[slot]done(int)None隐藏对话框,并将返回值设置成int,同时发送 finished(int)信号
[slot]reject()None隐藏对话框,并将返回值设置成QDialog.Rejected,同时发送 accepted()和finished(int)信号
setModal(bool)None设置对话框为模式对话框
isModal()boo1获取对话框是否是模式对话框
setResult(result:int)None设置对话框的返回值,将模态对话框的结果代码设置为result。建议使用DialogCode(枚举值见下方)定义的值之一。
result()int获取对话框的返回值
setSizeGripEnabled(bool)None设置对话框的右下角是否有三角形尺寸手柄
isSizeGripEnabled()bool获取对话框的右下角是否有三角形尺寸手柄
setVisible(bool)None设置对话框是否隐藏

PySide6.QtWidgets.QDialog.DialogCode

由模态对话框返回的值。

ConstantDescription
QDialog.Accepted
QDialog.Rejected
对话框QDialog的信号

自定义对话框QDialog 的信号如表所示。

  • 当执行QDialog的accept()方法时会发送 accepted()信号
  • 执行 reject()方法时会发送 rejected()信号
  • 执行 accept()、reject()或done(int)方法时都会发送 finished(result:int)信号

其中参数 result 是对话框的返回值,用hide()或 setVisible(False)方法隐藏对话框时,不会发送信号。

QDialog的信号及参数类型说 明
accepted()执行accept()和 done(int)方法时发送信号
当对话框被用户接受,或者通过使用accepted参数调用accept()或done()被接受时,就会发出这个信号。
注意,当使用hide()或setVisible(false)隐藏对话框时,不会触发这个信号。这包括在对话框可见时删除对话框。
finished(result:int)执行accept()、reject()和 done(int)方法时发送信号
该信号在对话框的结果代码被用户设置或通过调用done()、accept()或reject()设置时发出。
注意,当使用hide()或setVisible(false)隐藏对话框时,不会触发这个信号。这包括在对话框可见时删除对话框。
rejected()执行 reject()和done(int)方法时发送信号
当对话框被用户拒绝,或者通过调用reject()或done()和rejected参数拒绝时,就会发出这个信号。
注意,当使用hide()或setVisible(false)隐藏对话框时,不会触发这个信号。这包括在对话框可见时删除对话框。
对话框QDialog的应用实例

下面的程序用于输人学生成绩,其界面如图所示。

在主界面上建立菜单,单击菜单中的"输人成绩",弹出对话框,用于输人姓名、学号和成绩。单击对话框中的"应用"按钮,将输入的信息在主界面上显示,并不退出对话框,继续输人新的信息;单击"确定"按钮,将输入的信息在主界面上显示,并退出对话框;单击"取消"按钮,放弃输入的内容,并退出对话框。单击主界面上菜单中的"保存",将显示的内容保存到 txt 文件中,单击"退出"退出整个程序。

image-20230218021008661

import sys
from PySide6.QtWidgets import QApplication,QWidget,QDialog,QPushButton,QLineEdit,QMenuBar,QTextBrowser,QVBoxLayout,QHBoxLayout,QFormLayout,QFileDialog


class MyWindows(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setWindowTitle("学生成绩输人系统")
        self.widget_setupUi()
        self.dialog_setupUi()

    def widget_setupUi(self):  # 建立主程序界面
        menuBar=QMenuBar(self)# 定义菜单栏
        file_menu=menuBar.addMenu("文件(&F)")# 定义菜单
        action_input=file_menu.addAction("输人成绩(&I)")# 添加动作
        action_save=file_menu.addAction("保存(&S)")# 添加动作
        file_menu.addSeparator()
        action_exit=file_menu.addAction("退出(SE)")# 添加动作
        self.textBrowser=QTextBrowser(self)# 显示数据控件

        v=QVBoxLayout(self)# 主程序界面的布局
        v.addWidget(menuBar)
        v.addWidget(self.textBrowser)

        action_input.triggered.connect(self.action_input_triggered)# 信号与槽函数连接
        action_save.triggered.connect(self.action_save_triggered)# 信号与槽函数连接
        action_exit.triggered.connect(self.close)# 信号与槽雨数连接

    def dialog_setupUi(self):  # 建立对话框界面
        self.dialog=QDialog(self)
        self.btn_apply=QPushButton("应用")
        self.btn_ok=QPushButton("确定")
        self.btn_cancel=QPushButton("取消")
        h=QHBoxLayout()
        h.addWidget(self.btn_apply)
        h.addWidget(self.btn_ok)
        h.addWidget(self.btn_cancel)

        self.line_name=QLineEdit()
        self.line_number=QLineEdit()
        self.line_chinese=QLineEdit()
        self.line_math=QLineEdit()
        self.line_english=QLineEdit()

        f=QFormLayout(self.dialog)
        f.addRow("姓名:",self.line_name)
        f.addRow("学号:",self.line_number)
        f.addRow("语文:",self.line_chinese)
        f.addRow("数学:",self.line_math)
        f.addRow("英语:",self.line_english)
        f.addRow(h)

        self.btn_apply.clicked.connect(self.btn_apply_clicked)# 信号与槽函数连接
        self.btn_ok.clicked.connect(self.btn_ok_clicked)# 信号与槽函数连接
        self.btn_cancel.clicked.connect(self.dialog.close)# 信号与槽函数连接

    def action_input_triggered(self):
        self.dialog.open()

    def action_save_triggered(self):
        string=self.textBrowser.toPlainText()
        if len(string)> 0:
            filename,filter=QFileDialog.getSaveFileName(self,"保存文件",".","文本文件(*.txt)")
            if len(filename)> 0:
                fp=open(filename,"+",encoding="UTF-8")
                fp.writelines(string)
                fp.close()

    def btn_apply_clicked(self):  # 自定义槽函数,单击"应用"按钮
        template="姓名:{} 学号:{} 语文:{} 数学:{} 英语:{}"
        string=template.format(self.line_name.text(),self.line_number.text(),self.line_chinese.text(),self.line_math.text(),self.line_english.text())
        self.textBrowser.append(string)
        self.line_name.clear()
        self.line_number.clear()
        self.line_chinese.clear()
        self.line_math.clear()
        self.line_english.clear()

    def btn_ok_clicked(self):
        self.btn_apply_clicked()
        self.dialog.close()


if __name__=='__main__':
    app=QApplication(sys.argv)
    win=MyWindows()

    win.show()
    sys.exit(app.exec())

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

士别三日,当挖目相待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值