用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的步骤:

  1. 新建项目
  2. 新建窗体
  3. 编译窗体
  4. import窗体模块,编写自己的事件和属性
  5. 调试

最后,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>

results matching ""

    No results matching ""