簡體   English   中英

PyQT QThread 遵循線程執行順序(等待)

[英]PyQT QThread follow the thread execution order (wait)

我正在嘗試運行一些緩慢的進程,但是,我需要不斷更新 QDialog 以顯示進度(也許我也放了一個進度條)。

所以我決定使用 QThread,但在第一次嘗試時,它並沒有像我預期的那樣工作。

在我的示例代碼中: 1- 我正在對我的默認網關使用簡單的 ping 2- 我正在對我的 dns 解析器進行 ping

正如您在下面的圖片中看到的那樣,信息是根據線程正在完成顯示的,但這對我來說是一團糟。

是否可以尊重線程順序來顯示信息?

謝謝。

例子

按照我的示例代碼:

# -*- coding: utf8 -*-

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from ping3 import ping, verbose_ping
import socket
import dns.resolver

class ExternalTests(QThread):
    data_collected = pyqtSignal(object)
    
    def __init__(self, title, arg=None):
        QThread.__init__(self)
        self.title = title
        self.arg = arg

    def run(self):
        resp = ping(self.arg)
        self.data_collected.emit('%s: %s' % (self.title, resp))

class MainMenu(QMenu):
    def __init__(self, parent=None):
        QMenu.__init__(self)
        self.setStyleSheet("background-color: #3a80cd; color: rgb(255,255,255); selection-color: white; selection-background-color: #489de4;")
        # Diagnostics
        self.check_internet = QAction("Diagnosys")
        self.check_internet.setIcon(QIcon(QPixmap("..\\img\\lupa.png")))
        self.check_internet.triggered.connect(self.diagnosticNetwork)
        self.addAction(self.check_internet)
        self.addSeparator()

        # To quit the app
        self.quit = QAction("Quit")
        self.quit.triggered.connect(app.quit)
        self.addAction(self.quit)

    def diagnosticNetwork(self):
        self.check_internet_dialog = QDialog()
        self.check_internet_dialog.setWindowTitle("Check external connections")
        self.check_internet_dialog.setWindowModality(Qt.ApplicationModal)
        self.check_internet_dialog.setGeometry(150, 100, 700, 500)

        # text box
        self.textbox = QTextBrowser(self.check_internet_dialog)
        self.textbox.move(20, 20)
        self.textbox.resize(660,400)
        self.textbox.setFont(QFont("Courier New", 12))
        self.textbox.setStyleSheet("background-color: black;")

        #button copy
        btn_copy = QPushButton("Copy", self.check_internet_dialog)
        btn_copy.setIcon(QIcon(QPixmap("..\\img\\copy.png")))
        btn_copy.move(520,450)
        btn_copy.clicked.connect(self.dialogClickCopy)

        #button close
        btn_copy = QPushButton("Close", self.check_internet_dialog)
        btn_copy.setIcon(QIcon(QPixmap("..\\img\\close.png")))
        btn_copy.move(605,450)
        btn_copy.clicked.connect(self.dialogClickClose)
    
        # tests
        self.textbox.setTextColor(QColor("white"))
        self.textbox.append("Diagnosys")
        self.textbox.append("--------------------------------------------------")
        self.textbox.setTextColor(QColor("cyan"))
        
        self.threads = []
        #QCoreApplication.processEvents()
        
        ''' ping default gateway '''
        ping_default_gw = ExternalTests("default gatewat is reacheble", "192.168.0.1")
        ping_default_gw.data_collected.connect(self.onDataReady)
        self.threads.append(ping_default_gw)
        ping_default_gw.start()
        
        ''' ping dns resolver '''
        ping_dns_resolvers = dns.resolver.Resolver().nameservers
        for dns_resolver in ping_dns_resolvers:
            ping_dns_resolver = ExternalTests("dns resolver is reacheble %s" % dns_resolver, dns_resolver)
            ping_dns_resolver.data_collected.connect(self.onDataReady)
            self.threads.append(ping_dns_resolver)
            ping_dns_resolver.start()

        self.check_internet_dialog.exec_()

    
    def onDataReady(self, data):
        print(data)
        if data:
            self.textbox.append(data)
        else:
            self.textbox.append("error")


    def dialogClickCopy(self):
        pass

    def dialogClickClose(self):
        self.check_internet_dialog.close()

class SystemTrayIcon(QSystemTrayIcon):
    def __init__(self, menu, parent=None):
        QSystemTrayIcon.__init__(self)
        self.setIcon(QIcon("..\\img\\icon.png"))
        self.setVisible(True)
        self.setContextMenu(menu)

if __name__ == "__main__":
    import sys
    app = QApplication([])
    app.setQuitOnLastWindowClosed(False)
    app.setApplicationName('pkimonitor')      
    app.setApplicationVersion('0.1')
    app.setWindowIcon(QIcon("..\\img\\icon.png"))
    menu = MainMenu()
    widget = QWidget()
    trayIcon = SystemTrayIcon(menu, widget)
    trayIcon.show()
    sys.exit(app.exec_())

我試圖創建一個按“運行位置”組織的方案並且它有效。 按照我的代碼。

在“診斷網絡”中:

self.data_list = []
self.data_hold = []

在“onDataReady”中:

if len(self.data_list) > 0:
    if self.data_list[-1][0] + 1 == data[0]:
        self.data_list.append(data)
        if data[2]:
            self.textbox.append("%s: %s" % (data[1], 'OK'))
        else:
            self.textbox.append("%s: %s" % (data[1], 'NOK'))
    elif self.data_list[-1][0] < data[0]:
        self.data_hold.append(data)
else:
    self.data_list.append(data)
    if data[2]:
        self.textbox.append("%s: %s" % (data[1], 'OK'))
    else:
        self.textbox.append("%s: %s" % (data[1], 'NOK'))

if len(self.data_hold) > 0:
    hold_sorted = self.data_hold[:]
    hold_sorted.sort()
    for line_hold in hold_sorted:
        if self.data_list[-1][0] + 1 == line_hold[0]:
            if line_hold[2]:
                self.textbox.append("%s: %s" % (line_hold[1], 'OK'))
            else:
                self.textbox.append("%s: %s" % (line_hold[1], 'NOK'))
            self.data_list.append(line_hold)
            del self.data_hold[0]

我使用了兩個列表,data_list 和 data_hold。 我從線程收到的結果,我按照我預先建立的順序填寫了主列表,如果輸入的結果不是序列中的下一個,則進入data_hold,然后掃描這個列表來填充我的文本框的 rest。

謝謝大家的幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM