利用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
....