Python PyQt5 添加来自另一个 Py 文件的列表项

Python PyQt5 Add List Item from another Py-File

当单击 PyQt5 中的按钮时 Ui 我正在启动一个 mitmproxy。当代理启动时,我尝试使用来自代理的数据更改 listWidget。

main.py

    import sys
    
    from PyQt5 import QtWidgets
    from PyQt5.QtWidgets import QApplication, QMainWindow
    from MainWindow import Ui_MainWindow
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    
        def __init__(self, *args, obj=None, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
            self.setupUi(self)
    
            self.pushButton.clicked.connect(self.Start)
    
        def Start(self):
            x = threading.Thread(target=self.StartMITM)
            x.start()
    
        def StartMITM(self):
            os.system("mitmweb -s mitmproxy.py -q --no-web-open-browser")
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        win = MainWindow()
        win.show()
        sys.exit(app.exec_())

mitmproxy.py - 这是错误的部分

    from mitmproxy import http
    from main import MainWindow
    
    def response(flow):
        MainWindow.listWidget.addItem(flow.request.pretty_url)

我可以从另一个文件连接到小部件吗?

它有两个独立的进程:GUI 和 mitmproxy 脚本。并且通信这两个进程并不意味着导入模块,因为您将创建另一个小部件,也不应该通过 类 访问对象(我建议您检查您的基本 python 注释)。

在此解决方案是使用一些进程间通信 (IPC),在这种情况下您可以使用 Qt Remote Objects (QtRO):

main.py

from functools import cached_property

from PyQt5 import QtCore, QtRemoteObjects, QtWidgets


class Bridge(QtCore.QObject):
    messageChanged = QtCore.pyqtSignal(str)

    @QtCore.pyqtSlot(str)
    def add_message(self, message):
        self.messageChanged.emit(message)


class MitmwebManager(QtCore.QObject):
    logChanged = QtCore.pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        # self.process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
        self.process.readyReadStandardOutput.connect(self.handle_log)
        self.process.setProgram("mitmweb")

    @cached_property
    def process(self):
        return QtCore.QProcess()

    def start(self, arguments):
        self.process.setArguments(arguments)
        self.process.start()

    def stop(self):
        self.process.kill()

    def handle_log(self):
        data = self.process.readAllStandardOutput()
        codec = QtCore.QTextCodec.codecForName("UTF-8")
        message = codec.toUnicode(data)
        self.logChanged.emit(message)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.button = QtWidgets.QPushButton("Start", checkable=True)
        self.listwidget = QtWidgets.QListWidget()
        self.logview = QtWidgets.QPlainTextEdit(readOnly=True)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QGridLayout(central_widget)
        lay.addWidget(self.button, 0, 0, 1, 2)
        lay.addWidget(self.listwidget, 1, 0)
        lay.addWidget(self.logview, 1, 1)

        self.register_node = QtRemoteObjects.QRemoteObjectRegistryHost(
            QtCore.QUrl("local:registry")
        )
        self.source_node = QtRemoteObjects.QRemoteObjectHost(
            QtCore.QUrl("local:replica"), QtCore.QUrl("local:registry")
        )
        self.source_node.enableRemoting(self.bridge, "bridge")

        self.button.toggled.connect(self.handle_toggled)
        self.mitmweb.logChanged.connect(self.handle_log_changed)
        self.bridge.messageChanged.connect(self.handle_message_changed)

        self.resize(640, 480)

    @cached_property
    def mitmweb(self):
        return MitmwebManager()

    @cached_property
    def bridge(self):
        return Bridge()

    def handle_toggled(self, checked):
        if checked:
            self.mitmweb.start(["-s", "script.py", "--no-web-open-browser"])
            self.button.setText("Stop")
        else:
            self.mitmweb.stop()
            self.button.setText("Start")

    def handle_log_changed(self, message):
        self.logview.insertPlainText(message)

    def closeEvent(self, event):
        super().closeEvent(event)
        self.mitmweb.stop()

    def handle_message_changed(self, message):
        item = QtWidgets.QListWidgetItem(message)
        self.listwidget.addItem(item)


def main():
    app = QtWidgets.QApplication([])

    view = MainWindow()
    view.show()

    app.exec_()


if __name__ == "__main__":
    main()

script.py

from mitmproxy import http

from PyQt5 import QtCore, QtRemoteObjects


class Bridge(QtCore.QObject):
    def __init__(self, bridge, parent=None):
        super().__init__(parent)
        self._message = ""
        self._bridge = bridge

        self.bridge.initialized.connect(self.handle_initialized)

    @property
    def bridge(self):
        return self._bridge

    @property
    def message(self):
        return self._message

    def send_message(self, message):
        self._message = message

    @QtCore.pyqtSlot()
    def handle_initialized(self):
        self.bridge.add_message(self._message)
        QtCore.QTimer.singleShot(0, QtCore.QCoreApplication.quit)


def send_qt(message):
    qt_app = QtCore.QCoreApplication([])
    replica_node = QtRemoteObjects.QRemoteObjectNode(QtCore.QUrl("local:registry"))
    replica_bridge = replica_node.acquireDynamic("bridge")
    bridge = Bridge(replica_bridge)
    bridge.send_message(message)
    qt_app.exec_()


def response(flow):
    send_qt(flow.request.pretty_url)