查看: 8431|回复: 6

【懒兔子玩树莓】PyQt——结合Python与Qt的GUI编程

[复制链接]
  • TA的每日心情
    无聊
    2015-8-17 09:38
  • 签到天数: 361 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-5-21 15:26:42 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 懒兔子 于 2015-5-21 15:38 编辑

    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:

    1. $ sudo apt-get install python-pyqt4 pyqt4-dev-tools
    复制代码

    安装Python 3.x下的PyQt:

    1. $ sudo apt-get install python3-pyqt4 pyqt4-dev-tools
    复制代码

    获取PyQt的文档和范例程序(非必须):

    1. $ sudo apt-get install python-qt4-doc
    复制代码

    获取到的范例程序保存在/usr/share/doc/python-qt4-doc/examples目录下找到。

    2D绘图


    对话框演示


    FTP客户端(网络编程)演示


    OpenGL 3D绘图



    下面我们通过一段代码演示PyQt的使用。新建Python文件,命名为hello_pyqt.py,代码内容如下:

    1. import sys
    2. from PyQt4 import QtCore, QtGui

    3. class HelloPyQt(QtGui.QWidget):
    4.     def __init__(self, parent = None):
    5.         super(HelloPyQt, self).__init__(parent)
    6.         self.setWindowTitle("PyQt Test")
    7.         
    8.         self.textHello = QtGui.QTextEdit("This is a test program written in python with PyQt lib!")
    9.         self.btnPress = QtGui.QPushButton("Press me!")
    10.         
    11.         layout = QtGui.QVBoxLayout()
    12.         layout.addWidget(self.textHello)
    13.         layout.addWidget(self.btnPress)   
    14.         self.setLayout(layout)

    15.         self.btnPress.clicked.connect(self.btnPress_Clicked)
    16.         
    17.     def btnPress_Clicked(self):
    18.         self.textHello.setText("Hello PyQt!\nThe button has been pressed.")

    19. if __name__=='__main__':
    20.     app = QtGui.QApplication(sys.argv)
    21.     mainWindow = HelloPyQt()
    22.     mainWindow.show()
    23.     sys.exit(app.exec_())
    复制代码

    在本例中,所有的PyQt控件都封装在HelloPyQt类中。首先添加了一个QTextEdit 控件textHello和QPushButton控件btnPress,然后通过self.btnPress.clicked.connect()语句将btnPress按钮的clicked信号连接至btnPress_Clicked()函数。

    如此当按钮被按下时,会触发clicked事件,进而调用btnPress_Clicked()函数。该函数的功能就是改变textHello中的文本。

    在Python3下运行程序:

    1. $ 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文件,然后在此基础上进行修改,代码如下:

    1. from PyQt4 import QtCore, QtGui
    2. import os

    3. try:
    4.     _fromUtf8 = QtCore.QString.fromUtf8
    5. except AttributeError:
    6.     _fromUtf8 = lambda s: s

    7. class Ui_HelloPyQt(object):
    8.     def setupUi(self, HelloPyQt):
    9.         HelloPyQt.setObjectName(_fromUtf8("HelloPyQt"))
    10.         HelloPyQt.resize(304, 212)
    11.         self.centralWidget = QtGui.QWidget(HelloPyQt)
    12.         self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
    13.         self.lcdTemp = QtGui.QLCDNumber(self.centralWidget)
    14.         self.lcdTemp.setGeometry(QtCore.QRect(40, 40, 221, 81))
    15.         self.lcdTemp.setSmallDecimalPoint(False)
    16.         self.lcdTemp.setDigitCount(6)
    17.         self.lcdTemp.setObjectName(_fromUtf8("lcdTemp"))
    18.         self.sliderAlarm = QtGui.QSlider(self.centralWidget)
    19.         self.sliderAlarm.setGeometry(QtCore.QRect(40, 170, 221, 16))
    20.         self.sliderAlarm.setMaximum(120)
    21.         self.sliderAlarm.setProperty("value", 80)
    22.         self.sliderAlarm.setOrientation(QtCore.Qt.Horizontal)
    23.         self.sliderAlarm.setTickPosition(QtGui.QSlider.NoTicks)
    24.         self.sliderAlarm.setObjectName(_fromUtf8("sliderAlarm"))
    25.         self.labelAlarm = QtGui.QLabel(self.centralWidget)
    26.         self.labelAlarm.setGeometry(QtCore.QRect(40, 150, 221, 16))
    27.         self.labelAlarm.setObjectName(_fromUtf8("labelAlarm"))
    28.         self.labelTemp = QtGui.QLabel(self.centralWidget)
    29.         self.labelTemp.setGeometry(QtCore.QRect(40, 20, 221, 16))
    30.         self.labelTemp.setObjectName(_fromUtf8("labelTemp"))
    31.         
    32.         #Add timer
    33.         self.timerTemp = QtCore.QTimer(self.centralWidget)        
    34.         HelloPyQt.setCentralWidget(self.centralWidget)        
    35.         
    36.         # Add slots
    37.         self.sliderAlarm.valueChanged.connect(self.sliderAlarm_ValueChanged)
    38.         self.timerTemp.timeout.connect(self.timerTemp_TimeOut)
    39.         # Use the timeout event to initialize the LCD
    40.         self.timerTemp_TimeOut()
    41.         # Start timer, time out per 2 seconds
    42.         self.timerTemp.start(2000)
    43.         
    44.         
    45.         self.retranslateUi(HelloPyQt)
    46.         QtCore.QMetaObject.connectSlotsByName(HelloPyQt)       
    47.                         

    48.     def retranslateUi(self, HelloPyQt):
    49.         HelloPyQt.setWindowTitle(QtGui.QApplication.translate("HelloPyQt", "HelloPyQt", None, QtGui.QApplication.UnicodeUTF8))
    50.         self.labelAlarm.setText(QtGui.QApplication.translate("HelloPyQt", "Alarm: 80C", None, QtGui.QApplication.UnicodeUTF8))
    51.         self.labelTemp.setText(QtGui.QApplication.translate("HelloPyQt", "CPU Temperature", None, QtGui.QApplication.UnicodeUTF8))

    52.     # Event triggered when the value of labelAlarm changed
    53.     def sliderAlarm_ValueChanged(self):
    54.         self.labelAlarm.setText("Alarm: " + str(self.sliderAlarm.value()) + "C")
    55.         
    56.     # Event triggered when timerTemp time out
    57.     def timerTemp_TimeOut(self):
    58.         # Get temperature from sensor file
    59.         sensor = os.popen("cat /sys/class/thermal/thermal_zone0/temp")
    60.         temp = float(sensor.readline()) / 1000
    61.         alarm = float(self.sliderAlarm.value())
    62.         # Display temperature
    63.         self.lcdTemp.display("%.1fC" % temp)
    64.         # Check whether the temperature is too high
    65.         if temp <= alarm * 0.6:
    66.             self.lcdTemp.setStyleSheet("color: green")
    67.         elif temp <= alarm * 0.8:
    68.             self.lcdTemp.setStyleSheet("color: orange")
    69.         elif temp <= alarm:
    70.             self.lcdTemp.setStyleSheet("color: red")
    71.         else:
    72.             self.lcdTemp.setStyleSheet("color: red")
    73.             msg = QtGui.QMessageBox()
    74.             msg.setWindowTitle("Alarm")
    75.             msg.setText("Temperature is too high!")
    76.             msg.setIcon(QtGui.QMessageBox.Warning)
    77.             msg.exec_()
    78.             # You can do something else here, like shut down the system
    79.             
    80. if __name__ == "__main__":
    81.     import sys
    82.     app = QtGui.QApplication(sys.argv)
    83.     HelloPyQt = QtGui.QMainWindow()
    84.     ui = Ui_HelloPyQt()
    85.     ui.setupUi(HelloPyQt)
    86.     HelloPyQt.show()
    87. 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个进程才能跑满全部内核)。代码内容如下:

    1. while True:
    2.     a = 1298/1412
    复制代码

    多进程后台执行:

    1. $ python tst.py&
    2. $ python tst.py&
    3. $ python tst.py&
    4. $ python tst.py&
    复制代码

    提高CPU占用率


    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2015-8-17 09:38
  • 签到天数: 361 天

    连续签到: 1 天

    [LV.8]以坛为家I

     楼主| 发表于 2015-5-21 15:34:41 | 显示全部楼层
    本帖最后由 懒兔子 于 2015-5-21 15:39 编辑

    为啥Code全都乱码了,害我重贴一遍……
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    擦汗
    2016-5-9 12:20
  • 签到天数: 350 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-5-21 16:39:29 | 显示全部楼层
    楼主写的都是好文啊!支持。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2022-6-22 23:57
  • 签到天数: 943 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-5-21 16:51:43 | 显示全部楼层
    楼主写的很好
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-7-2 14:08
  • 签到天数: 99 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2015-8-5 13:56:27 | 显示全部楼层
    楼主写的很好 好东西,学习一下
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2022-11-7 10:36
  • 签到天数: 898 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-8-10 08:36:18 | 显示全部楼层
    这个东西真是不错
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-7-25 22:49
  • 签到天数: 385 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-8-14 12:16:26 | 显示全部楼层
    Python这几年很火哦。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-29 06:23 , Processed in 0.172091 second(s), 26 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.