进程以退出代码 -1073741819 (0xC0000005) Python Tkinter GUI Canvas 更新完成
Posted
技术标签:
【中文标题】进程以退出代码 -1073741819 (0xC0000005) Python Tkinter GUI Canvas 更新完成【英文标题】:Process finished with exit code -1073741819 (0xC0000005) Python Tkinter GUI Canvas Update 【发布时间】:2021-02-03 16:41:14 【问题描述】:我需要在线程计时器的每次迭代中更新 TKagg Canvas 图。该图显示在计时器的第一次迭代中,然后程序暂停并输出 - '进程完成,退出代码 -1073741819 (0xC0000005)'
我这几天一直在努力让这段代码正常工作。任何帮助,将不胜感激。代码按原样运行,并且应该输出相同的退出代码。我不知道如何附加我的测试矩阵,但它只是一个 401x401 numpy 数组,包含 0.0-0.05 之间的值
import threading
from tkinter import *
from tkinter import ttk
import tkinter as tk
import numpy as np
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
matplotlib.use('Agg')
from matplotlib import cm, colors
import os
import os.path
class APP(tk.Tk):
update_interval = 0.2
dwell_time = np.array([20., 20., 20.])
current_count = 0
colormap = 'jet'
window_height = 480
window_width = 720
num_columns = 20
num_rows = 20
canvas_width = window_width / num_columns * 13
canvas_height = window_height / num_rows * 16
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# create a container
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=False)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# initialize an empty array of frames
self.frames =
# iterate through the tuple of page frames - basically creates/configures an empty frame for each page
for F in (Page1, Page2):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="NSEW")
frame.grid_rowconfigure(0, weight=1) # fills the whole window
frame.grid_columnconfigure(0, weight=1) # fills the whole window
self.show_frame(Page1)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def resource_path(relative_path):
return os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path)
filename = "22222222_20210203083122.csv"
filepath = resource_path('PDT_Patient_Treatment_Maps/' + filename)
dose_map = np.load(resource_path('test.npy'))
print(dose_map)
class Page1(tk.Frame):
f = Figure()
update_interval = 0.2
dwell_time = np.array([20., 20., 20.])
current_count = 0
colormap = 'jet'
window_height = 480
window_width = 720
num_columns = 20
num_rows = 20
canvas_width = window_width / num_columns * 13
canvas_height = window_height / num_rows * 16
plt = f.add_subplot(111)
def start_treatment(self):
counts_per_each_diffuser = (APP.dwell_time / APP.update_interval).astype(int)
self.cumulative_count = counts_per_each_diffuser.cumsum()
self.total_count = self.cumulative_count[-1]
self.max_count = counts_per_each_diffuser.max()
self.current_map = np.zeros(APP.dose_map.shape) # initialize detection map
self.timer_update()
def timer_update(self):
"""update detector map and progress bar"""
timer = threading.Timer(APP.update_interval, self.timer_update)
timer.start()
if APP.current_count >= self.total_count:
timer.cancel()
APP.current_count = 0
else:
self.update_det_map()
self.current_count += 1
current_percentage = self.current_count / self.total_count
current_percentage = current_percentage if current_percentage <= 1 else 1
self.progress['value'] = round(current_percentage, 3) * 100
self.style.configure('text.Horizontal.TProgressbar', text=':.1%'.format(current_percentage))
def update_det_map(self):
self.show_det_map(self.current_map, self.det_canvas, self.plt)
def show_det_map(self, map_data, canvas, ax):
"""convert 2d map data into PhotoImage RGB data and draw it on detector canvas"""
self.gray2rgb = cm.get_cmap(self.colormap)
img = (np.delete(self.gray2rgb(map_data), 3, 2) * 255).astype(np.uint8)
ax.clear()
ax.imshow(img, cmap=self.gray2rgb)
canvas.draw()
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# initializes grid to have evenly weighted rows and columns for the page
# self.dose_map = dose_map
cols = 0
while cols < 20:
self.grid_columnconfigure(cols, weight=1)
self.grid_rowconfigure(cols, weight=1)
cols += 1
self.det_canvas = FigureCanvasTkAgg(self.f, self)
self.det_canvas.draw()
self.det_canvas.get_tk_widget().grid(row=0, column=6, rowspan=16, columnspan=13, padx=5, pady=10, sticky='NSEW')
self.det_canvas._tkcanvas.grid(sticky='nsew', pady=10, padx=10)
self.det_canvas._tkcanvas.config(highlightbackground='grey64', highlightthickness=1)
# progress bar
self.style = ttk.Style(self)
self.style.layout('text.Horizontal.TProgressbar',
[('Horizontal.Progressbar.trough',
'children': [('Horizontal.Progressbar.pbar',
'side': 'left', 'sticky': 'ns')],
'sticky': 'nsew'),
('Horizontal.Progressbar.label', 'sticky': 'ns')])
self.style.configure('text.Horizontal.TProgressbar', text='0.0 %', font=('Times', 12))
self.progress = ttk.Progressbar(self, orient=HORIZONTAL, mode='determinate')
self.progress.configure(style='text.Horizontal.TProgressbar')
self.progress.grid(row=18, column=0, rowspan=1, columnspan=20, padx=10, pady=5, sticky='NSEW')
# inserts space between lumeda logo and username label
self.grid_rowconfigure(17, weight=1) # weight controls number of spaces
self.grid_rowconfigure(19, weight=1) # weight controls number of spaces
style = ttk.Style()
style.configure('green.TButton', background='green4', font='bold', foreground='green4', highlightcolor='green4')
self.start_btn = ttk.Button(self, text="START", style='green.TButton',
command=lambda: self.start_treatment())
self.start_btn.grid(row=20, column=5, rowspan=1, columnspan=1, pady=10, padx=5, sticky='nsew')
class Page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
if __name__ == '__main__':
root = APP()
root.geometry("720x460")
root.resizable(0, 0)
root.mainloop()
【问题讨论】:
我害怕将线程用于 tkinter 的定时进程,但一直无法让它工作。而是发现递归使用after
方法更容易。
我发现它与计时器和在 tkagg 画布上绘图有关。如果我注释掉 canvas.draw,程序会按预期完成执行,但不会更新图形。如果我将计时器更改为循环并保持 canvas.draw 图形得到更新。我的程序由计时器控制,所以我需要保留它。
@Andrew Allaire 我需要保留计时器,因为它控制在后端运行的函数的进度,链接到我的绘图和 GUI 的其他元素。我在应用程序的任何其他方面都没有遇到计时器和 GUI 的问题,只是这个 tkagg 画布绘制
而不是计时器更好地使用after
- Tkinter
类似于许多其他 GUI 不喜欢更新 threads
中的小部件。在timer_update
的末尾你应该运行root.after(APP.update_interval, self.timer_update)
您可以使用command=self.start_treatment
代替command=lambda: self.start_treatment()
- 没有lambda
和没有()
【参考方案1】:
最终使用 after() 函数,一切正常。谢谢!
【讨论】:
以上是关于进程以退出代码 -1073741819 (0xC0000005) Python Tkinter GUI Canvas 更新完成的主要内容,如果未能解决你的问题,请参考以下文章
如果进程以退出代码 0 结束,我应该调用 Process.destroy() 吗?
进程以退出代码 1 Spring Boot Intellij 结束
进程以退出代码 -1073741515 (0xC0000135) 结束