PyQt5 线程应用程序中的信息错误对话管理

Info-Error Dialogue Management in Threading application in PyQt5

我是 GUI 编程的新手,需要有关 QThread 应用程序的帮助。我有一个 gui 程序可以进行查询并在屏幕上列出查询结果。我希望在屏幕上的列表完成后打开一个信息对话框。我为此编写了一个函数,当操作成功时,它可以正常工作。但是我无法弄清楚如果出现无效的 link 条目如何显示错误对话框。谢谢你的帮助。

-我已经注释掉了一些我尝试过但失败的方法

import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
from time import sleep


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(476, 391)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.listWidget = QtWidgets.QListWidget(self.centralwidget)
        self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
        self.listWidget.setObjectName("listWidget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.running = False
        self.pushButton.clicked.connect(self.startBs4Worker)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "GET"))

    def reveiceData(self, data):
        # This method is the method that will 
        # process the data sent by the thread.
        if data == None:
            return

        _translate = QtCore.QCoreApplication.translate
        item = QtWidgets.QListWidgetItem()
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(11)
        item.setFont(font)
        item.setCheckState(QtCore.Qt.Checked)
        item.setText(_translate("MainWindow", data))
        self.listWidget.addItem(item)

    def setThreadStatus(self):
        self.running = not self.running

    def startBs4Worker(self):
        if self.running:
            print("Thread is still running ...")
            return
        else:
            self.thread = QThread()

            # We send the URL address that the thread will process as a parameter.
            self.worker = Bs4Worker(url=self.lineEdit.text())

            self.worker.moveToThread(self.thread)
            self.thread.started.connect(self.worker.run)
            self.worker.finished.connect(self.thread.quit)
            self.worker.finished.connect(self.worker.deleteLater)
            self.worker.finished.connect(self.setThreadStatus)
            self.thread.finished.connect(self.thread.deleteLater)
            self.worker.notifyProgress.connect(self.reveiceData)
            self.worker.finished.connect(self.uyariBox) #---> With this place active, I couldn't figure out how to activate the Error message when wrong connection was entered.
            self.running = True
            self.thread.start()


    def uyariBox(self):
        self.msg = QMessageBox()
        self.msg.thread()
        self.msg.setWindowTitle("Bilgi !")
        self.msg.setText("Tüm Sonuçlar Getirildi")
        self.msg.setIcon(QMessageBox.Information)
        self.msg.exec_()



class Bs4Worker(QThread):
    notifyProgress = QtCore.pyqtSignal(str)

    def __init__(self, url, parent=None):
        QThread.__init__(self, parent)
        self.url = url

    def run(self):
        try:
            r = requests.get(self.url)
            soup = BeautifulSoup(r.content)
            linkler = soup.find_all("a")
            for link in linkler:
                baslik = link.get("title")

                # Sending header information to master class
                self.notifyProgress.emit(baslik)
            self.finished.connect(ui.uyariBox) #---> When you activate this place, the warning appears instantly and disappears immediately.
                                               #--->  and there is no click anywhere in the app. (Since completion is not pressed in the warning message)

            self.finished.emit()

           # self.finished.connect(ui.uyariBox) #----> Warning does not appear when you activate this place.


        except:

            print("link error")
            self.finished.emit()
            # When I create a new QMessageBox to show the error message, the application crashes.
    
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())

您可以将运算结果作为字符串传递给 uyariBox 方法。

首先你可以在Bs4Worker中创建另一个信号:

class Bs4Worker(QThread):
    result = QtCore.pyqtSignal(str)

将之前的worker.finished连接改为worker.result:

def startBs4Worker(self):
    else:
         self.worker.result.connect(self.uyariBox)
         #Previous was self.worker.finished.connect(self.uyariBox)

向函数添加变量:

def uyariBox(self,message):
    self.msg = QMessageBox()
    self.msg.thread()
    self.msg.setWindowTitle("Bilgi !")
    self.msg.setText(message)
    self.msg.setIcon(QMessageBox.Information)
    self.msg.exec_()

然后用signal传递运算结果:

    def run(self):
        try:
            self.result.emit("Tüm Sonuçlar Getirildi")
        except Exception as e:
            self.result.emit(f"Error: {e}")

完整代码:

import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
from time import sleep


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(476, 391)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
        self.pushButton.setObjectName("pushButton")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.listWidget = QtWidgets.QListWidget(self.centralwidget)
        self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
        self.listWidget.setObjectName("listWidget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        self.running = False
        self.pushButton.clicked.connect(self.startBs4Worker)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "GET"))

    def reveiceData(self, data):
        # This method is the method that will
        # process the data sent by the thread.
        if data == None:
            return

        _translate = QtCore.QCoreApplication.translate
        item = QtWidgets.QListWidgetItem()
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(11)
        item.setFont(font)
        item.setCheckState(QtCore.Qt.Checked)
        item.setText(_translate("MainWindow", data))
        self.listWidget.addItem(item)

    def setThreadStatus(self):
        self.running = not self.running

    def startBs4Worker(self):
        if self.running:
            print("Thread is still running ...")
            return
        else:
            self.thread = QThread()

            # We send the URL address that the thread will process as a parameter.
            self.worker = Bs4Worker(url=self.lineEdit.text())

            self.worker.moveToThread(self.thread)
            self.thread.started.connect(self.worker.run)
            self.worker.finished.connect(self.thread.quit)
            self.worker.finished.connect(self.worker.deleteLater)
            self.worker.finished.connect(self.setThreadStatus)
            self.thread.finished.connect(self.thread.deleteLater)
            self.worker.notifyProgress.connect(self.reveiceData)
            self.worker.result.connect(
                self.uyariBox)  # ---> With this place active, I couldn't figure out how to activate the Error message when wrong connection was entered.
            self.running = True
            self.thread.start()

    def uyariBox(self,message):
        self.msg = QMessageBox()
        self.msg.thread()
        self.msg.setWindowTitle("Bilgi !")
        self.msg.setText(message)
        self.msg.setIcon(QMessageBox.Information)
        self.msg.exec_()


class Bs4Worker(QThread):
    result = QtCore.pyqtSignal(str)
    notifyProgress = QtCore.pyqtSignal(str)

    def __init__(self, url, parent=None):
        QThread.__init__(self, parent)
        self.url = url

    def run(self):
        try:
            r = requests.get(self.url)
            soup = BeautifulSoup(r.content)
            linkler = soup.find_all("a")
            for link in linkler:
                baslik = link.get("title")

                # Sending header information to master class
                self.notifyProgress.emit(baslik)
            self.finished.connect(
                ui.uyariBox)  # ---> When you activate this place, the warning appears instantly and disappears immediately.
            # --->  and there is no click anywhere in the app. (Since completion is not pressed in the warning message)

            self.finished.emit()
            self.result.emit("Tüm Sonuçlar Getirildi")
        # self.finished.connect(ui.uyariBox) #----> Warning does not appear when you activate this place.

        except Exception as e:

            print("link error")
            self.finished.emit()
            self.result.emit(f"Error: {e}")
            # When I create a new QMessageBox to show the error message, the application crashes.


Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())