1. 程式人生 > >PyQt5進階(一)——讓視窗裝載更多的控制元件

PyQt5進階(一)——讓視窗裝載更多的控制元件

1. QTabWidget的使用

視窗上側有標籤,選擇不同標籤進入不同佈局頁面

import sys
from PyQt5.QtWidgets import *


class TabDemo(QTabWidget):
    def __init__(self, parent=None):
        super(TabDemo, self).__init__(parent)
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tab3 = QWidget()
        self.addTab(self.tab1, "Tab 1"
) self.addTab(self.tab2, "Tab 2") self.addTab(self.tab3, "Tab 3") self.tab1UI() self.tab2UI() self.tab3UI() self.setWindowTitle("Tab 例子") def tab1UI(self): layout = QFormLayout() layout.addRow("姓名", QLineEdit()) layout.addRow("地址"
, QLineEdit()) self.setTabText(0, "聯絡方式") # 也可以在addTab時進行修改 self.tab1.setLayout(layout) def tab2UI(self): layout = QFormLayout() sex = QHBoxLayout() sex.addWidget(QRadioButton("男")) sex.addWidget(QRadioButton("女")) layout.addRow(QLabel("性別"
), sex) layout.addRow("生日", QLineEdit()) self.setTabText(1, "個人詳細資訊") self.tab2.setLayout(layout) def tab3UI(self): layout = QHBoxLayout() layout.addWidget(QLabel("科目")) layout.addWidget(QCheckBox("物理")) layout.addWidget(QCheckBox("高數")) self.setTabText(2, "教育程度") self.tab3.setLayout(layout) if __name__ == '__main__': app = QApplication(sys.argv) demo = TabDemo() demo.show() sys.exit(app.exec_())

2. QStackedWidget

和上面一個示例的表現形式類似,標籤換成列表放在了視窗左側

import sys
from PyQt5.QtWidgets import *


class StackedExample(QWidget):
    def __init__(self):
        super(StackedExample, self).__init__()
        self.setGeometry(300, 50, 10, 10)
        self.setWindowTitle('StackedWidget 例子')

        # 左側列表資訊
        self.leftlist = QListWidget()
        self.leftlist.insertItem(0, '聯絡方式')
        self.leftlist.insertItem(1, '個人資訊')
        self.leftlist.insertItem(2, '教育程度')

        # 右側佈局資訊
        self.stack1 = QWidget()
        self.stack2 = QWidget()
        self.stack3 = QWidget()
        self.stack1UI()
        self.stack2UI()
        self.stack3UI()

        # 新增右側佈局到Stack
        self.Stack = QStackedWidget(self)
        self.Stack.addWidget(self.stack1)
        self.Stack.addWidget(self.stack2)
        self.Stack.addWidget(self.stack3)

        # 設定整體佈局
        hbox = QHBoxLayout(self)
        hbox.addWidget(self.leftlist)
        hbox.addWidget(self.Stack)
        self.setLayout(hbox)

        # 將訊號與槽關聯,從而改變堆疊控制元件的檢視
        self.leftlist.currentRowChanged.connect(self.display)

    def stack1UI(self):
        layout = QFormLayout()
        layout.addRow("姓名", QLineEdit())
        layout.addRow("地址", QLineEdit())
        self.stack1.setLayout(layout)

    def stack2UI(self):
        layout = QFormLayout()
        sex = QHBoxLayout()
        sex.addWidget(QRadioButton("男"))
        sex.addWidget(QRadioButton("女"))
        layout.addRow(QLabel("性別"), sex)
        layout.addRow("生日", QLineEdit())
        self.stack2.setLayout(layout)

    def stack3UI(self):
        layout = QHBoxLayout()
        layout.addWidget(QLabel("科目"))
        layout.addWidget(QCheckBox("物理"))
        layout.addWidget(QCheckBox("高數"))
        self.stack3.setLayout(layout)

    def display(self, i):
        self.Stack.setCurrentIndex(i)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = StackedExample()
    demo.show()
    sys.exit(app.exec_())

3. QDockWidget

建立一個可以停靠在QMainWindow內的視窗控制元件,它既可以保持浮動狀態獨立於主視窗,也可以在指定位置作為子視窗附加到主視窗內。

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class DockDemo(QMainWindow):
    def __init__(self, parent=None):
        super(DockDemo, self).__init__(parent)
        layout = QHBoxLayout()

        # 選單欄,對於本例中核心內容的展示無影響,可刪去
        bar = self.menuBar()
        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("save")
        file.addAction("quit")

        # 建立可停靠的視窗
        self.items = QDockWidget("Dockable", self)

        # 在停靠視窗內新增QListWidget物件
        self.listWidget = QListWidget()
        self.listWidget.addItem("item1")
        self.listWidget.addItem("item2")
        self.listWidget.addItem("item3")
        self.items.setWidget(self.listWidget)

        # 是否將可停靠視窗置於浮動狀態,預設是False,下面這句刪掉不影響顯示結果
        self.items.setFloating(False)

        # 中央控制元件
        self.setCentralWidget(QTextEdit())

        # 將停靠視窗放在中央控制元件的右側
        self.addDockWidget(Qt.RightDockWidgetArea, self.items)

        self.setLayout(layout) 
        self.setWindowTitle("Dock 例子")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = DockDemo()
    demo.show()
    sys.exit(app.exec_())

4. 多文件介面

一個典型的GUI應用程式可能有多個視窗,示例1中的選項卡控制元件和示例2中的堆疊視窗控制元件允許一次使用其中一個視窗,這時其他視窗的檢視是隱藏的,一種同時顯示多個視窗的方法是,建立多個獨立的視窗,這些獨立的視窗被稱為SDI(Single Document Interface, 單文件介面)每個視窗都可以有自己的菜單系統、工具欄等,一個簡單示例如下所示:

from PyQt5.QtWidgets import *
import sys


class TrainWindow(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self)

        self.resize(100, 60)
        self.setWindowTitle('訓練')

        self.btn_back = QPushButton('返回')

        # 介面佈局
        vbox = QVBoxLayout()
        vbox.addWidget(self.btn_back)
        self.setLayout(vbox)

        self.btn_back.clicked.connect(self.back)

    def back(self):
        self.close()


class TestWindow(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self)

        self.resize(100, 60)
        self.setWindowTitle('測試')

        self.btn_back = QPushButton('返回')

        # 介面佈局
        vbox = QVBoxLayout()
        vbox.addWidget(self.btn_back)
        self.setLayout(vbox)

        self.btn_back.clicked.connect(self.back)

    def back(self):
        self.close()


class MainWindow(QWidget):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.resize(120, 80)

        self.btn_train = QPushButton('訓練')
        self.btn_test = QPushButton('測試')

        hbox = QHBoxLayout()
        hbox.addWidget(self.btn_train)
        hbox.addWidget(self.btn_test)

        self.setLayout(hbox)

        self.btn_train.clicked.connect(self.tab_1)
        self.btn_test.clicked.connect(self.tab_2)
        self.show()

    # 開啟訓練介面
    def tab_1(self):
        self.TrainWindow = TrainWindow()
        self.TrainWindow.show()

    # 開啟測試介面
    def tab_2(self):
        self.TestWindow = TestWindow()
        self.TestWindow.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = MainWindow()
    app.exec_()

但上面這種方式需要佔用較多的記憶體資源,MDI(Multiple Document Interface, 多文件介面)應用程式佔用較少的記憶體資源,子視窗都可以放在主視窗容器(QMdiArea)中,QMdiArea通常佔據在QMainWindow物件的中央位置,子視窗在這個區域是QMdiSubWindow類的例項,可以設定任何QWidget作為子視窗物件的內部控制元件,示例如下:

import sys
from PyQt5.QtWidgets import *


class MainWindow(QMainWindow):
    count = 0

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        # 建立MdiArea控制元件
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)

        # 建立選單欄
        bar = self.menuBar()
        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")

        # 當單機選單控制元件時觸發triggered訊號,連線到槽函式windowaction()
        file.triggered.connect(self.windowaction)

        self.setWindowTitle("MDI demo")

    def windowaction(self, q):

        # 選擇“New”則新建一個子視窗並顯示,每建立一個子視窗則子視窗名稱數增加1
        if q.text() == "New":
            MainWindow.count = MainWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("subwindow" + str(MainWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        # 選擇“cascade”則將建立的子視窗層疊顯示   
        if q.text() == "cascade":
            self.mdi.cascadeSubWindows()

        # 選擇“Tiled”則將建立的子視窗平鋪顯示    
        if q.text() == "Tiled":
            self.mdi.tileSubWindows()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = MainWindow()
    demo.show()
    sys.exit(app.exec_()

5. QScrollBar

import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):

        # 設定佈局方式
        hbox = QHBoxLayout()

        # 建立標籤
        self.l1 = QLabel("拖動滑動條去改變顏色")
        self.l1.setFont(QFont("Arial", 16))

        # 建立滾動條
        self.s1 = QScrollBar()
        self.s1.setMaximum(255)
        # ScrollBar的常用訊號有兩種,valueChanged和sliderMoved,兩者的區別在於
        # sliderMoved只在拖動滾動條時有效,而valueChanged則不關心你改變值的方式
        self.s1.valueChanged.connect(self.sliderval)
        self.s2 = QScrollBar()
        self.s2.setMaximum(255)
        self.s2.sliderMoved.connect(self.sliderval)
        self.s3 = QScrollBar()
        self.s3.setMaximum(255)
        self.s3.sliderMoved.connect(self.sliderval)

        # 為佈局新增控制元件
        hbox.addWidget(self.l1)
        hbox.addWidget(self.s1)
        hbox.addWidget(self.s2)
        hbox.addWidget(self.s3)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QScrollBar 例子')

        self.setLayout(hbox)

    # 槽函式,將滾動條的值轉化為RGB顏色值
    def sliderval(self):

        palette = QPalette()
        c = QColor(self.s1.value(), self.s2.value(), self.s3.value(), 255)
        palette.setColor(QPalette.Foreground, c)
        self.l1.setPalette(palette)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Example()
    demo.show()
    sys.exit(app.exec_())