PyQt5 中的访问冲突错误

Acess violation error in PyQt5

我真的是编程新手,最近不得不用 PyQt 做一个 GUI。基本上它所做的是读取串行端口上来自 Arduino 的一些数据,并每 100 个 Arduino 发送的值更新一个图表。还有一个日志功能,可以将数据记录到格式化文件中。一切似乎都工作正常,但现在我的程序停止工作,并弹出一条消息说 python 停止工作。我试了几次,同样的消息随机弹出。你能帮我解决这个问题吗?

主要是根据我在其他一些论坛和这个论坛上阅读的内容,我认为问题出在我的 PlotThread class 中,它被我的主要 window class 使用。我不知道那个问题是什么以及如何解决它。这里是 Window 和 PlotThread class.

谢谢,

西蒙·贝尔马尔

class Window(QDialog):
  def __init__(self, parent=None):
    super(Window, self).__init__(parent)

    self.log_x = np.array([])
    self.log_y = np.array([])
    self.test_id = ''
    self.plot_thread = PlotThread()
    self.plot_thread.main = self
    self.figure = plt.figure()

    # Canvas Widget
    self.canvas = FigureCanvas(self.figure)

    # Navigation Widget
    self.toolbar = NavigationToolbar(self.canvas, self)

    # Button to control plot function
    self.control_plot = QPushButton('Start')
    self.control_plot.clicked.connect(self.plot)

    # Button to log data
    self.log_data = QPushButton('Log')
    self.log_data.clicked.connect(self.log_file)

    # Progress bar to indicate data harvesting speed
    self.progressBar = QProgressBar(self)
    self.progressBar.setGeometry(QRect(10, 10, 200, 25))
    self.progressBar.move(500, 10)

    # Layout
    layout = QVBoxLayout()
    layout.addWidget(self.toolbar)
    layout.addWidget(self.canvas)
    layout.addWidget(self.control_plot)
    layout.addWidget(self.log_data)
    self.setLayout(layout)

    # Initialising the plot figure
    self.fig1 = self.figure.add_subplot(111)
    rect = self.fig1.patch
    rect.set_facecolor('white')
    self.fig1.set_xlabel('time [s]')
    self.fig1.set_ylabel('RSSI [dBm]')
    self.fig1.grid(True)
    self.fig1.spines["top"].set_visible(False)
    self.fig1.spines["right"].set_visible(False)
    self.fig1.spines["bottom"].set_visible(False)
    self.fig1.spines["left"].set_visible(False)

  def log_file(self):
    directory = ''.join(filter(str.isalpha, self.test_id))

    # Creating the directory if it doesn't exist
    create_directory(directory)

    # Creating the file if it doesn't exist
    if not os.path.isfile(
            'C:\Users\Simon\Documents\Ete2017\PythonCode\main\{0}\{1}.txt'.format(directory,
                                                                                         self.test_id)):
        log = open('C:\Users\Simon\Documents\Ete2017\PythonCode\main\{0}\{1}.txt'.format(directory,
                                                                                               self.test_id),
                   'w')
        # Creating the header
        log.write(' ' * 9 + 'Time [s]' + ' ' * 9 + '|' + ' ' * 4 + 'RSSI [dBm] \n')
    else:
        log = open('C:\Users\Simon\Documents\Ete2017\PythonCode\main\{0}\{1}.txt'.format(directory,
                                                                                               self.test_id),
                   'a')

    # Logging the data
    for i in range(np.size(self.log_x)):
        x = str(self.log_x[i])
        space_num = 24 - len(x)
        log.write(' ' * space_num + x + "  |" + ' ' * 5 + str(self.log_y[i]) + ' \n')

    # Reinitialising logging
    self.log_x = np.array([])
    self.log_y = np.array([])

  def pause(self):
    self.plot_thread.terminate()
    self.control_plot.setText('Start')
    self.control_plot.clicked.connect(self.plot)
    self.log_data.setText('Log')
    self.log_data.clicked.connect(self.log_file)

  def plot(self):
    self.control_plot.setText('Pause')
    self.control_plot.clicked.connect(self.pause)
    self.log_data.setText('')
    self.log_data.clicked.connect(self.wait)

    self.plot_thread.start()

  def wait(self):
    pass

class PlotThread(QThread):
    def __init__(self):
        QThread.__init__(self)
        self.main = ''
        self.t_start = 0
        self.ser = ser

        # Replace by expected values at time 0s
        self.xf = 0
        self.yf = -43

    def run(self):
        while self.isRunning():
            print("Starting to plot")
            self.ser.flushInput()
            self.t_start = time.time()
            # Preallocating memory for the arrays
            x = np.empty([100])
            y = np.empty([100])

            # Initializing start values
            x[0] = self.xf
            y[0] = self.yf
            self.main.progressBar.setValue(1)

            # Reading data from the Arduino
            for i in range(99):
                reading = str(ser.readline())
                while not reading[3:5].isdigit():
                    reading = str(ser.readline())
                y[i + 1] = -int(reading[3:5])
                x[i + 1] = self.xf + (time.time() - self.t_start)
                print(x[i])
                self.main.progressBar.setValue(i + 1)

            # Preparing start values for next iteration
            self.xf = x[99]
            self.yf = y[99]

            # Preparing the log variables
            self.main.log_x = np.append(self.main.log_x, x)
            self.main.log_y = np.append(self.main.log_y, y)

            # Plotting raw data
            self.main.fig1.plot(x, y, 'r--')

            # Filtering raw data
            poly8 = np.polyfit(x, y, 8)
            xGraph = np.linspace(x[0], x[99], num=200)
            yGraph = np.polyval(poly8, xGraph)

            # Graphing filtered data
            self.main.fig1.plot(xGraph, yGraph, 'b')
            # Saving the graph into a file
            timer = self.xf + time.time() - self.t_start
            # Scaling the axes
            if timer > 80:
                print("Scaling the axes")
                self.main.fig1.set_xlim([int(timer) - 80, timer])

            # refresh canvas
            self.main.canvas.draw()
            self.main.canvas.flush_events()

may not在非主线程中与 GUI 交互:

As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.