1. 程式人生 > >利用Python3開發一款小工具 (介面背後的程式碼)

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