用PyQt5重新编写GUI
安装 Anaconda + PyQt5 + Eric6
PyQt5里面包含了一个Designer,可以直接设计窗口的GUI界面,而Eric6则是一个IDE开发环境,可以进行代码的编写与调试,PyQt5+Eric6就是一个不错的GUI开发组合。
Anaconda在课程开始时已经安装了,里面包含了PyQt5,需要再安装一个Eric6即可。
Anaconda官方网址:https://www.continuum.io/
Anaconda下载链接:https://www.continuum.io/downloads
PyQt5下载链接:https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.6/
安装 Eric6
Eric6下载链接:https://sourceforge.net/projects/eric-ide/files/eric6/stable/
选择适合的版本下载。下载后,解压到目录中,然后进入目录,用下面的命令安装:
python install.py install
我的是Windows系统。安装完成后,会在Anaconda安装目录下的Scripts多了一个eric6.bat,进入命令行,直接输入eric6即可看到下面的启动界面,进入开发界面:


- 第一个坑:装了Eric6,不知道怎么运行 找了好大一圈,才知道用pythonw运行eric6.pyw。当时就想:不可能用这么土的方式来运行的,在命令行输入eric6一样可以进入,查找了一下,原来安装的时候已经将eric6.bat放到了Anaconda的Scripts目录,该目录有放入系统的$PATH$,所以可以在任何地方直接运行。
第一个UI界面:
- Step1: 在Eric6中的菜单栏。项目->新建,填写好项目名称和保存目录后,项目类型选择"PyQt5 GUI"。然后在左边新建窗体,如下图:

- Step2: 选择 主窗口:

- Step3: 然后就会直接跳转到QT Designer界面进行窗口的编辑和设计:

Step4: 通过添加组件,就可以完成窗口的设计。关闭Qt Designer后,可以回到Eric6继续进行代码编写。
Step5: 技巧:添加信号 PyQt5可以通过界面操作,添加信号,从而可以使组件间传递信息,形成“事件”。我在界面中定义了两个事件:一个是“清空”按钮可以直接清除文本框的内容,另一个是“退出”按钮,直接退出主窗体:

窗体文件:*.ui
前面用Designer编辑的UI文件,到底是什么内容呢? 用文本编辑软件即可打开,里面是XML的内容,记录的界面里面各个元素的设定。包含了组件的名称、位置等各个属性。

编译窗体
回到Eric6,就可以将刚刚生成的界面文件.ui编译成为.py文件。

默认,系统会编译为Ui-xxx.py,xxx就是刚刚的界面名称。 下一步,重用里面的代码,不要直接改这个文件!不要直接改这个文件!不要直接改这个文件!重要的事情说三遍!
- 第二坑:直接改了界面编译的文件
自己把各个事件写了进去,调试基本完成了,然后,我发现界面需要微调一下,于是去Qt Designer改,接着顺手点“编译窗体”,于是之前写的代码马上给覆盖了。郁闷啊!
正确的步骤是将编译后的界面文件import进来,然后重写事件和属性。
总结
PyQt5的步骤:
- 新建项目
- 新建窗体
- 编译窗体
- import窗体模块,编写自己的事件和属性
- 调试
最后,Eric6的调试功能非常方便,在写代码的过程中就会提示错误,不用每次到运行的时候才发现,低级的拼写错误可以直接解决。 现在才发现Eric这个工具,我不会告诉你们我前面的代码是用notepad写的。。
最后附上代码:
窗体主程序 App_weatherquery.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from Ui_weatherquery import Ui_MainWindow
import datetime
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
city_weather={}
queryHistory=[]
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.getWeatherInfo()
self.clearButton.clicked.connect(self.outputText.clear)
self.helpButton.clicked.connect(self.printHelpInfo)
self.queryButton.clicked.connect(self.getEnter)
self.inputEntry.returnPressed.connect(self.queryAction)
self.historyButton.clicked.connect(self.getHistory)
def getWeatherInfo(self):
'''函数功能:初始化时读入城市天气结果'''
with open ('weather_info.txt', 'r', encoding='utf-8') as f:
for lines in f.readlines():
line=lines.strip().split(',')
self.city_weather[line[0]] = line[1]
def printErrorInfo(self):
'''函数功能:打印错误信息'''
printstr='''你输入的城市名称不存在,或者指令错误,请重新输入。
- 如果不清楚指令,可以输入?或者help, 或点击"帮助"按钮,获取帮助。
\n'''
print(printstr)
self.outputText.append(printstr)
def getEnter(self,event):
'''函数功能:输入框按下回车触发查询动作'''
self.queryAction()
self.inputEntry.setFocus()
def printHelpInfo(self):
'''函数功能:打印帮助信息'''
helpstr='''
- 输入城市名,获取该城市的天气情况;
- 输入 ?/help,获取本帮助信息;
- 输入 h/history,获取历史查询信息;
- 输入 q/quit,退出天气查询系统。'''
#console打印输出
print (helpstr)
#窗口显示结果
self.outputText.append(helpstr+'\n')
def getHistory(self):
'''函数功能:打印历史查询信息,输出查询序号、时间和结果
调用格式:getHistory(history)
需要输入历史查询记录'''
history=self.queryHistory
if history:
print ()
print ('你查询过以下城市的天气情况:')
self.outputText.append('\n你查询过以下城市的天气情况:\n')
for i in range(history.__len__()):
printstr=str(i+1)+' '+history[i]
print (printstr)
#窗口显示结果
self.outputText.append(printstr)
else:
print ('并无查询历史记录')
self.outputText.append('并无查询历史记录\n')
def printWeatherInfo(self,city,history):
'''函数功能:打印对应的城市天气查询记录'''
print (city, self.city_weather[city])
self.outputText.append(city + ' 的天气情况为:' + self.city_weather[city] )
#获得当前时间
now = datetime.datetime.now()
#转换为指定的格式:
dt = now.strftime("%Y-%m-%d %H:%M:%S")
historystr=dt + ' ' + city + ' 的天气情况为:' + self.city_weather[city]
history.append(historystr)
return history
def queryAction(self):
'''函数功能:根据输入框内容进行判断,执行对应的指令或查询城市天气'''
user_input=self.inputEntry.text().lower()
if user_input=="help" or user_input=="?":
self.printHelpInfo()
self.inputEntry.clear()
elif user_input=="h" or user_input=="history":
self.getHistory()
self.inputEntry.clear()
elif user_input in self.city_weather:
self.queryHistory=self.printWeatherInfo(user_input,self.queryHistory)
self.inputEntry.clear()
elif user_input=="q" or user_input=="quit":
self.quitApp()
else:
errorstr='\n你刚刚输入的 "'+user_input+ '" 有误:\n'
print (errorstr)
self.outputText.append(errorstr)
self.printErrorInfo()
self.inputEntry.clear()
self.inputEntry.setFocus()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = MainWindow()
ui.show()
sys.exit(app.exec_())
窗体编译模块 Ui_weatherquery.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'G:\Eric6-Projects\QtGui\weatherquery.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(513, 333)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.outputLabel = QtWidgets.QLabel(self.centralWidget)
self.outputLabel.setGeometry(QtCore.QRect(20, 120, 61, 16))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(10)
self.outputLabel.setFont(font)
self.outputLabel.setObjectName("outputLabel")
self.inputLabel = QtWidgets.QLabel(self.centralWidget)
self.inputLabel.setGeometry(QtCore.QRect(10, 20, 171, 16))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(10)
self.inputLabel.setFont(font)
self.inputLabel.setObjectName("inputLabel")
self.inputEntry = QtWidgets.QLineEdit(self.centralWidget)
self.inputEntry.setGeometry(QtCore.QRect(200, 19, 71, 20))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(10)
self.inputEntry.setFont(font)
self.inputEntry.setObjectName("inputEntry")
self.outputText = QtWidgets.QTextEdit(self.centralWidget)
self.outputText.setGeometry(QtCore.QRect(90, 50, 421, 231))
self.outputText.setObjectName("outputText")
self.queryButton = QtWidgets.QPushButton(self.centralWidget)
self.queryButton.setGeometry(QtCore.QRect(298, 17, 75, 23))
self.queryButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.queryButton.setObjectName("queryButton")
self.clearButton = QtWidgets.QPushButton(self.centralWidget)
self.clearButton.setGeometry(QtCore.QRect(10, 150, 71, 23))
self.clearButton.setObjectName("clearButton")
self.helpButton = QtWidgets.QPushButton(self.centralWidget)
self.helpButton.setGeometry(QtCore.QRect(90, 290, 75, 23))
self.helpButton.setObjectName("helpButton")
self.quitButton = QtWidgets.QPushButton(self.centralWidget)
self.quitButton.setGeometry(QtCore.QRect(370, 290, 75, 23))
self.quitButton.setObjectName("quitButton")
self.historyButton = QtWidgets.QPushButton(self.centralWidget)
self.historyButton.setGeometry(QtCore.QRect(230, 290, 75, 23))
self.historyButton.setObjectName("historyButton")
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
self.clearButton.clicked.connect(self.outputText.clear)
self.quitButton.clicked.connect(MainWindow.close)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.outputText.setText("in ui")
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.outputLabel.setText(_translate("MainWindow", "查询结果"))
self.inputLabel.setText(_translate("MainWindow", "请输入指令或需查天气的城市"))
self.inputEntry.setText(_translate("MainWindow", "广州"))
self.queryButton.setText(_translate("MainWindow", "查询"))
self.clearButton.setText(_translate("MainWindow", "清空"))
self.helpButton.setText(_translate("MainWindow", "帮助"))
self.quitButton.setText(_translate("MainWindow", "退出"))
self.historyButton.setText(_translate("MainWindow", "查询历史"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
窗体设计文件 weatherquery.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>513</width>
<height>333</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QLabel" name="outputLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>120</y>
<width>61</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>查询结果</string>
</property>
</widget>
<widget class="QLabel" name="inputLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>171</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>请输入指令或需查天气的城市</string>
</property>
</widget>
<widget class="QLineEdit" name="inputEntry">
<property name="geometry">
<rect>
<x>200</x>
<y>19</y>
<width>71</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>广州</string>
</property>
</widget>
<widget class="QTextEdit" name="outputText">
<property name="geometry">
<rect>
<x>90</x>
<y>50</y>
<width>421</width>
<height>231</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="queryButton">
<property name="geometry">
<rect>
<x>298</x>
<y>17</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="cursor">
<cursorShape>ArrowCursor</cursorShape>
</property>
<property name="text">
<string>查询</string>
</property>
</widget>
<widget class="QPushButton" name="clearButton">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>71</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>清空</string>
</property>
</widget>
<widget class="QPushButton" name="helpButton">
<property name="geometry">
<rect>
<x>90</x>
<y>290</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>帮助</string>
</property>
</widget>
<widget class="QPushButton" name="quitButton">
<property name="geometry">
<rect>
<x>370</x>
<y>290</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>退出</string>
</property>
</widget>
<widget class="QPushButton" name="historyButton">
<property name="geometry">
<rect>
<x>230</x>
<y>290</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>查询历史</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>clearButton</sender>
<signal>clicked()</signal>
<receiver>outputText</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>44</x>
<y>157</y>
</hint>
<hint type="destinationlabel">
<x>118</x>
<y>160</y>
</hint>
</hints>
</connection>
<connection>
<sender>quitButton</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>435</x>
<y>300</y>
</hint>
<hint type="destinationlabel">
<x>471</x>
<y>304</y>
</hint>
</hints>
</connection>
</connections>
</ui>