Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/366.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python在使用Qt运行日志拖缆时崩溃 目标_Python_Multithreading_Logging_Pyside2_Qrunnable - Fatal编程技术网

Python在使用Qt运行日志拖缆时崩溃 目标

Python在使用Qt运行日志拖缆时崩溃 目标,python,multithreading,logging,pyside2,qrunnable,Python,Multithreading,Logging,Pyside2,Qrunnable,我有一个进程,它在运行时记录一个文件(realtime.log),我想实时打印应用程序中该文件的每一行。换句话说,我想将输出从进程重定向到GUI。这意味着我有两个不同的进程运行:“引擎”和GUI 我已经通过使用Tkinter实现了这一点,但由于我必须制作更复杂、更专业、更美观的GUI,我决定切换到Qt for Python(PySide2) 问题 当我启动GUI时,Python经常会崩溃,并显示错误消息:Python已停止工作。窗口开始打印行,在某个点停止工作 在多次尝试和搜索之后,我发现只有在

我有一个进程,它在运行时记录一个文件(realtime.log),我想实时打印应用程序中该文件的每一行。换句话说,我想将输出从进程重定向到GUI。这意味着我有两个不同的进程运行:“引擎”和GUI

我已经通过使用Tkinter实现了这一点,但由于我必须制作更复杂、更专业、更美观的GUI,我决定切换到Qt for Python(PySide2

问题 当我启动GUI时,Python经常会崩溃,并显示错误消息:Python已停止工作。窗口开始打印行,在某个点停止工作

在多次尝试和搜索之后,我发现只有在点击GUI窗口时程序才会崩溃。此外,程序不会突然崩溃,而是在引擎执行结束时崩溃

环境
  • 视窗10
  • Python 3.6.5
  • PySide2 5.12.6
代码 请注意,这是一个简化版本

datalog_path = "realtime.log"


def get_array_from_file(file_path):
    try:
        with open(file_path, 'r') as file:
            lines = file.readlines()
        return lines
    except:
        print('error in file access')


class Streamer(QRunnable):
    def __init__(self, stream, old_array, edit):
        super().__init__()
        self.stream = stream
        self.old_array = old_array
        self.edit = edit

    def run(self):
        try:
            while self.stream:
                array_file = get_array_from_file(datalog_path)
                if len(array_file) != len(self.old_array):
                    for line in array_file[len(self.old_array) - 1:len(array_file)]:
                        self.edit.append(line)
                        # print(line)
                        self.old_array.append(line)
        except:
            print('problem in streaming funct')


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()

        self.setWindowTitle("DATALOG")
        self.thread_pool = QThreadPool()
        self.edit = QTextEdit()

        self.stream = True
        self.old_array = get_array_from_file(datalog_path)
        self.streamer = Streamer(self.stream, self.old_array, self.edit)
        self.thread_pool.start(self.streamer)

        window = QWidget()
        layout.addWidget(self.edit)
        window.setLayout(layout)
        self.setCentralWidget(window)


    def closeEvent(self, event):
        self.stream = False
        event.accept()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    app.exec_()

虽然我对Python Qt不太熟悉,但问题可能是,您使用的GUI对象
edit
来自不同的线程。这是不允许的,GUI部分必须全部在同一(主)线程中运行

要解决这个问题,您需要有一些其他的方式让线程来传达UI更改。由于您的QRunnable不是QObject,所以您不能仅仅发出一个信号,而是可以使用它的可调用方法。请让我知道这是否直接起作用:

# self.edit.append(line) # can't do this from a thread!
# instead, invoke append through GUI thread event loop
QtCore.QMetaObject.invokeMethod(self.edit, 
                                'append', 
                                QtCore.Qt.QueuedConnection, 
                                QtCore.QGenericArgument('QString', line)

虽然我对Python Qt不太熟悉,但问题可能是,您使用的GUI对象
edit
来自不同的线程。这是不允许的,GUI部分必须全部在同一(主)线程中运行

要解决这个问题,您需要有一些其他的方式让线程来传达UI更改。由于您的QRunnable不是QObject,所以您不能仅仅发出一个信号,而是可以使用它的可调用方法。请让我知道这是否直接起作用:

# self.edit.append(line) # can't do this from a thread!
# instead, invoke append through GUI thread event loop
QtCore.QMetaObject.invokeMethod(self.edit, 
                                'append', 
                                QtCore.Qt.QueuedConnection, 
                                QtCore.QGenericArgument('QString', line)
指出部分解释了问题的原因,但其解决方案不适用于PySide2(在PyQt5中,必须进行小的修改,请参见),另一种方法是创建具有以下信号的QObject:

class Signaller(QtCore.QObject):
    textChanged = Signal(str)
class拖缆(QRunnable):
def_uuuinit_uuu(自、流、旧数组):
super()。\uuuu init\uuuuu()
self.stream=流
self.old\u数组=old\u数组
self.signaller=signaller()
def运行(自):
尝试:
而self.stream:
数组\u文件=从\u文件(数据日志\u路径)获取\u数组\u
如果len(数组_文件)!=len(self.old_数组):
对于数组_文件中的行[len(self.old_数组)-1:len(数组_文件)]:
self.signaller.textChanged.emit(行)
#打印(行)
self.old_数组.append(行)
除:
打印(“流式处理功能中存在问题”)
self.stream=True
self.old\u array=从\u文件(数据日志\u路径)获取\u array\u
self.streamer=拖缆(self.stream、self.old_阵列)
self.streamer.signaller.textChanged.connect(self.edit.append)
self.thread_pool.start(self.streamer)
指出的问题解释了问题的原因,但其解决方案不适用于PySide2(在PyQt5中,必须进行一个小的修改,请参阅),另一种方法是创建一个具有以下信号的QObject:

class Signaller(QtCore.QObject):
    textChanged = Signal(str)
class拖缆(QRunnable):
def_uuuinit_uuu(自、流、旧数组):
super()。\uuuu init\uuuuu()
self.stream=流
self.old\u数组=old\u数组
self.signaller=signaller()
def运行(自):
尝试:
而self.stream:
数组\u文件=从\u文件(数据日志\u路径)获取\u数组\u
如果len(数组_文件)!=len(self.old_数组):
对于数组_文件中的行[len(self.old_数组)-1:len(数组_文件)]:
self.signaller.textChanged.emit(行)
#打印(行)
self.old_数组.append(行)
除:
打印(“流式处理功能中存在问题”)
self.stream=True
self.old\u array=从\u文件(数据日志\u路径)获取\u array\u
self.streamer=拖缆(self.stream、self.old_阵列)
self.streamer.signaller.textChanged.connect(self.edit.append)

self.thread\u pool.start(self.streamer)
非常感谢您的回答。正如@eyllanesc所述,您的解决方案不适用于PySide2,但概念绝对正确。非常感谢您的回答。正如@eyllanesc所述,您的解决方案不适用于PySide2,但概念绝对正确。