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.
我真的是编程新手,最近不得不用 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.