利用Python3开发一款小工具 (界面背后的代码)
界面设计参照上一篇博客(https://blog.csdn.net/hitguolu/article/details/82620681),
前文已经写到,只有界面没有后台的程序,界面是没有用的。本篇将对界面背后的代码进行介绍,辛辛苦苦在后面执行,今天终于露脸了,话不多说,我们开始了。
前文讲到,用pyUIC可以将ui界面转换成py文件,py文件中其实就是生成一个类,类名为UI_MainWindows,该类包含两个方法,setupUi和retranslateUi。一般来说,我们不会直接用这个类的,在这里我们会新定义一个类,这个类我们会参照UI_MainWindowsd类。
class UI_AutoCodeCheck(QtWidgets.QMainWindows):
logSignal = QtCore.pyqtSignal(str)
def __init__(self):
...
def retranslateUi(self):
...
1、界面中的控件
下图就是我们用的所有控件,
包括了GroupBox、PushButton、Label、LineEdit、ComboBox、Checkbox、TextBrowser、PlainTextEdit等。
- LineEdit
我们常用来做参数的输入 - GroupBox
就是个面板,控件常常用于逻辑地组合一组控件,如RadioButton 及 CheckBox控件,显示一个框架,其上有一个标题 - PushBotton
可以理解为一个按钮 - ComboBox
是下拉框控件 - CheckBox
多选框控件,要结合GroupBox使用 - TextBrowser是文字显示
- PlainTextEdit
是可以编辑的文本
2、如何给一个控件添加事件响应
我们分别给控件添加事件响应
-LineEdit
想想,我们在界面输入的文字是怎么传递到程序中的呢?排除法,肯定不是自己跑进去的。在pyqt中,我们需要这样做:
1)给控件添加connect函数
self.LinuxServerIP.textChanged.connect(self.configureEdited)
从该语句其实就可以知道,只要LinuxServerIP这个输入框发生了变化,就会触发执行configureEdited函数,要想保存该参数,就要在connect函数中添加处理代码
2)connect函数中读取界面中的内容
serverIp = self.LinuxServerIP.text()
该语句就是用来获取LineEdit中的字符的,需要注意的时,如果我们输入的是数字,需要讲字符串转换成我们需要的格式。
不过,我们通常不会再connect函数中直接保存,因为你在输入的第一个字符开始,每输入一个字符,都会进入connect函数中,这个不是我们想要的。
因此我在这里的处理,通常用这个configureEdited函数校验参数是否已经满足运行的要求,然后控制START按钮是否允许被用户点击。这个在后面界面的约束进行介绍。
– 浏览按钮的实现
self.BrowseFileButton.clicked.connect(self.fileBrowsePressed)
def fileBrowsePressed(self):
self.dirSelector = QtWidgets.QFileDialog()
self.dirSelector.setGeometry(QtCore.QRect(20, 0, 651, 441))
browsedir = (os.getcwd() if self.LocalRepoDir.text() == '' else self
.LocalRepoDir.text())
dir = self.dirSelector.getExistingDirectory(
self.centralwidget, "Select Directory", browsedir,
QtWidgets.QFileDialog.ShowDirsOnly |
QtWidgets.QFileDialog.DontResolveSymlinks)
self.LocalRepoDir.setText(browsedir if dir == '' else dir)
– comboBox
self.StationTypeComboBox.currentIndexChanged.connect(self.stationTypeComboBoxChange)
这段代码用于感知下拉框状态的改变,如果想知道下拉框选择的选项,可以使用两种,
#此函数可以获取当前选择的下拉框中的字符串
self.StationTypeComboBox.currentText()
#此函数可以获取当前下拉框的索引,如0,1,2,3
self.StationTypeComboBox.currentIndex()
– checkBox
在我们的界面中,有一组多选框,多选框状态的获取可以使用如下方法:
self.LinuxCompileReleaseBin.stateChanged.connect(self.LinuxCompileReleaseBinSwitchChanged)
判断当前状态是否是选中状态
def LinuxCompileReleaseBinSwitchChanged(self, state)
if state == QtCore.Qt.Checked:
pass
如果想让程序选中或者取消选中复选框,则可以
self.LinuxCompileReleaseBin.setCheckState(QtCore.Qt.Unchecked)#取消选中
self.LinuxCompileReleaseBin.setCheckState(QtCore.Qt.Checked)#选中
– 鼠标响应事件
之所以要有这个事件,是因为我希望实现一个功能,就是在RunningLogs窗口双击鼠标,可以弹出一个messageBox,然后选择是否要跳转到详细日志保存目录及版本包存放目录。因此,我给重写了TextBrowser类。
class MyTextBrowser(QtWidgets.QTextBrowser):
def __init__(self, parent=None):
super(MyTextBrowser, self).__init__(parent)
# 双击鼠标事件响应
def mouseDoubleClickEvent(self, event):
msg = QtWidgets.QMessageBox.information(self,
"Rungging logs",
"是否查看详细日志\n",
QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.NO,
QtWidgets.QMessageBox.Yes)
if QtWidgets.QMessageBox.Yes == msg:
start_directory = os.getcwd()
cmd = "explorer.exe " + start_directory
try:
run(cmd, shell = True)
# 调用了subprocesss的run函数,执行explorer打开本地目录
except Exception as err:
print(err)
... #后续异常处理
于是,在定义TextBrowser时,就用了MyTextBrower类定义,这就赋予了RunningLogs控件有了鼠标双击事件响应
self.textBrowser = MyTextBrowser(self.RunningLogs)
3、界面的约束
根据我们的需求,对界面提出了一下两点约束:
1、用户配置信息不完善时,不允许‘START’按钮被按下,而且多选框按钮必须选择一个才能允许点击’START’按钮
2、站型切换时,要把所有的checkBox设置为未选中状态
- 约束1的实现
需求:Linux服务器地址2个、远程目录、本地目录、用户名、密码必须全都要配置
首先给LinuxServerIP1、remoteDir、LocalReportDir、username、password、LinuxServerIP2加上connect函数,改变这些值,就会触发我们的校验函数
self.LinuxServerIP1.textChanged.connect(self.configureEdited)
self.LinuxServerIP2.textChanged.connect(self.configureEdited)
self.LinuxRemoteDir.textChanged.connect(self.configureEdited)
self.LocalRepoDir.textChanged.connect(self.configureEdited)
self.PassWord.textChanged.connect(self.configureEdited)
self.UserName.textChanged.connect(self.configureEdited)
def configureEdited(self):
LinuxServerIP1 = self.LinuxServerIP1.text()
RemoteDir = self.LinuxRemoteDir.text()
LocalRepoDir = self.LocalRepoDir.text()
username = self.UserName.text()
password = self.PassWord.text()
LinuxServerIP2= self.LinuxServerIP2.text()
#变量名做了模糊处理,正常编码时,尽量避免这种命名方法
if (LinuxServerIP1 != '' and RemoteDir != '' and
LocalRepoDir != '' and username != '' and
password != '' and LinuxServerIP2 != ''):
# ischeckSettingComplete函数是用来判断checkbox是否至少有一个被选中的
if self.isCheckSettingComplete() == False:
self.StartButton.setEnabled(False)
else:
self.StartButton.setEnabled(True)
- 约束2的实现
需求:站型在A和B之间切换时,要清空所有的脚本执行多选框
1、首先给ComboBox加入connect函数
self.StationTypeComboBox.currentIndexChanged.connect(self.stationTypeComboBoxChange)
2、编写connect函数
def stationTypeComboBoxChange(self):
self.LinuxCompileReleaseBin.setCheckState(QtCore.Qt.Unchecked)#取消选中
self.LinuxCompileDebugBin.setCheckState(QtCore.Qt.Unchecked)
self.LinuxCompileX86DebugBin.setCheckState(QtCore.Qt.Unchecked)
self.LinuxFtBin.setCheckState(QtCore.Qt.Unchecked)
4、信号量的用处
这里简单介绍一下,后面会专门对信号量进行讲解。
我们在这里,使用了信号量用于日志的输出,信号量的定义如下
logSignal = QtCore.pyqtSignal(str)
# 这个str就是我们需要打印出的日志
以上只是信号量的定义,如何将信号量和写日志联系起来,可以想一想。
其实,我们还是用的connect函数。
self.logSignal.connect(self.LogParsingShow)
我们只需要定义一下logParsingShow函数即可
def logParsingShow(self, log_info):
# 插入了日志的时间
self.textBrowser.insertPlainText(str(dateTime.datetime.now().strftime('%H:%M:%S')))
self.textBrowser.insetPlainText(' ')
self.textBrowser.insetPlainText(log_info)
# 实现进度条的自动滚动,能够保证看到的是最新的日志
self.textBrowser.moveCursor(QtGui.QTextCursor.End)
使用的时候
self.logSignal.emit("Connected to server 192.168.53.238\n")
这样,日志就输出到了textBrower上。
效果就是这样:
10:25:03 Connected to server 192.168.53.238
10:25:04 upload modified files completely
10:25:05 Exec rrc_bin_x86_release_debug.sh success
....