PyQt5之窗口类型
注:原创不易,转载请务必注明原作者和出处,感谢支持!
一 写在开头
1.1 本文内容
本文的主要内容:PyQt中的窗口部件:QMainWindow,QWidget,QDialog。
上述三种窗口部件都是用来创建窗口的,可以直接使用,也可以继承后再使用。它们的异同如下:
- QMainWindow窗口可以包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,是GUI程序的主窗口。
- QDialog是对话框窗口的基类。对话框主要用来执行短期任务,或者与用户进行互动,它可以是模态的,也可是非模态的。QDialog窗口没有菜单栏、工具栏、状态栏等。
- QWidget即可以用来作为顶层窗口(QMainWindow),可以嵌入到其他窗口中。
三者之间的继承关系如下图:
二 QMainWindow
2.1 知识铺垫
何为顶层窗口?如果一个窗口包含一个或多个窗口,那么这个窗口就是父窗口,被包含的窗口则是子窗口。没有父窗口的窗口则是顶层窗口。QMainWindow就是一个顶层窗口,它可以包含很多界面元素,如菜单栏、工具栏、状态栏、子窗口等等。QMainWindow元素布局如下图(来自Qt文档)。

QMainWindow常用的方法有:
| 方法 | 描述 | 
|---|---|
| addToolBar() | 添加工具栏 | 
| centralWidget() | 返回窗口中心的控件,未设置时返回NULL | 
| menuBar() | 返回主窗口的菜单栏 | 
| setCentralWidget() | 设置窗口中心的控件 | 
| setStatusBar() | 设置状态栏 | 
| statusBar() | 获得状态栏对象后,调用状态栏对象的showMessage()方法显示状态栏信息 | 
2.2 QMainWindow实例
什么也不设置的“空白”QMainWindow,代码及效果图如下所示。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = QMainWindow()
    w.show()
    sys.exit(app.exec_())

我们通过一个仿照Windows系统的中记事本程序的小实例来了解QMainWindow的使用。
# text-editor.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import webbrowser
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QMainWindow, QTextEdit, QAction, QApplication, \
        QMessageBox, QFileDialog, QDesktopWidget
class TextEditor(QMainWindow):
    '''
    TextEditor : 一个简单的记事本程序
    '''
    def __init__(self):
        super().__init__()
        self.copiedText = ''
        self.initUI()
    # 初始化窗口界面
    def initUI(self):
        # 设置中心窗口部件为QTextEdit
        self.textEdit = QTextEdit()
        self.setCentralWidget(self.textEdit)
        self.textEdit.setText('')
        # 定义一系列的Action
        # 退出
        exitAction = QAction(QIcon('./images/exit.png'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit application')
        exitAction.triggered.connect(self.close)
        # 新建
        newAction = QAction(QIcon('./images/new.png'), 'New', self)
        newAction.setShortcut('Ctrl+N')
        newAction.setStatusTip('New application')
        newAction.triggered.connect(self.__init__)
        # 打开
        openAction = QAction(QIcon('./images/open.png'), 'Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.setStatusTip('Open Application')
        openAction.triggered.connect(self.open)
        # 保存
        saveAction = QAction(QIcon('./images/save.png'), 'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save Application')
        saveAction.triggered.connect(self.save)
        # 撤销
        undoAction = QAction(QIcon('./images/undo.png'), 'Undo', self)
        undoAction.setShortcut('Ctrl+Z')
        undoAction.setStatusTip('Undo')
        undoAction.triggered.connect(self.textEdit.undo)
        # 重做
        redoAction = QAction(QIcon('./images/redo.png'), 'Redo', self)
        redoAction.setShortcut('Ctrl+Y')
        redoAction.setStatusTip('Redo')
        redoAction.triggered.connect(self.textEdit.redo)
        # 拷贝
        copyAction = QAction(QIcon('./images/copy.png'), 'Copy', self)
        copyAction.setShortcut('Ctrl+C')
        copyAction.setStatusTip('Copy')
        copyAction.triggered.connect(self.copy)
        # 粘贴
        pasteAction = QAction(QIcon('./images/paste.png'), 'Paste', self)
        pasteAction.setShortcut('Ctrl+V')
        pasteAction.setStatusTip('Paste')
        pasteAction.triggered.connect(self.paste)
        # 剪切
        cutAction = QAction(QIcon('./images/cut.png'), 'Cut', self)
        cutAction.setShortcut('Ctrl+X')
        cutAction.setStatusTip('Cut')
        cutAction.triggered.connect(self.cut)
        # 关于
        aboutAction = QAction(QIcon('./images/about.png'), 'About', self)
        aboutAction.setStatusTip('About')
        aboutAction.triggered.connect(self.about)
        # 添加菜单
        # 对于菜单栏,注意menuBar,menu和action三者之间的关系
        # 首先取得QMainWindow自带的menuBar:menubar = self.menuBar()
        # 然后在menuBar里添加Menu:fileMenu = menubar.addMenu('&File')
        # 最后在Menu里添加Action:fileMenu.addAction(newAction)
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(newAction)
        fileMenu.addAction(openAction)
        fileMenu.addAction(saveAction)
        fileMenu.addAction(exitAction)
        editMenu = menubar.addMenu('&Edit')
        editMenu.addAction(undoAction)
        editMenu.addAction(redoAction)
        editMenu.addAction(cutAction)
        editMenu.addAction(copyAction)
        editMenu.addAction(pasteAction)
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(aboutAction)
        # 添加工具栏
        # 对于工具栏,同样注意ToolBar和Action之间的关系
        # 首先在QMainWindow中添加ToolBar:tb1 = self.addToolBar('File')
        # 然后在ToolBar中添加Action:tb1.addAction(newAction)
        tb1 = self.addToolBar('File')
        tb1.addAction(newAction)
        tb1.addAction(openAction)
        tb1.addAction(saveAction)
        tb2 = self.addToolBar('Edit')
        tb2.addAction(undoAction)
        tb2.addAction(redoAction)
        tb2.addAction(cutAction)
        tb2.addAction(copyAction)
        tb2.addAction(pasteAction)
        tb3 = self.addToolBar('Exit')
        tb3.addAction(exitAction)
        # 添加状态栏,以显示每个Action的StatusTip信息
        self.statusBar()
        self.setGeometry(0, 0, 600, 600)
        self.setWindowTitle('Text Editor')
        self.setWindowIcon(QIcon('./images/text.png'))
        self.center()
        self.show()
    # 主窗口居中显示
    def center(self):
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
    # 定义Action对应的触发事件,在触发事件中调用self.statusBar()显示提示信息
    # 重写closeEvent
    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Confirm', \
                'Are you sure to quit without saving ?', \
                QMessageBox.Yes | QMessageBox.No, \
                QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.statusBar().showMessage('Quiting...')
            event.accept()
        else:
            event.ignore()
            self.save()
            event.accept()
    # open
    def open(self):
        self.statusBar().showMessage('Open Text Files')
        fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
        self.statusBar().showMessage('Open File')
        if fname[0]:
            f = open(fname[0], 'r')
            with f:
                data = f.read()
                self.textEdit.setText(data)
    # save
    def save(self):
        self.statusBar().showMessage('Add extension to file name')
        fname = QFileDialog.getSaveFileName(self, 'Save File')
        if (fname[0]):
            data = self.textEdit.toPlainText()
            f = open(fname[0], 'w')
            f.write(data)
            f.close()
    # copy
    def copy(self):
        cursor = self.textEdit.textCursor()
        textSelected = cursor.selectedText()
        self.copiedText = textSelected
    # paste
    def paste(self):
        self.textEdit.append(self.copiedText)
    # cut
    def cut(self):
        cursor = self.textEdit.textCursor()
        textSelected = cursor.selectedText()
        self.copiedText = textSelected
        self.textEdit.cut()
    # about
    def about(self):
        url = 'https://en.wikipedia.org/wiki/Text_editor'
        self.statusBar().showMessage('Loading url...')
        webbrowser.open(url)
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = TextEditor()
    sys.exit(app.exec_())

三 QWidget
QWidget类是所有用户界面对象的基类,所有的窗口和控件都直接或间接继承自QWidget类。QWidget类相关的方法。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QToolTip
from PyQt5.QtGui import QIcon, QFont
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = QWidget()
    btn = QPushButton(w)
    btn.setText('Button')
    btn.move(20, 20)
    w.resize(300, 200)
    w.move(250, 200)
    w.setWindowTitle('QWidget')
    # setWindowIcon()用于设置应用程序图标
    w.setWindowIcon(QIcon('./icon.png'))
    # setFont()为QToolTip设定字体
    QToolTip.setFont(QFont('Monospace Regular', 20))
    w.setToolTip('这是一个<b>气泡提示!</b>')
    w.show()
    print('QWidget:')
    print('w.x() = %d' % w.x())
    print('w.y() = %d' % w.y())
    print('w.width() = %d' % w.width())
    print('w.height() = %d' % w.height())
    print('QWidget.geometry')
    print('w.geometry().x() = %d' % w.geometry().x())
    print('w.geometry().y() = %d' % w.geometry().y())
    print('w.geometry().width() = %d' % w.geometry().width())
    print('w.geometry().height() = %d' % w.geometry().height())
    sys.exit(app.exec_())

脚本输出为:
QWidget:
w.x() = 250
w.y() = 200
w.width() = 300
w.height() = 200
QWidget.geometry
w.geometry().x() = 250
w.geometry().y() = 200
w.geometry().width() = 300
w.geometry().height() = 200
四 QDialog
QDialog的各种子类提供了各种标准对话框,比如QMessageBox, QFileDialog, QInputDialog, QFontDialog等等。它们之间的继承关系如下图所示。
4.1 QDialog
QDialog类中常用方法:
| 方法 | 描述 | 
|---|---|
| setWindowTitle() | 设置对话框标题 | 
| setWindowModality() | 设置窗口模态。取值如下: Qt.NonModal - 非模态 Qt.WindowModal - 窗口模态 Qt.ApplicationModal - 应用程序模态 | 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QDialog
from PyQt5.QtCore import Qt
class DialogWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Dialog')
        self.resize(350, 300)
        self.btn = QPushButton(self)
        self.btn.setText('弹出对话框')
        self.btn.move(50, 50)
        self.btn.clicked.connect(self.showDialog)
        self.show()
    def showDialog(self):
        dialog = QDialog()
        btn = QPushButton('ok', dialog)
        btn.move(50, 50)
        dialog.setWindowTitle('Dialog')
        dialog.setWindowModality(Qt.ApplicationModal)
        dialog.exec_()
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = DialogWindow()
    sys.exit(app.exec_())

4.2 QMessageBox
QMessageBox是一种通用的弹出式对话框,用于显示消息,允许用户通过单击不同的标准按钮对消息进行反馈。每个标准按钮都有一个预定义的文本、角色和十六进制数。QMessageBox类提供了许多常用的弹出式对话框,比如提示、警告、错误、询问、关于等对话框。这些不同类型的QMessageBox对话框只是显示时得图标不同,其他功能是一样的。QMessageBox类中常用的方法有:
| 方法 | 描述 | 
|---|---|
| information(QWidget parent, title, text, buttons, defaultButton) | parent:父窗口 title:对话框标题 text:对话框文本 buttons:多个标准按钮 defaultButton:默认选中的标准按钮 | 
| question(QWidget parent, title, text, buttons, defaultButton) | 问答对话框 | 
| warning(QWidget parent, title, text, buttons, defaultButton) | 警告对话框 | 
| critical(QWidget parent, title, text, buttons, defaultButton) | 严重错误对话框 | 
| about(QWidget parent, title, text) | 关于对话框 | 
| setTitle() | 设置标题 | 
| setText() | 设置消息正文 | 
| setIcon() | 设置对话框的图片 | 
QMessageBox中的标准按钮类型有:
| 类型 | 描述 | 
|---|---|
| QMessageBox.Ok | 确定 | 
| QMessageBox.Cancel | 取消 | 
| QMessageBox.Yes | 是 | 
| QMessageBox.No | 否 | 
| QMessageBox.Abort | 终止 | 
| QMessageBox.Retry | 重试 | 
| QMessageBox.Ignore | 忽略 | 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QVBoxLayout, \
        QPushButton
class MessageBoxWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        vbox = QVBoxLayout()
        btn = QPushButton('点击弹出消息框')
        btn.clicked.connect(self.showMessageBox)
        vbox.addWidget(btn)
        self.setLayout(vbox)
        self.setWindowTitle('QMessageBox')
        self.resize(300, 200)
        self.show()
    def showMessageBox(self):
        QMessageBox.question(self, '标题', '正文内容', QMessageBox.Yes | \
                QMessageBox.No, QMessageBox.Yes)
        QMessageBox.warning(self, '标题', '正文内容', QMessageBox.Yes | \
                QMessageBox.No, QMessageBox.Yes)
        QMessageBox.critical(self, '标题', '正文内容', QMessageBox.Yes | \
                QMessageBox.No, QMessageBox.Yes)
        QMessageBox.about(self, '标题', '正文内容')
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MessageBoxWindow()
    sys.exit(app.exec_())




4.3 QInputDialog
QInputDialog控件是一个标准对话框,由一个文本框和两个按钮(OK和Cancel)组成。当用户单击OK按钮后,在父窗口可以接受通过QInputDialog控件输入的信息。在QInputDialog控件中可以输入数字、字符串或者列表中的选择。标签用于提示必要的信息。QInputDialog类常用的方法有:
| 方法 | 描述 | 
|---|---|
| getInt() | 从控件中获取标准整型输入 | 
| getDouble() | 从控件中获取标准浮点数输入 | 
| getText() | 从控件中获取标准字符串输入 | 
| getItem() | 从控件中获取列表里的选项输入 | 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QFormLayout, QPushButton, QLineEdit, \
        QInputDialog, QApplication
class InputDialogWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        layout = QFormLayout()
        self.btn1 = QPushButton('获得列表里的选项')
        self.btn1.clicked.connect(self.getItem)
        self.le1 = QLineEdit()
        layout.addRow(self.btn1, self.le1)
        self.btn2 = QPushButton('获得字符串')
        self.btn2.clicked.connect(self.getText)
        self.le2 = QLineEdit()
        layout.addRow(self.btn2, self.le2)
        self.btn3 = QPushButton('获得整数')
        self.btn3.clicked.connect(self.getInt)
        self.le3 = QLineEdit()
        layout.addRow(self.btn3, self.le3)
        self.setLayout(layout)
        self.setWindowTitle('QInputDialog')
        self.show()
    def getItem(self):
        items = ('C', 'C++', 'Java', 'Python')
        item, ok = QInputDialog.getItem(self, 'Select Input Dialog', \
                '语言列表', items, 0, False)
        if ok and item:
            self.le1.setText(item)
    def getText(self):
        text, ok = QInputDialog.getText(self, 'Text Input Dialog', \
                '输入姓名:')
        if ok:
            self.le2.setText(str(text))
    def getInt(self):
        num, ok = QInputDialog.getInt(self, 'Integer Input Dialog', \
                '输入数字:')
        if ok:
            self.le3.setText(str(num))
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = InputDialogWindow()
    sys.exit(app.exec_())



4.4 QFontDialg
QFontDialog控件是一个常用的字体选择对话框,可以让用户选择显示文本的字体样式、字号大小和格式。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QFontDialog, QApplication, \
        QPushButton, QLabel
class FontDialogWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        layout = QVBoxLayout()
        self.btn = QPushButton('选择字体')
        self.btn.clicked.connect(self.chooseFont)
        self.lb = QLabel('Hello, 测试字体例子')
        layout.addWidget(self.btn)
        layout.addWidget(self.lb)
        self.setLayout(layout)
        self.setWindowTitle('FontDialog')
        self.show()
    def chooseFont(self):
        font, ok = QFontDialog.getFont()
        if ok:
            self.lb.setFont(font)
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = FontDialogWindow()
    sys.exit(app.exec_())


4.5 QFileDialog
QFileDialog是用于打开和保存文件的标准对话框。QFileDialog在打开文件时使用了文件过滤器,用于显示指定扩展名的文件。也可以设置使用QFileDialog打开文件时的起始目录和指定扩展名的文件。QFileDialog类的常用方法有:
| 方法 | 描述 | 
|---|---|
| getOpenFileName() | 返回用户所选择文件的名称,并打开该文件 | 
| getSaveFileName() | 使用用户选择的文件名并保存文件 | 
| setFileMode() | 可以选择的文件类型,可选枚举常量有: QFileDialog.AnyFile:任何文件 QFileDialog.ExistingFile:已存在的文件 QFileDialog.Directory:文件目录 QFileDialog.ExistingFiles:已存在的多个文件 | 
| setFilter() | 设置过滤器,只显示过滤器允许的文件类型 | 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QPushButton, \
        QLabel, QTextEdit, QFileDialog
from PyQt5.QtCore import QDir
from PyQt5.QtGui import QPixmap
class FileDialogWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        layout = QVBoxLayout()
        self.btn1 = QPushButton('加载图片')
        self.btn1.clicked.connect(self.chooseImage)
        self.lb = QLabel()
        layout.addWidget(self.btn1)
        layout.addWidget(self.lb)
        self.btn2 = QPushButton('加载文本文件')
        self.btn2.clicked.connect(self.chooseTextFile)
        self.content = QTextEdit()
        layout.addWidget(self.btn2)
        layout.addWidget(self.content)
        self.setLayout(layout)
        self.setWindowTitle('FileDialg')
        self.show()
    def chooseImage(self):
        fname, _ = QFileDialog.getOpenFileName(self, 'Open file', '/home', \
                "Image files (*.jpg *.png *.gif)")
        self.lb.setPixmap(QPixmap(fname))
    def chooseTextFile(self):
        dlg = QFileDialog()
        dlg.setFileMode(QFileDialog.AnyFile)
        dlg.setFilter(QDir.Files)
        if dlg.exec_():
            fname = dlg.selectedFiles()
            f = open(fname[0], 'r')
            with f:
                data = f.read()
                self.content.setText(data)
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = FileDialogWindow()
    sys.exit(app.exec_())

 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号