使用?PyQt5?設(shè)計(jì)下載遠(yuǎn)程服務(wù)器日志文件程序的思路
最近通過 PyQt5 設(shè)計(jì)了一個(gè)下載服務(wù)器指定日期日志文件的程序,里面有些有意思的技術(shù)點(diǎn),現(xiàn)在做一些分享。
PyQt5 是一套 Python 綁定 Digia Qt5 應(yīng)用的框架,是最強(qiáng)大的 GUI 庫(kù)之一,使用 PyQt5 我們能夠很容易的開發(fā)桌面應(yīng)用,接下來我們將用它來開發(fā)一個(gè)下載服務(wù)器日志文件的小程序。
前期準(zhǔn)備
軟件
- QT5
- Python 模塊PyQt5==5.15.7paramiko==2.9.2
- PyCharm 添加擴(kuò)展工具 PyUIC
PyUIC 擴(kuò)展用于將使用 Qt Designer 生成的 ui 文件轉(zhuǎn)成 py 文件,可以在 PyCharm 中通過 Preferences-Tools-External Tools 進(jìn)行配置,截圖如下:
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
實(shí)操步驟
1. 創(chuàng)建項(xiàng)目
創(chuàng)建 DownloadServerLog 項(xiàng)目,設(shè)計(jì)程序結(jié)構(gòu)如下:
DownloadServerLog ├── app │ ├── downloadlog.py │ └── downloadlog_qtui.py ├── main.py └── ui │ └── downloadlog_qtui.ui ├── .env
main.py 作為程序入口文件,.env 存放環(huán)境變量,ui 存放使用 Qt Designer 設(shè)計(jì)界面導(dǎo)出的源碼文件,app 存放下載程序文件。
2.使用 QtDesigner 設(shè)計(jì)界面
Qt Designer 使用起來非常簡(jiǎn)單,可以通過“拖拉拽”的形式生成 UI 界面(文檔:https://doc.qt.io/qtcreator/creator-using-qt-designer.html),設(shè)計(jì)界面如下:
這個(gè)程序功能一目了然,左側(cè)幾個(gè)輸入框用于輸入必要的信息,右側(cè)一個(gè)展示框用于展示程序?qū)崟r(shí)日志。界面設(shè)計(jì)好后可以將其保存至項(xiàng)目 DownloadServerLog 下的 ui 目錄下 downloadlog_qtui.ui,供后續(xù)使用。
3. 使用 ui 生成對(duì)應(yīng)的 py 文件
使用 PyCharm 打開項(xiàng)目,在 downloadlog_qtui.ui 文件上右鍵,選擇 External Tools 使用 PyUIC 根據(jù) ui 文件生成對(duì)應(yīng)的 py 文件 downloadlog_qtui.py,將文件存放至 app 目錄。
4. 新建 main.py 作為程序入口
在項(xiàng)目根目錄下創(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) # 自定義信號(hào)處理函數(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): """處理點(diǎn)擊「下載」按鈕事件""" 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_())
MyWindow 作為主窗口程序,程序初始化時(shí)會(huì)將 self.click_download 方法注冊(cè)到 下載 按鈕的點(diǎn)擊事件,并自動(dòng)調(diào)用 self.set_window_init_data 方法來設(shè)置輸入框初始值。
5. 下載
下載日志程序 DownloadLog 定義在 app/downloadlog.py 中,遠(yuǎn)程下載文件主要步驟有兩步:
- 通過 SSH 登錄遠(yuǎn)程服務(wù)器
- 通過 FTP 進(jìn)行文件下載
這里采用 paramiko 來實(shí)現(xiàn)遠(yuǎn)程下載功能,paramiko 是一個(gè)純 Python 庫(kù),它實(shí)現(xiàn)了 SSHv2 協(xié)議,提供了 SSH 和 FTP 的能力。
核心代碼如下,讀者可以根據(jù)自己的需求實(shí)現(xiàn) DownloadLog:
class DownloadLog(object): def __init__(self, **kwargs): """初始化一些參數(shù)""" ... def main(self): # 獲取 Transport 實(shí)例 tran = paramiko.Transport((self.host, int(self.port))) # 連接 SSH 服務(wù)端 tran.connect(username=self.username, password=self.password) # 創(chuàng)建 SFTP 實(shí)例 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í)行步驟實(shí)時(shí)展示到輸出框,這里需要引入 PyQt5 的信號(hào)處理機(jī)制。
由于 PyQt 建議只在主線程中操作界面,可以發(fā)現(xiàn)我們?cè)?main.py 中調(diào)用 DownloadLog.main 方法時(shí)創(chuàng)建了一個(gè)新的線程。
所有的 GUI 程序都是事件驅(qū)動(dòng)的,事件可能由用戶觸發(fā),比如點(diǎn)擊 下載 按鈕事件,也可能由程序觸發(fā),比如我們現(xiàn)在要實(shí)現(xiàn)的展示下載過程的功能,就需要使用程序主動(dòng)觸發(fā)事件。
在 PyQt5 中通過 Signal 信號(hào)來處理事件,其基本使用步驟如下:
自定義一個(gè) CommunicateSignal 類,繼承自 PyQt5 的 QObject 類,里面封裝自定義的 Signal 信號(hào)(Signal 實(shí)例對(duì)象的初始化參數(shù)指定的類型,就是發(fā)出信號(hào)對(duì)象時(shí),傳遞的參數(shù)數(shù)據(jù)類型。因?yàn)?PyQt5 底層是 C++ 開發(fā)的,必須指定類型)。
class CommunicateSignal(QObject): text_print = pyqtSignal(str)
定義主線程執(zhí)行的函數(shù)處理 Signal 信號(hào)(通過 connect 方法綁定)。
# 自定義信號(hào)處理函數(shù) self.comm_signal = CommunicateSignal() self.comm_signal.text_print.connect(self.show_text)
在 DownloadLog 線程需要操作界面的時(shí)候,就通過自定義對(duì)象(CommunicateSignal)發(fā)出信號(hào)(使用 emit 方法發(fā)出信號(hào)),所以在實(shí)例化 DownloadLog 時(shí)會(huì)將 comm_signal 傳遞進(jìn)去。
# 通過該信號(hào)對(duì)象的 emit 方法發(fā)出信號(hào),emit 方法的參數(shù)傳遞必要的數(shù)據(jù)。 # 參數(shù)類型遵循定義 Signal 時(shí)指定的類型。 self.comm_signal.text_print.emit(text)
主線程信號(hào)處理函數(shù),被觸發(fā)執(zhí)行,獲取 Signal 里面的參數(shù),執(zhí)行必要的更新界面操作,這里將每次通過事件傳過來的文本內(nèi)容展示到輸出框內(nèi)。
def show_text(self, text): """將文本內(nèi)容追加到程序「展示框」""" self.textBrowser.append(text)
7. 效果展示
通過以上步驟我們完成的程序設(shè)計(jì),現(xiàn)在可以驗(yàn)證下這個(gè)下載日志文件的小程序了:
查看下載結(jié)果:
總結(jié)
我們通過 PyQt5 實(shí)現(xiàn)了一個(gè)下載遠(yuǎn)程服務(wù)器日志文件的小程序,其實(shí)它不止可以用來下載日志,同樣可以用來下載其他文件。
借助 PyQt5 強(qiáng)大的能力,我們可以通過“拖拉拽”的形式很容易地實(shí)現(xiàn)桌面端程序,只需要將原來的 Python 腳本綁定到 UI 程序的事件中,就實(shí)現(xiàn)了命令行程序到桌面程序的演進(jìn)。
接下來你可以根據(jù)自己的需求來定制自己的桌面小程序啦~
資料參考:
https://download.qt.io/archive/qt/5.14/5.14.2/
https://doc.qt.io/qtcreator/creator-using-qt-designer.html
https://docs.paramiko.org/en/stable/
到此這篇關(guān)于使用 PyQt5 設(shè)計(jì)下載遠(yuǎn)程服務(wù)器日志文件程序的文章就介紹到這了,更多相關(guān)PyQt5遠(yuǎn)程服務(wù)器日志文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python面向?qū)ο蠖嗑€程爬蟲爬取搜狐頁(yè)面的實(shí)例代碼
這篇文章主要介紹了python面向?qū)ο蠖嗑€程爬蟲爬取搜狐頁(yè)面的實(shí)例代碼,需要的朋友可以參考下2018-05-05機(jī)器學(xué)習(xí)python實(shí)戰(zhàn)之決策樹
這篇文章主要為大家詳細(xì)介紹了機(jī)器學(xué)習(xí)python實(shí)戰(zhàn)之決策樹的相關(guān)資料 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11python flask框架實(shí)現(xiàn)傳數(shù)據(jù)到j(luò)s的方法分析
這篇文章主要介紹了python flask框架實(shí)現(xiàn)傳數(shù)據(jù)到j(luò)s的方法,結(jié)合實(shí)例形式分析了前端數(shù)據(jù)序列化及后臺(tái)Flask交互數(shù)據(jù)返回相關(guān)操作技巧,需要的朋友可以參考下2019-06-06Python中import的用法陷阱解決盤點(diǎn)小結(jié)
這篇文章主要為大家介紹了Python中import的用法陷阱解決盤點(diǎn)小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10簡(jiǎn)單實(shí)現(xiàn)Python爬取網(wǎng)絡(luò)圖片
這篇文章主要教大家如何簡(jiǎn)單實(shí)現(xiàn)Python爬取網(wǎng)絡(luò)圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04python爬蟲之urllib庫(kù)常用方法用法總結(jié)大全
urllib是python自帶的請(qǐng)求庫(kù),各種功能相比較之下也是比較完備的,下面這篇文章主要給大家介紹了關(guān)于python爬蟲之urllib庫(kù)常用方法用法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-11-11淺析Python+OpenCV使用攝像頭追蹤人臉面部血液變化實(shí)現(xiàn)脈搏評(píng)估
這篇文章主要介紹了Python+OpenCV使用攝像頭追蹤人臉面部血液變化實(shí)現(xiàn)脈搏評(píng)估,本文通過一段代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10