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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM