pyqt5-基礎


PyQt5是一套來自Digia的Qt5應用框架和Python的粘合劑。支持Python2.x和Python3.x版本。

PyQt5以一套Python模塊的形式來實現功能。它包含了超過620個類,600個方法和函數。它是一個多平台的工具套件,它可以運行在所有的主流操作系統中,包含Unix,Windows和Mac OS。PyQt5采用雙重許可模式。開發者可以在GPL和社區授權之間選擇。

PyQt5的類被划分在幾個模塊中,下面列出了這些模塊:

  • QtCore :模塊包含了非GUI的功能設計。這個模塊被用來實現時間,文件和目錄,不同數據類型,流,URL,mime類型,線程和進程。
  • QtGui:模塊包含的類用於窗口化的系統結構,事件處理,2D繪圖,基本圖形,字體和文本。
  • QtWidgets:模塊包含的類提供了一套UI元素來創建經典桌面風格用戶界面。
  • QtMultimedia:模塊包含的類用於處理多媒體內容和鏈接攝像頭和無線電功能的API。
  • QtBluetooth:模塊包含的類用於掃描藍牙設備,並且和他們建立連接互動。
  • QtNetwork:模塊包含的類用於網絡編程,這些類使TCP/IP和UDP客戶端/服務端編程更加容易和輕便。
  • QtPositioning:模塊包含的類用於多種可獲得資源的位置限定,包含衛星定位,Wi-Fi,或一個文本文件。
  • Enginio:模塊用於解決客戶端訪問Qt雲服務托管。
  • QtWebSockets:模塊用於解決客戶端訪問Qt雲服務托管。
  • QtWebKit:包含的關於瀏覽器的類用於解決基於WebKit2的支持庫。
  • QtWebKitWidgets:模塊包含的關於WebKit1的類基本解決瀏覽器使用基於QtWidgets應用問題。 
  • QtXmlQtXml 模塊包含的類用於解析XML文件。這個模塊提供SAX和DOM API解決方法。
  • QtSvg:模塊提供類用於顯示SVG文件內容。Scalable Vector Graphics (SVG) 是一種語言,用XML來描述二維圖形和圖形應用程序。
  • QtSql:模塊提供類驅動數據庫工作。 
  • QtTest:模塊包含了方法提供PyQt5應用的單元測試。

PyQt5不向后兼容PyQt4;這是一些在PyQt5中的重要改變。然而,將舊代碼遷移到新的版本中並不是非常困難。不同點如下:

  • Python 模塊已經被改寫. 一些模塊被舍棄 (QtScript), 部分的模塊被分割成子模塊 (QtGuiQtWebKit).
  • 新的模塊被引進, 包含 QtBluetoothQtPositioning, 和 Enginio.
  • PyQt5 只支持最新風格的信號和槽的寫法. SIGNAL()和SLOT()的調用將不會被長時間支持.
  • PyQt5 不支持任何在Qt 5.0版本中棄用或取消的API.

安裝

pip install pyqt5

1、示例:簡單的窗口

import sys
from PyQt5.QtWidgets import QApplication, QWidget

def show_w():
	'顯示窗口'

	app = QApplication(sys.argv) # 所有的PyQt5應用必須創建一個應用(Application)對象。
	# sys.argv參數是一個來自命令行的參數列表。

	w = QWidget() # Qwidget組件是PyQt5中所有用戶界面類的基礎類。我們給QWidget提供了默認的構造方法。
	# 默認構造方法沒有父類。沒有父類的widget組件將被作為窗口使用。

	w.resize(500, 500) # resize()方法調整了widget組件的大小。它現在是500px寬,500px高。
	w.move(500, 100) # move()方法移動widget組件到一個位置,這個位置是屏幕上x=500,y=200的坐標。
	w.setWindowTitle('Simple') # 設置了窗口的標題。這個標題顯示在標題欄中。
	w.show() # show()方法在屏幕上顯示出widget。一個widget對象在這里第一次被在內存中創建,並且之后在屏幕上顯示。

	sys.exit(app.exec_()) # 應用進入主循環。在這個地方,事件處理開始執行。主循環用於接收來自窗口觸發的事件,
	# 並且轉發他們到widget應用上處理。如果我們調用exit()方法或主widget組件被銷毀,主循環將退出。
	# sys.exit()方法確保一個不留垃圾的退出。系統環境將會被通知應用是怎樣被結束的。

if __name__ == '__main__':

	show_w()

2、示例:應用圖標、按鈕、窗口關閉

 

引入相關模塊

 

import sys
from PyQt5.QtWidgets import (QWidget, QToolTip, QDesktopWidget, QMessageBox,QTextEdit,QLabel,
    QPushButton, QApplication,QMainWindow, QAction, qApp, QHBoxLayout, QVBoxLayout,QGridLayout,
	QLineEdit)
from PyQt5.QtGui import QFont,QIcon
from PyQt5.QtCore import QCoreApplication

 

應用圖標是一個常常顯示在標題欄左上方角落的小圖片。

 

# ##***應用圖標***## #
class AppIcon(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self): 
		self.setGeometry(300, 300, 300, 220) # 窗口在屏幕上顯示,並設置了它的尺寸。resize()和remove()合而為一的方法。
		# 前兩個參數定位了窗口的x軸和y軸位置。第三個參數是定義窗口的寬度,第四個參數是定義窗口的高度。
		self.setWindowTitle('Icon') # 創建一個窗口標題
		self.setWindowIcon(QIcon('t1.jpg')) # 創建一個QIcon對象並接收一個我們要顯示的圖片路徑作為參數。
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = AppIcon()
	sys.exit(app.exec_())

 

提示文本

 

# ##***提示文本***## #
class PromptText(QWidget):

	def __init__(self):
		super().__init__()
		self.initUI()

	def initUI(self):
		QToolTip.setFont(QFont('SansSerif', 10))  # 這個靜態方法設置了用於提示框的字體。
		# 這里使用10px大小的SansSerif字體。
		self.setToolTip('This is a <b>QWidget</b> widget')  # 調用setTooltip()方法創建提示框。
		# 可以在提示框中使用富文本格式。
		btn = QPushButton('Button', self)  # 創建按鈕
		btn.setToolTip('This is a <b>QPushButton</b> widget')  # 設置按鈕提示框
		btn.resize(btn.sizeHint())  # 改變按鈕大小
		btn.move(300, 100)  # 移動按鈕位置
		self.setGeometry(300, 100, 600, 600)
		self.setWindowTitle('Tooltips')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = PromptText()
	sys.exit(app.exec_())

 

按鈕

QPushButton(string text, QWidget parent = None)
# text參數是將顯示在按鈕中的內容。
# parent參數是一個用來放置我們按鈕的組件。在下文例子中將會是QWidget組件。
# 一個應用的組件是分層結構的。在這個分層內,大多數組件都有父類。沒有父類的組件是頂級窗口。

明顯的關閉窗口的方法是點擊標題欄的X標記。

 

# ##***關閉窗口***## #
class CloseW(QWidget):

	def __init__(self):
		super().__init__()
		self.initUI()

	def initUI(self):
		qbtn = QPushButton('Quit', self)  # 創建了一個按鈕。按鈕是一個QPushButton類的實例。
		# 構造方法的第一個參數是顯示在button上的標簽文本。第二個參數是父組件。
		# 父組件是Example組件,它繼承了QWiget類。
		qbtn.clicked.connect(QCoreApplication.instance().quit)
		qbtn.resize(qbtn.sizeHint())
		qbtn.move(500, 50)
		self.setGeometry(300, 100, 600, 600)
		self.setWindowTitle('excise')
		self.show()

if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = CloseW()
	sys.exit(app.exec_())

 

信號&槽機制

qbtn.clicked.connect(QCoreApplication.instance().quit)

在PyQt5中,事件處理系統由信號&槽機制建立。如果我們點擊了按鈕,信號clicked被發送。槽可以是Qt內置的槽或Python 的一個方法調用。QCoreApplication類包含了主事件循環;它處理和轉發所有事件。instance()方法給我們返回一個實例化對象。注意QCoreAppli類由QApplication創建。點擊信號連接到quit()方法,將結束應用。事件通信在兩個對象之間進行:發送者和接受者。發送者是按鈕,接受者是應用對象。

Message Box

默認的,如果我們點擊了標題欄上的x按鈕,QWidget會被關閉。又是我們希望修改這個默認動作。舉個例子,如果我們有個文件在編輯器內打開,並且我們對這個文件做了一些修改。 我們顯示一個message box來確認這個動作。

# ##***Message Box***## #
class MessageBox(QWidget):

	def __init__(self):
		super().__init__()
		self.initUI()

	def initUI(self):
		qbtn = QPushButton('Quit', self)  # 創建了一個按鈕。按鈕是一個QPushButton類的實例。
		# 構造方法的第一個參數是顯示在button上的標簽文本。第二個參數是父組件。
		# 父組件是Example組件,它繼承了QWiget類。
		qbtn.clicked.connect(QCoreApplication.instance().quit)
		qbtn.resize(qbtn.sizeHint())
		qbtn.move(500, 50)
		self.setGeometry(300, 100, 600, 600)
		self.setWindowTitle('excise')
		self.show()

	def closeEvent(self, event):

		reply = QMessageBox.question(self, 'Message',
									 "Are you sure to quit?", QMessageBox.Yes |
									 QMessageBox.No, QMessageBox.No)
		if reply == QMessageBox.Yes:
			event.accept()
		else:
			event.ignore()

if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = MessageBox()
	sys.exit(app.exec_())

如果我們關閉一個QWidget,QCloseEvent類事件將被生成。要修改組件動作我們需要重新實現closeEvent()事件處理方法。

reply = QMessageBox.question(self, 'Message', "Are you sure to quit?", QMessageBox.Yes |QMessageBox.No, QMessageBox.No)

我們實現一個帶兩個按鈕的message box:YES和No按鈕。代碼中第一個字符串的內容被顯示在標題欄上。第二個字符串是對話框上顯示的文本。第三個參數指定了顯示在對話框上的按鈕集合。最后一個參數是默認選中的按鈕。這個按鈕一開始就獲得焦點。返回值被儲存在reply變量中。

  if reply == QMessageBox.Yes:
	event.accept()
else:
	event.ignore()

在這里我們測試一下返回值。代碼邏輯是如果我們點擊Yes按鈕,我們接收到的事件關閉事件,這將導致了組件的關閉和應用的結束。否則不是點擊Yes按鈕的話我們將忽略將關閉事件。

屏幕居中窗口

 

# ##***屏幕居中窗口***## #
class CenterW(QWidget):

	def __init__(self):
		super().__init__()
		self.initUI()

	def initUI(self):
		self.resize(250, 150)
		self.center()  # 將窗口居中放置的代碼在自定義的center()方法中。
		self.setWindowTitle('Center')
		self.show()

	def center(self):

		qr = self.frameGeometry() # 獲得主窗口的一個矩形特定幾何圖形。這包含了窗口的框架。
		cp = QDesktopWidget().availableGeometry().center() # 算出相對於顯示器的絕對值。
		# 並且從這個絕對值中,我們獲得了屏幕中心點。
		qr.moveCenter(cp) # 矩形已經設置好了它的寬和高。現在我們把矩形的中心設置到屏幕的中間去。
		# 矩形的大小並不會改變。
		self.move(qr.topLeft()) # 移動了應用窗口的左上方的點到qr矩形的左上方的點,因此居中顯示在我們的屏幕上。


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = CenterW()
	sys.exit(app.exec_())

 

3、菜單和工具欄

菜單是位於菜單欄的一組命令操作。工具欄是應用窗體中由按鈕和一些常規命令操作組成的組件。

主窗口

QMainWindow類提供了一個應用主窗口。默認創建一個擁有狀態欄、工具欄和菜單欄的經典應用窗口骨架。

狀態欄

狀態欄是用來顯示狀態信息的組件。狀態欄又QMainWindow組件幫助創建完成(依賴於QMainWindow組件)。

# ##***狀態欄***## #
class StatusBar(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		self.statusBar().showMessage('Ready')

		self.setGeometry(300, 300, 250, 150)
		self.setWindowTitle('Statusbar')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = StatusBar()
	sys.exit(app.exec_())

為了得到狀態欄,我們調用了QtGui.QMainWindow類的statusBar()方法。第一次調用這個方法創建了一個狀態欄。隨后方法返回狀態欄對象。然后用showMessage()方法在狀態欄上顯示一些信息。

菜單欄

菜單欄是GUI應用的常規組成部分。是位於各種菜單中的一組命令操作(Mac OS 對待菜單欄有些不同。為了獲得全平台一致的效果,我們可以在代碼中加入一行:menubar.setNativeMenuBar(False))。

# ##***菜單欄***## #
class MenuBar(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		exitAction = QAction(QIcon('t2.jpg'), '&Exit', self)
		exitAction.setShortcut('Ctrl+Q')
		exitAction.setStatusTip('Exit application')
		exitAction.triggered.connect(qApp.quit)

		self.statusBar()

		menubar = self.menuBar()
		fileMenu = menubar.addMenu('&File')
		fileMenu.addAction(exitAction)

		self.setGeometry(300, 300, 300, 200)
		self.setWindowTitle('Menubar')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = MenuBar()
	sys.exit(app.exec_())

在上面的例子中,我們創建了有一個菜單項的菜單欄。這個菜單項包含一個選中后中斷應用的動作。

exitAction = QAction(QIcon('t2.jpg'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')

QAction是一個用於菜單欄、工具欄或自定義快捷鍵的抽象動作行為。在上面的三行中,我們創建了一個有指定圖標和文本為'Exit'的標簽。另外,還為這個動作定義了一個快捷鍵。第三行創建一個當我們鼠標浮於菜單項之上就會顯示的一個狀態提示。

工具欄

菜單可以集成所有命令,這樣我們可以在應用中使用這些被集成的命令。工具欄提供了一個快速訪問常用命令的方式。

# ##***工具欄***## #
class ToolBar(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		exitAction = QAction(QIcon('t3.jpg'), 'Exit', self)
		exitAction.setShortcut('Ctrl+Q')
		exitAction.triggered.connect(qApp.quit)

		self.toolbar = self.addToolBar('Exit')
		self.toolbar.addAction(exitAction)

		self.setGeometry(300, 300, 300, 200)
		self.setWindowTitle('Toolbar')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = ToolBar()
	sys.exit(app.exec_())

上述例子中,我們創建了一個簡單的工具欄。工具欄有一個動作,當這個退出動作被觸發時應用將會被中斷。

 

組件組合

 

在上面的例子中,我們創建了菜單欄、工具欄和狀態欄。下面我們將創建一個中心組件。

# ##***組件組合***## #
class Combination(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		textEdit = QTextEdit()
		self.setCentralWidget(textEdit)

		exitAction = QAction(QIcon('t2.jpg'), 'Exit', self)
		exitAction.setShortcut('Ctrl+Q')
		exitAction.setStatusTip('Exit application')
		exitAction.triggered.connect(self.close)

		self.statusBar()

		menubar = self.menuBar()
		fileMenu = menubar.addMenu('&File')
		fileMenu.addAction(exitAction)

		toolbar = self.addToolBar('Exit')
		toolbar.addAction(exitAction)

		self.setGeometry(300, 300, 350, 250)
		self.setWindowTitle('Main window')
		self.show()

if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = Combination()
	sys.exit(app.exec_())

示例代碼創建了一個帶有菜單欄、工具欄和狀態欄的經典GUI應用骨架。

textEdit = QTextEdit()
self.setCentralWidget(textEdit)

在這里我們創建了一個文本編輯框組件。我們將它設置成QMainWindow的中心組件。中心組件占據了所有剩下的空間。

4、布局管理

布局管理是GUI編程中的一個重要方面。布局管理是一種如何在應用窗口上防止組件的一種方法。我們可以通過兩種基礎方式來管理布局。我們可以使用絕對定位和布局類。

4.1 絕對定位

 

程序指定了組件的位置並且每個組件的大小用像素作為單位來丈量。當你使用了絕對定位,我們需要知道下面的幾點限制:

 

  • 如果我們改變了窗口大小,組件的位置和大小並不會發生改變。
  • 在不同平台上,應用的外觀可能不同
  • 改變我們應用中的字體的話可能會把應用弄得一團糟。
  • 如果我們決定改變我們的布局,我們必須完全重寫我們的布局,這樣非常乏味和浪費時間。

 

# ##***絕對定位***## #
class AbsPosition(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		lbl1 = QLabel('Zetcode', self)
		lbl1.move(15, 10)

		lbl2 = QLabel('tutorials', self)
		lbl2.move(35, 40)

		lbl3 = QLabel('for programmers', self)
		lbl3.move(55, 70)

		self.setGeometry(300, 300, 250, 150)
		self.setWindowTitle('Absolute')
		self.show()

if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = AbsPosition()
	sys.exit(app.exec_())

我們使用move()方法來定位我們的組件。在上面的例子中我們使用move()方法定位了一些標簽組件。在使用move()方法時,我們給move()方法提供了x和y坐標作為參數。move()使用的坐標系統是從左上角開始計算的。x值從左到右增長。y值從上到下增長。

4.2 箱布局

布局管理器的布局管理類非常靈活,實用。它是將組件定位在窗口上的首選方式。QHBoxLayout和QVBoxLayout是兩個基礎布局管理類,他們水平或垂直的線性排列組件。想象一下我們需要在右下角排列兩個按鈕。為了使用箱布局,我們將使用一個水平箱布局和垂直箱布局來實現。同樣為了使用一些必要的空白,我們將添加一些拉伸因子。

# ##***箱布局***## #
class BoxLayout(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		okButton = QPushButton("OK")
		cancelButton = QPushButton("Cancel")

		# 創建了一個水平箱布局,並且增加了一個拉伸因子和兩個按鈕。拉伸因子在兩個按鈕之前增加了一個可伸縮空間。
		# 這會將按鈕推到窗口的右邊。
		hbox = QHBoxLayout()
		hbox.addStretch(1)
		hbox.addWidget(okButton)
		hbox.addWidget(cancelButton)

		# 為了創建必要的布局,把水平布局放置在垂直布局內。拉伸因子將把包含兩個按鈕的水平箱布局推到窗口的底邊。
		vbox = QVBoxLayout()
		vbox.addStretch(1)
		vbox.addLayout(hbox)

		self.setLayout(vbox)

		self.setGeometry(300, 300, 300, 150)
		self.setWindowTitle('Buttons')
		self.show()
		
if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = BoxLayout()
	sys.exit(app.exec_())

例子在右下角放置了兩個按鈕。當我們改變應用窗口大小時,它們會相對於應用窗口不改變位置。在這個例子中我們使用了QHBoxLayout和QVBoxLayout兩個布局類。

4.3 網格布局

最常用的布局類是網格布局。這個布局使用行了列分割空間。要創建一個網格布局,我們需要使用QGridLayout類。

# ##***網格布局***## #
class GridLayout(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):

		grid = QGridLayout() # 實例化QGridLayout類
		self.setLayout(grid) # 把QGridLayout類設為應用窗口的布局。

		names = ['Cls', 'Bck', '', 'Close',
				 '7', '8', '9', '/',
				 '4', '5', '6', '*',
				 '1', '2', '3', '-',
				 '0', '.', '=', '+']

		positions = [(i, j) for i in range(5) for j in range(4)]

		for position, name in zip(positions, names):

			if name == '':
				continue
			button = QPushButton(name)
			grid.addWidget(button, *position)

		self.move(300, 150)
		self.setWindowTitle('Calculator')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = GridLayout()
	sys.exit(app.exec_())

 

4.4 文本審閱窗口示例

 

在網格中,組件可以跨多列或多行。在這個例子中,我們對它進行一下說明。

# ##***文本審閱***## #
class TextReview(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		title = QLabel('Title')
		author = QLabel('Author')
		review = QLabel('Review')

		titleEdit = QLineEdit()
		authorEdit = QLineEdit()
		reviewEdit = QTextEdit()

		grid = QGridLayout()
		grid.setSpacing(10) # 創建了一個網格布局並且設置了組件之間的間距。

		grid.addWidget(title, 1, 0)
		grid.addWidget(titleEdit, 1, 1)

		grid.addWidget(author, 2, 0)
		grid.addWidget(authorEdit, 2, 1)

		grid.addWidget(review, 3, 0)
		grid.addWidget(reviewEdit, 3, 1, 5, 1) # 如果我們向網格布局中增加一個組件,我們可以提供組件的跨行
		# 和跨列參數。在這個例子中,我們讓reviewEdit組件跨了5行。

		self.setLayout(grid)

		self.setGeometry(300, 300, 350, 300)
		self.setWindowTitle('Review')
		self.show()
		
		
if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = TextReview()
	sys.exit(app.exec_())

我們創建了包含三個標簽,兩個單行編輯框和一個文本編輯框組件的窗口。布局使用了QGridLayout布局。

5、事件和信號

 

5.1 事件

 

所有的GUI應用都是事件驅動的。事件主要由應用的用戶操作產生的。但是事件可能由其他條件觸發,比如:一個網絡連接,一個窗口管理器,一個定時器,這些動作都可能觸發事件的產生。當我們調用應用的exec_()方法時,應用進入了主循環。主循環用於檢測事件的產生並且將事件送到用於處理的對象中去。

 

在事件模型,有三個參與者:

  • 事件源
  • 事件對象
  • 事件目標

事件源是狀態發生改變的對象。它產生了事件。事件對象(evnet)封裝了事件源中的狀態變化。事件目標是想要被通知的對象。事件源對象代表了處理一個事件直到事件目標做出響應的任務。

PyQt5有一個獨一無二的信號和槽機制來處理事件。信號和槽用於對象之間的通信。當指定事件發生,一個事件信號會被發射。槽可以被任何Python腳本調用。當和槽連接的信號被發射時,槽會被調用。

5.2 信號&槽

 

在我們的例子中,我們顯示了一個QtGui.QLCDNumber和一個QtGui.QSlider類。我們拖動滑塊條的把手,lcd數字會變化。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
							 QVBoxLayout, QApplication)


class EventsSignals(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		lcd = QLCDNumber(self) # 顯示一個LCD數字。
		sld = QSlider(Qt.Horizontal, self) # 提供了一個水平滑動條。

		vbox = QVBoxLayout() 
		vbox.addWidget(lcd)
		vbox.addWidget(sld)

		self.setLayout(vbox)
		sld.valueChanged.connect(lcd.display) # 滑塊條的valueChanged信號和lcd數字顯示的display槽連接在一起。
		#發送者是一個發送了信號的對象。接受者是一個接受了信號的對象。槽是對信號做出反應的方法。

		self.setGeometry(300, 300, 250, 150)
		self.setWindowTitle('Signal & slot')
		self.show()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = EventsSignals()
	sys.exit(app.exec_())

5.3 重寫事件處理函數

 

PyQt中的事件處理通常通過重寫事件處理函數來處理。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QApplication


class Rewrite(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		self.setGeometry(300, 300, 250, 150)
		self.setWindowTitle('Event handler')
		self.show()

	def keyPressEvent(self, e):
		if e.key() == Qt.Key_Escape:
			self.close()


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = Rewrite()
	sys.exit(app.exec_())

在我們的例子中,我們重寫了keyPressEvent()事件處理函數。如果我們點擊了Esc按鈕,應用將會被終止。

5.4 事件發送者

有時需要方便的知道哪一個組件是信號發送者。因此,PyQt5擁有了sender()方法來解決這個問題。

import sys
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication


class EventSender(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		btn1 = QPushButton("Button 1", self)
		btn1.move(30, 50)

		btn2 = QPushButton("Button 2", self)
		btn2.move(150, 50)

		btn1.clicked.connect(self.buttonClicked)
		btn2.clicked.connect(self.buttonClicked)

		self.statusBar()

		self.setGeometry(300, 300, 290, 150)
		self.setWindowTitle('Event sender')
		self.show()

	def buttonClicked(self):
		sender = self.sender()
		self.statusBar().showMessage(sender.text() + ' was pressed')


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = EventSender()
	sys.exit(app.exec_())

在我們的例子中,我們有兩個按鈕。在buttonClikced()方法中,我們調用sender()方法來判斷哪一個按鈕是我們按下的。兩個按鈕都連接到了同一個槽中。

我們調用sender()方法判斷發送信號的信號源是哪一個。然后在應用的狀態欄上顯示被按下的按鈕的標簽內容。

5.5 發送信號

從QObejct生成的對象可以發送信號。在下面的例子中我們將會看到怎樣去發送自定義的信號。

import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication


class Communicate(QObject):
	closeApp = pyqtSignal() # 信號使用了pyqtSignal()方法創建,並且成為外部類Communicate類的屬性。


class SendSignal(QMainWindow):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		self.c = Communicate()
		self.c.closeApp.connect(self.close) # 把自定義的closeApp信號連接到QMainWindow的close()槽上。

		self.setGeometry(300, 300, 290, 150)
		self.setWindowTitle('Emit signal')
		self.show()

	def mousePressEvent(self, event):
		self.c.closeApp.emit() # 當我們在窗口上點擊一下鼠標,closeApp信號會被發射。應用中斷。


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = SendSignal()
	sys.exit(app.exec_())

我們創建一個新的信號叫做closeApp。當觸發鼠標點擊事件時信號會被發射。信號連接到了QMainWindow的close()方法。

 

6、對話框

 

對話框窗口或對話框是大多數主流GUI應用不可缺少的部分。對話是兩個或更多人之間的會話。在計算機應用中,對話框是一個用來和應用對話的窗口。對話框可以用來輸入數據,修改數據,改變應用設置等等。

6.1 輸入對話框

QInputDialog提供了一個簡單便利的對話框用於從用戶那兒獲得只一個值。輸入值可以是字符串,數字,或者一個列表中的列表項。

import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,
							 QInputDialog, QApplication)


class InputDialog(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		self.btn = QPushButton('Dialog', self)
		self.btn.move(20, 20)
		self.btn.clicked.connect(self.showDialog)

		self.le = QLineEdit(self)
		self.le.move(130, 22)

		self.setGeometry(300, 300, 290, 150)
		self.setWindowTitle('Input dialog')
		self.show()

	def showDialog(self):
		# 這一行會顯示一個輸入對話框。第一個字符串參數是對話框的標題,第二個字符串參數是對話框內的消息文本。
		# 對話框返回輸入的文本內容和一個布爾值。如果我們點擊了Ok按鈕,布爾值就是true,反之布爾值是false
		# (也只有按下Ok按鈕時,返回的文本內容才會有值)。
		text, ok = QInputDialog.getText(self, 'Input Dialog',
										'Enter your name:')

		if ok:
			self.le.setText(str(text)) # 把我們從對話框接收到的文本設置到單行編輯框組件上顯示。


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = InputDialog()
	sys.exit(app.exec_())

例子中有一個按鈕和一個單行編輯框組件。按下按鈕會顯示輸入對話框用於獲得一個字符串值。在對話框中輸入的值會在單行編輯框組件中顯示。

6.2 顏色選擇對話框

QColorDialog類提供了一個用於選擇顏色的對話框組件。

import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QFrame,
							 QColorDialog, QApplication)
from PyQt5.QtGui import QColor


class ColorChoose(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		col = QColor(0, 0, 0) # 初始化QtGuiQFrame組件的背景顏色。

		self.btn = QPushButton('Dialog', self)
		self.btn.move(20, 20)

		self.btn.clicked.connect(self.showDialog)

		self.frm = QFrame(self)
		self.frm.setStyleSheet("QWidget { background-color: %s }"
							   % col.name())
		self.frm.setGeometry(130, 22, 100, 100)

		self.setGeometry(300, 300, 250, 180)
		self.setWindowTitle('Color dialog')
		self.show()

	def showDialog(self):
		col = QColorDialog.getColor() # 彈出顏色選擇框。

		if col.isValid():
			# 如果我們選中一個顏色並且點了ok按鈕,會返回一個有效的顏色值。如果我們點擊了Cancel按鈕,
			# 不會返回選中的顏色值。我們使用樣式表來定義背景顏色。
			self.frm.setStyleSheet("QWidget { background-color: %s }"
								   % col.name())


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = ColorDialog()
	sys.exit(app.exec_())

例子中顯示了一個按鈕和一個QFrame。將QFrame組件的背景設置為黑色。使用顏色選擇框類,我們可以改變它的顏色。

6.3 字體選擇框

QFontDialog是一個用於選擇字體的對話框組件。

import sys
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QPushButton,
							 QSizePolicy, QLabel, QFontDialog, QApplication)


class FontChoose(QWidget):
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		vbox = QVBoxLayout()

		btn = QPushButton('Dialog', self)
		btn.setSizePolicy(QSizePolicy.Fixed,
						  QSizePolicy.Fixed)

		btn.move(20, 20)

		vbox.addWidget(btn)

		btn.clicked.connect(self.showDialog)

		self.lbl = QLabel('Knowledge only matters', self)
		self.lbl.move(130, 20)

		vbox.addWidget(self.lbl)
		self.setLayout(vbox)

		self.setGeometry(300, 300, 250, 180)
		self.setWindowTitle('Font dialog')
		self.show()

	def showDialog(self):
		font, ok = QFontDialog.getFont() # 彈出一個字體對話框。getFont()方法返回字體名字和布爾值。
		# 如果用戶點擊了OK,布爾值為True;否則為False。
		if ok:
			self.lbl.setFont(font) # 如果我們點擊了Ok按鈕,標簽字體會被改變。


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = FontChoose()
	sys.exit(app.exec_())

在我們的例子中,我們有一個按鈕和一個表情。通過字體選擇對話框,我們可以改變標簽的字體。

6.4 文件對話框

文件對話框是用於讓用戶選擇文件或目錄的對話框。可以選擇文件的打開和保存。

import sys
from PyQt5.QtWidgets import (QMainWindow, QTextEdit,
							 QAction, QFileDialog, QApplication)
from PyQt5.QtGui import QIcon


class FileDialog(QMainWindow): # 基於QMainWindow組件,因為我們中心需要設置一個文本編輯框組件。
	def __init__(self):
		super().__init__()

		self.initUI()

	def initUI(self):
		self.textEdit = QTextEdit()
		self.setCentralWidget(self.textEdit)
		self.statusBar()

		openFile = QAction(QIcon('open.png'), 'Open', self)
		openFile.setShortcut('Ctrl+O')
		openFile.setStatusTip('Open new File')
		openFile.triggered.connect(self.showDialog)

		menubar = self.menuBar()
		fileMenu = menubar.addMenu('&File')
		fileMenu.addAction(openFile)

		self.setGeometry(300, 300, 350, 300)
		self.setWindowTitle('File dialog')
		self.show()

	def showDialog(self):
		# 彈出文件選擇框。第一個字符串參數是getOpenFileName()方法的標題。第二個字符串參數指定了對話框的工作目錄。
		# 默認的,文件過濾器設置成All files (*)。
		fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')

		# 選中文件后,讀出文件的內容,並設置成文本編輯框組件的顯示文本
		if fname[0]:
			f = open(fname[0], 'r')

			with f:
				data = f.read()
				self.textEdit.setText(data)


if __name__ == '__main__':
	app = QApplication(sys.argv)
	ex = FileDialog()
	sys.exit(app.exec_())

示例中顯示了一個菜單欄,中間設置了一個文本編輯框組件,和一個狀態欄。點擊菜單項會顯示QtGui.QFileDialog(文件選擇框)對話框,用於選擇一個文件。文件的內容會被讀取並在文本編輯框組件中顯示。


免責聲明!

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



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