PyQt——結合Python與Qt的GUI程式設計
http://www.eefocus.com/nightseas/blog/15-05/312675_3e518.html
PyQt是Python下的另一套圖形介面介面庫,顧名思義就是在Python中呼叫Qt圖形庫和元件。使用PyQt的優點在於可以使用Qt成熟的IDE(如Qt Creator)進行圖形介面設計,並自動生成可執行的Python程式碼。
1.1.PyQt的安裝和使用
PyQt可以通過apt-get命令安裝,其對應Python 2.x 和Python 3.x的包名稱不同。
安裝Python 2.x下的PyQt:
$ sudo apt-get install python-pyqt4 pyqt4-dev-tools
安裝Python 3.x下的PyQt:
$ sudo apt-get install python3-pyqt4 pyqt4-dev-tools
獲取PyQt的文件和範例程式(非必須):
$ sudo apt-get install python-qt4-doc
獲取到的範例程式儲存在/usr/share/doc/python-qt4-doc/examples目錄下找到。
2D繪圖
對話方塊演示
FTP客戶端(網路程式設計)演示
OpenGL 3D繪圖
下面我們通過一段程式碼演示PyQt的使用。新建Python檔案,命名為hello_pyqt.py,程式碼內容如下:
import sys
from PyQt4 import QtCore, QtGui
class HelloPyQt(QtGui.QWidget):
def __init__(self, parent = None):
super(HelloPyQt, self).__init__(parent)
self.setWindowTitle("PyQt Test")
self.textHello = QtGui.QTextEdit("This is a test program written in python with PyQt lib!")
self.btnPress = QtGui.QPushButton("Press me!")
layout = QtGui.QVBoxLayout()
layout.addWidget(self.textHello)
layout.addWidget(self.btnPress)
self.setLayout(layout)
self.btnPress.clicked.connect(self.btnPress_Clicked)
def btnPress_Clicked(self):
self.textHello.setText("Hello PyQt!\nThe button has been pressed.")
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
mainWindow = HelloPyQt()
mainWindow.show()
sys.exit(app.exec_())
在本例中,所有的PyQt控制元件都封裝在HelloPyQt類中。首先添加了一個QTextEdit 控制元件textHello和QPushButton控制元件btnPress,然後通過self.btnPress.clicked.connect()語句將btnPress按鈕的clicked訊號連線至btnPress_Clicked()函式。
如此當按鈕被按下時,會觸發clicked事件,進而呼叫btnPress_Clicked()函式。該函式的功能就是改變textHello中的文字。
在Python3下執行程式:
$ python3 hello_pyqt.py
PyQt程式執行效果
從上面的例子可以看出手動編寫程式碼呼叫PyQt依然十分不便,好在PyQt還為我們準備了Qt GUI介面的轉換工具,可以將Qt Creator生成的.ui檔案直接轉換成Python程式碼。比如需要對test.ui進行轉換,其命令如下:
$ pyuic4 test.ui -x -o test.py
其中-x引數相當於--execute,在程式碼中增加了一些測試語句,這樣生成的Python檔案就可以直接執行了。之後我們就可以在生成的程式碼基礎上實現自己的功能。
在Python借用Qt強大的圖形控制元件
1.2.例:通過PyQt設計CPU溫度監控軟體
這裡我們將通過PyQt設計一個監控樹莓派核心溫度的小軟體。首先開啟QtCreator,新建一個Qt GUI應用程式工程(如何在樹莓派2本地安裝執行Qt Creator,請參見:程式設計篇(一)在樹莓派2上本地開發Qt GUI程式)。設計如下圖所示的視窗介面:
在Qt Creator中設計GUI
通過pyuic命令將GUI檔案轉換成Python檔案,然後在此基礎上進行修改,程式碼如下:
from PyQt4 import QtCore, QtGui
import os
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_HelloPyQt(object):
def setupUi(self, HelloPyQt):
HelloPyQt.setObjectName(_fromUtf8("HelloPyQt"))
HelloPyQt.resize(304, 212)
self.centralWidget = QtGui.QWidget(HelloPyQt)
self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
self.lcdTemp = QtGui.QLCDNumber(self.centralWidget)
self.lcdTemp.setGeometry(QtCore.QRect(40, 40, 221, 81))
self.lcdTemp.setSmallDecimalPoint(False)
self.lcdTemp.setDigitCount(6)
self.lcdTemp.setObjectName(_fromUtf8("lcdTemp"))
self.sliderAlarm = QtGui.QSlider(self.centralWidget)
self.sliderAlarm.setGeometry(QtCore.QRect(40, 170, 221, 16))
self.sliderAlarm.setMaximum(120)
self.sliderAlarm.setProperty("value", 80)
self.sliderAlarm.setOrientation(QtCore.Qt.Horizontal)
self.sliderAlarm.setTickPosition(QtGui.QSlider.NoTicks)
self.sliderAlarm.setObjectName(_fromUtf8("sliderAlarm"))
self.labelAlarm = QtGui.QLabel(self.centralWidget)
self.labelAlarm.setGeometry(QtCore.QRect(40, 150, 221, 16))
self.labelAlarm.setObjectName(_fromUtf8("labelAlarm"))
self.labelTemp = QtGui.QLabel(self.centralWidget)
self.labelTemp.setGeometry(QtCore.QRect(40, 20, 221, 16))
self.labelTemp.setObjectName(_fromUtf8("labelTemp"))
#Add timer
self.timerTemp = QtCore.QTimer(self.centralWidget)
HelloPyQt.setCentralWidget(self.centralWidget)
# Add slots
self.sliderAlarm.valueChanged.connect(self.sliderAlarm_ValueChanged)
self.timerTemp.timeout.connect(self.timerTemp_TimeOut)
# Use the timeout event to initialize the LCD
self.timerTemp_TimeOut()
# Start timer, time out per 2 seconds
self.timerTemp.start(2000)
self.retranslateUi(HelloPyQt)
QtCore.QMetaObject.connectSlotsByName(HelloPyQt)
def retranslateUi(self, HelloPyQt):
HelloPyQt.setWindowTitle(QtGui.QApplication.translate("HelloPyQt", "HelloPyQt", None, QtGui.QApplication.UnicodeUTF8))
self.labelAlarm.setText(QtGui.QApplication.translate("HelloPyQt", "Alarm: 80C", None, QtGui.QApplication.UnicodeUTF8))
self.labelTemp.setText(QtGui.QApplication.translate("HelloPyQt", "CPU Temperature", None, QtGui.QApplication.UnicodeUTF8))
# Event triggered when the value of labelAlarm changed
def sliderAlarm_ValueChanged(self):
self.labelAlarm.setText("Alarm: " + str(self.sliderAlarm.value()) + "C")
# Event triggered when timerTemp time out
def timerTemp_TimeOut(self):
# Get temperature from sensor file
sensor = os.popen("cat /sys/class/thermal/thermal_zone0/temp")
temp = float(sensor.readline()) / 1000
alarm = float(self.sliderAlarm.value())
# Display temperature
self.lcdTemp.display("%.1fC" % temp)
# Check whether the temperature is too high
if temp <= alarm * 0.6:
self.lcdTemp.setStyleSheet("color: green")
elif temp <= alarm * 0.8:
self.lcdTemp.setStyleSheet("color: orange")
elif temp <= alarm:
self.lcdTemp.setStyleSheet("color: red")
else:
self.lcdTemp.setStyleSheet("color: red")
msg = QtGui.QMessageBox()
msg.setWindowTitle("Alarm")
msg.setText("Temperature is too high!")
msg.setIcon(QtGui.QMessageBox.Warning)
msg.exec_()
# You can do something else here, like shut down the system
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
HelloPyQt = QtGui.QMainWindow()
ui = Ui_HelloPyQt()
ui.setupUi(HelloPyQt)
HelloPyQt.show()
sys.exit(app.exec_())
程式碼中新建了一個QTimer定時器控制元件,用於定時查詢CPU當前的溫度並更新顯示。self.timerTemp.timeout.connect()語句將定時器的超時訊號連結至timerTemp_TimeOut()函式。self.timerTemp.start(2000)設定定時器超時時間為200ms,即每2秒執行一次timerTemp_TimeOut()函式。
LCD控制元件用於顯示CPU當前的溫度。在顯示介面和執行定時器之前,可以通過手動呼叫self.timerTemp_TimeOut()函式讀取CPU溫度來初始化LCD控制元件內容。
CPU的溫度通過讀取 /sys/class/thermal/thermal_zone0/temp檔案內容獲得。這裡採用os.popen()方法在Linux Shell中通過cat命令讀取檔案,並將返回的字串資訊轉換為數字顯示在LCD控制元件中。
視窗下面的滾動條用於設定溫度報警門限,如果CPU溫度接近門限值,則會改變溫度顯示的顏色。如果超過門限值則彈出對話方塊報警。
溫度監控程式執行效果
這裡我們還可以使用一個小程式將CPU佔用率提高到100%來提升CPU溫度,只要編寫一段死迴圈的運算程式碼即可(一個Python程序只能在單個核心上執行,對於樹莓派2,需要同時啟動4個程序才能跑滿全部核心)。程式碼內容如下:
while True:
a = 1298/1412
多程序後臺執行:
$ python tst.py&
$ python tst.py&
$ python tst.py&
$ python tst.py&
提高CPU佔用率