PyQt5之窗口类型


注:原创不易,转载请务必注明原作者和出处,感谢支持!

一 写在开头

1.1 本文内容

本文的主要内容:PyQt中的窗口部件:QMainWindow,QWidget,QDialog。

上述三种窗口部件都是用来创建窗口的,可以直接使用,也可以继承后再使用。它们的异同如下:

  • QMainWindow窗口可以包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,是GUI程序的主窗口。
  • QDialog是对话框窗口的基类。对话框主要用来执行短期任务,或者与用户进行互动,它可以是模态的,也可是非模态的。QDialog窗口没有菜单栏、工具栏、状态栏等。
  • QWidget即可以用来作为顶层窗口(QMainWindow),可以嵌入到其他窗口中。

三者之间的继承关系如下图:

graph TD; QWidget-->QMainWindow; QWidget-->QDialog;

二 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等等。它们之间的继承关系如下图所示。

graph TD; QDialog-->QMessageBox; QDialog-->QColorDialog; QDialog-->QFileDialog; QDialog-->QFontDialog; QDialog-->QInputDialog;

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_())

posted @ 2018-12-10 20:34  wallace-rice  阅读(4553)  评论(0编辑  收藏  举报