1. 程式人生 > >PyQt——結合Python與Qt的GUI程式設計

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_paint.png

2D繪圖

dialog.png

對話方塊演示

ftp.png

FTP客戶端(網路程式設計)演示

openGL.png

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_hello.png

PyQt程式執行效果

從上面的例子可以看出手動編寫程式碼呼叫PyQt依然十分不便,好在PyQt還為我們準備了Qt GUI介面的轉換工具,可以將Qt Creator生成的.ui檔案直接轉換成Python程式碼。比如需要對test.ui進行轉換,其命令如下:

$ pyuic4 test.ui -x -o test.py

其中-x引數相當於--execute,在程式碼中增加了一些測試語句,這樣生成的Python檔案就可以直接執行了。之後我們就可以在生成的程式碼基礎上實現自己的功能。

pyqt_widgets.png

在Python借用Qt強大的圖形控制元件

1.2.例:通過PyQt設計CPU溫度監控軟體

這裡我們將通過PyQt設計一個監控樹莓派核心溫度的小軟體。首先開啟QtCreator,新建一個Qt GUI應用程式工程(如何在樹莓派2本地安裝執行Qt Creator,請參見:程式設計篇(一)在樹莓派2上本地開發Qt GUI程式)。設計如下圖所示的視窗介面:

pyqt_gui.png

在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溫度接近門限值,則會改變溫度顯示的顏色。如果超過門限值則彈出對話方塊報警。

pyqt_temp_alarm.png

溫度監控程式執行效果

這裡我們還可以使用一個小程式將CPU佔用率提高到100%來提升CPU溫度,只要編寫一段死迴圈的運算程式碼即可(一個Python程序只能在單個核心上執行,對於樹莓派2,需要同時啟動4個程序才能跑滿全部核心)。程式碼內容如下:

while True:

    a = 1298/1412

多程序後臺執行:

$ python tst.py&

$ python tst.py&

$ python tst.py&

$ python tst.py&

pyqt_temp_heat.png

提高CPU佔用率