最近通過 PyQt5 設(shè)計了一個下載服務(wù)器指定日期日志文件的程序,里面有些有意思的技術(shù)點,現(xiàn)在做一些分享。
PyQt5 是一套 綁定 Digia Qt5 應(yīng)用的框架,是最強大的 GUI 庫之一,使用 PyQt5 我們能夠很容易的開發(fā)桌面應(yīng)用,接下來我們將用它來開發(fā)一個下載服務(wù)器日志文件的小程序。
前期準備
軟件- 模塊- PyQt5==5.15.7- ==2.9. 添加擴展工具 擴展用于將使用 Qt 生成的 ui 文件轉(zhuǎn)成 py 文件,可以在 中通過 -Tools- Tools 進行配置,截圖如下:
Program:/Users/macbookpro/workspace/projects/DownloadServerLog/venv/bin/python3.9
Arguments:-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
Working directory:/Users/macbookpro/workspace/projects/DownloadServerLog/ui
實操步驟
1. 創(chuàng)建項目
創(chuàng)建 項目,設(shè)計程序結(jié)構(gòu)如下:
DownloadServerLog
├── app
│ ├── downloadlog.py
│ └── downloadlog_qtui.py
├── main.py
└── ui
│ └── downloadlog_qtui.ui
├── .env
main.py 作為程序入口文件日志文件太大無法打開,.env 存放環(huán)境變量,ui 存放使用 Qt 設(shè)計界面導(dǎo)出的源碼文件,app 存放下載程序文件。
2.使用 設(shè)計界面
Qt 使用起來非常簡單,可以通過“拖拉拽”的形式生成 UI 界面(文檔:),設(shè)計界面如下:
這個程序功能一目了然,左側(cè)幾個輸入框用于輸入必要的信息,右側(cè)一個展示框用于展示程序?qū)崟r日志。界面設(shè)計好后可以將其保存至項目 下的 ui 目錄下 .ui,供后續(xù)使用。
3. 使用 ui 生成對應(yīng)的 py 文件
使用 打開項目,在 .ui 文件上右鍵,選擇 Tools 使用 PyUIC 根據(jù) ui 文件生成對應(yīng)的 py 文件 .py,將文件存放至 app 目錄。
4. 新建 main.py 作為程序入口
在項目根目錄下創(chuàng)建 main.py 文件:
import sys
from PyQt5 import QtCore
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow
from threading import Thread
from app.downloadlog_qtui import Ui_Dialog
from app.downloadlog import DownloadLog
class CommunicateSignal(QObject):
text_print = pyqtSignal(str)
# MyWindow 是主窗口程序,繼承自 PyQt5.QtWidgets.QMainWindow
# 和通過 ui 文件生成的 downloadlog_qtui.py 中的 Ui_Dialog 類
class MyWindow(QMainWindow, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.btn_download.clicked.connect(self.click_download)
# 自定義信號處理函數(shù)
self.comm_signal = CommunicateSignal()
self.comm_signal.text_print.connect(self.show_text)
self.set_window_init_data()
def set_window_init_data(self):
"""設(shè)置程序窗體初始值"""
# 從 .env 讀取環(huán)境變量
result_dict = dict()
with open('.env', 'r', encoding='utf-8') as f:
for line in f.readlines():
key = line.split('=')[0].strip()
value = line.split('=')[-1].strip()
result_dict[key] = value
# 設(shè)置輸入框值
_translate = QtCore.QCoreApplication.translate
self.host.setText(_translate("Dialog", result_dict.get("HOST", '')))
self.port.setText(_translate("Dialog", result_dict.get("PORT", '22')))
self.username.setText(_translate("Dialog", result_dict.get("USERNAME", 'root')))
self.password.setText(_translate("Dialog", result_dict.get("PASSWORD", '')))
self.directory.setPlainText(_translate("Dialog", result_dict.get("DIRECTORY", '')))
self.startTime.setDate(QtCore.QDate.currentDate())
self.endTime.setDate(QtCore.QDate.currentDate())
def get_window_input_value(self):
"""獲取程序各「輸入框」組件值"""
return {
"host": self.host.text(),
"port": self.port.text(),
"username": self.username.text(),
"password": self.password.text(),
"directory": self.directory.toPlainText(),
"start_time": self.startTime.date().toString("yyyy-MM-dd"),
"end_time": self.endTime.date().toString("yyyy-MM-dd"),
"suffix": ".log",
}
def show_text(self, text):
"""將文本內(nèi)容追加到程序「展示框」"""
self.textBrowser.append(text)
def click_download(self):
"""處理點擊「下載」按鈕事件"""
params = self.get_window_input_value()
def run():
res = DownloadLog(conn_type='ssh', comm_signal=self.comm_signal, **params)
res.main()
t = Thread(target=run)
t.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
myWin = MyWindow()
myWin.show()
sys.exit(app.exec_())
作為主窗口程序,程序初始化時會將 self. 方法注冊到 下載 按鈕的點擊事件,并自動調(diào)用 self. 方法來設(shè)置輸入框初始值。
5. 下載
下載日志程序 定義在 app/.py 中,遠程下載文件主要步驟有兩步:這里采用 來實現(xiàn)遠程下載功能, 是一個純 庫,它實現(xiàn)了 SSHv2 協(xié)議,提供了 SSH 和 FTP 的能力。核心代碼如下,讀者可以根據(jù)自己的需求實現(xiàn) :
class DownloadLog(object):
def __init__(self, **kwargs):
"""初始化一些參數(shù)"""
...
def main(self):
# 獲取 Transport 實例
tran = paramiko.Transport((self.host, int(self.port)))
# 連接 SSH 服務(wù)端
tran.connect(username=self.username, password=self.password)
# 創(chuàng)建 SFTP 實例
self.sftp = paramiko.SFTPClient.from_transport(tran)
# 下載文件
# :param str remotepath: the remote file to copy
# :param str localpath: the destination path on the local host
self.sftp.get(remotepath=self.remote_path, localpath=self.local_path)
6. 展示下載過程
為了將下載程序執(zhí)行步驟實時展示到輸出框,這里需要引入 PyQt5 的信號處理機制。由于 PyQt 建議只在主線程中操作界面,可以發(fā)現(xiàn)我們在 main.py 中調(diào)用 .main 方法時創(chuàng)建了一個新的線程。所有的 GUI 程序都是事件驅(qū)動的,事件可能由用戶觸發(fā),比如點擊 下載 按鈕事件,也可能由程序觸發(fā),比如我們現(xiàn)在要實現(xiàn)的展示下載過程的功能,就需要使用程序主動觸發(fā)事件。在 PyQt5 中通過 信號來處理事件,其基本使用步驟如下:自定義一個 類,繼承自 PyQt5 的 類,里面封裝自定義的 信號( 實例對象的初始化參數(shù)指定的類型,就是發(fā)出信號對象時日志文件太大無法打開,傳遞的參數(shù)數(shù)據(jù)類型。因為 PyQt5 底層是 C++ 開發(fā)的,必須指定類型)。
class CommunicateSignal(QObject):
text_print = pyqtSignal(str)
定義主線程執(zhí)行的函數(shù)處理 信號(通過 方法綁定)。
# 自定義信號處理函數(shù)
self.comm_signal = CommunicateSignal()
self.comm_signal.text_print.connect(self.show_text)
在 線程需要操作界面的時候,就通過自定義對象()發(fā)出信號(使用 emit 方法發(fā)出信號),所以在實例化 時會將 傳遞進去。
# 通過該信號對象的 emit 方法發(fā)出信號,emit 方法的參數(shù)傳遞必要的數(shù)據(jù)。
# 參數(shù)類型遵循定義 Signal 時指定的類型。
self.comm_signal.text_print.emit(text)
主線程信號處理函數(shù),被觸發(fā)執(zhí)行,獲取 里面的參數(shù),執(zhí)行必要的更新界面操作,這里將每次通過事件傳過來的文本內(nèi)容展示到輸出框內(nèi)。
def show_text(self, text):
"""將文本內(nèi)容追加到程序「展示框」"""
self.textBrowser.append(text)
7. 效果展示
通過以上步驟我們完成的程序設(shè)計,現(xiàn)在可以驗證下這個下載日志文件的小程序了:
查看下載結(jié)果:
總結(jié)
我們通過 PyQt5 實現(xiàn)了一個下載遠程服務(wù)器日志文件的小程序,其實它不止可以用來下載日志,同樣可以用來下載其他文件。借助 PyQt5 強大的能力,我們可以通過“拖拉拽”的形式很容易地實現(xiàn)桌面端程序,只需要將原來的 腳本綁定到 UI 程序的事件中,就實現(xiàn)了命令行程序到桌面程序的演進。接下來你可以根據(jù)自己的需求來定制自己的桌面小程序啦~
資料參考:
快 來 找 又 小 拍
推薦 閱 讀
設(shè)為星標
更新不錯過