PyQt5之窗口類型

[TOC]python


注:原創不易,轉載請務必註明原做者和出處,感謝支持!web

一 寫在開頭

1.1 本文內容

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

上述三種窗口部件都是用來建立窗口的,能夠直接使用,也能夠繼承後再使用。它們的異同以下:工具

  • 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,代碼及效果圖以下所示。ui

#!/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的使用。url

# 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類相關的方法。spa

#!/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_())

相關文章
相關標籤/搜索