PyQt5進階(一)——讓視窗裝載更多的控制元件
阿新 • • 發佈:2018-12-16
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_())