Tkinter 中的线程和 Python3
Threading in Tkinter and Python3
我在 PyCharm 中根据我的需要调整此 code,它运行良好,没有任何异常和错误。当我在 Jupyter Notebook 中尝试它时它起作用了,但是当我关闭 Tkinter window 时,我得到异常 Exception in thread Thread-:
和错误 RuntimeError: main thread is not in main loop
.
追溯是:第 90 行,在 运行 - 第 51 行,在执行操作 - 第 30 行,在 try_move
我试图找到解决方案,但我只找到了 Python2 的 mtTkinter。
由于我是线程的新手,我不知道如何解决这个问题,也不知道为什么它只显示在 Jupyter Notebook 中。 Jupyter Notebook 是否可能是问题的根源?
密码是:
from tkinter import *
import threading
import time
def render_grid():
global specials, walls, WIDTH, x, y, player
for i in range(x):
for j in range(y):
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="misty rose", width=1)
temp = {}
cell_scores[(i, j)] = temp
for (i, j, c, w) in specials:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill=c, width=1)
for (i, j) in walls:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="wheat4", width=1)
def set_cell_score(state, action, val):
global cell_score_min, cell_score_max
def try_move(dx, dy):
global player, x, y, score, walk_reward, me, restart
if restart:
restart_game()
new_x = player[0] + dx
new_y = player[1] + dy
score += walk_reward
if (new_x >= 0) and (new_x < x) and (new_y >= 0) and (new_y < y) and not ((new_x, new_y) in walls):
board.coords(me, new_x * WIDTH + WIDTH * 2 / 10, new_y * WIDTH + WIDTH * 2 / 10, new_x * WIDTH + WIDTH * 8 / 10,
new_y * WIDTH + WIDTH * 8 / 10)
player = (new_x, new_y)
for (i, j, c, w) in specials:
if new_x == i and new_y == j:
score -= walk_reward
score += w
if score > 0:
print("Success! score: ", score)
else:
print("Fail! score: ", score)
restart = True
return
# print "score: ", score
def call_up(event):
try_move(0, -1)
def call_down(event):
try_move(0, 1)
def call_left(event):
try_move(-1, 0)
def call_right(event):
try_move(1, 0)
def restart_game():
global player, score, me, restart
player = (0, y - 1)
score = 1
restart = False
board.coords(me, player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10)
def has_restarted():
return restart
def start_game():
master.mainloop()
master = Tk()
master.resizable(False, False)
cell_score_min = -0.2
cell_score_max = 0.2
WIDTH = 100
(x, y) = (5, 5)
actions = ["up", "down", "left", "right"]
board = Canvas(master, width=x * WIDTH, height=y * WIDTH)
player = (0, y - 1)
score = 1
restart = False
walk_reward = -0.04
walls = [(1, 1), (1, 2), (2, 1), (2, 2)]
specials = [(4, 1, "salmon1", -1), (4, 0, "medium sea green", 1)]
cell_scores = {}
discount = 0.3
states = []
Q = {}
for i in range(x):
for j in range(y):
states.append((i, j))
for state in states:
temp = {}
for action in actions:
temp[action] = 0.1
set_cell_score(state, action, temp[action])
Q[state] = temp
for (i, j, c, w) in specials:
for action in actions:
Q[(i, j)][action] = w
set_cell_score((i, j), action, w)
def do_action(action):
s = player
r = -score
if action == actions[0]:
try_move(0, -1)
elif action == actions[1]:
try_move(0, 1)
elif action == actions[2]:
try_move(-1, 0)
elif action == actions[3]:
try_move(1, 0)
else:
return
s2 = player
r += score
return s, action, r, s2
def max_Q(s):
val = None
act = None
for a, q in Q[s].items():
if val is None or (q > val):
val = q
act = a
return act, val
def inc_Q(s, a, alpha, inc):
Q[s][a] *= 1 - alpha
Q[s][a] += alpha * inc
set_cell_score(s, a, Q[s][a])
def run():
global discount
time.sleep(1)
alpha = 1
t = 1
while True:
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
time.sleep(0.1)
render_grid()
master.bind("<Up>", call_up)
master.bind("<Down>", call_down)
master.bind("<Right>", call_right)
master.bind("<Left>", call_left)
me = board.create_rectangle(player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10, fill="sandy brown",
width=1, tag="me")
board.grid(row=0, column=0)
t = threading.Thread(target=run)
t.setDaemon(True)
t.start()
start_game()
可能所有 GUI 都不喜欢在线程中 运行 并且小部件中的所有更改都应该在主线程中(但计算仍然可以在单独的线程中)
在 tkinter
中,您可以使用 master.after(milliseconds, function_name)
而不是 thread
和 while
- 定期循环到 运行 代码 - 这将像循环一样工作但是在当前线程中。
def run():
global t
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
# run again after 100ms
master.after(100, run)
然后作为正常功能启动它
#master.after(100, run) # run after 100ms
run() # run at once
start_game()
完整的工作代码:
编辑:
您也可以使用全局变量 - 即。 running = True
- 在销毁 GUI 之前停止循环。
当你点击关闭按钮[X]
时,它可能还需要master.protocol("WM_DELETE_WINDOW", on_delete)
来执行功能
from tkinter import *
#import threading
import time
def render_grid():
global specials, walls, WIDTH, x, y, player
for i in range(x):
for j in range(y):
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="misty rose", width=1)
temp = {}
cell_scores[(i, j)] = temp
for (i, j, c, w) in specials:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill=c, width=1)
for (i, j) in walls:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="wheat4", width=1)
def set_cell_score(state, action, val):
global cell_score_min, cell_score_max
def try_move(dx, dy):
global player, x, y, score, walk_reward, me, restart
if restart:
restart_game()
new_x = player[0] + dx
new_y = player[1] + dy
score += walk_reward
if (new_x >= 0) and (new_x < x) and (new_y >= 0) and (new_y < y) and not ((new_x, new_y) in walls):
board.coords(me, new_x * WIDTH + WIDTH * 2 / 10, new_y * WIDTH + WIDTH * 2 / 10, new_x * WIDTH + WIDTH * 8 / 10,
new_y * WIDTH + WIDTH * 8 / 10)
player = (new_x, new_y)
for (i, j, c, w) in specials:
if new_x == i and new_y == j:
score -= walk_reward
score += w
if score > 0:
print("Success! score: ", score)
else:
print("Fail! score: ", score)
restart = True
return
# print "score: ", score
def call_up(event):
try_move(0, -1)
def call_down(event):
try_move(0, 1)
def call_left(event):
try_move(-1, 0)
def call_right(event):
try_move(1, 0)
def restart_game():
global player, score, me, restart
player = (0, y - 1)
score = 1
restart = False
board.coords(me, player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10)
def has_restarted():
return restart
def start_game():
master.mainloop()
def do_action(action):
s = player
r = -score
if action == actions[0]:
try_move(0, -1)
elif action == actions[1]:
try_move(0, 1)
elif action == actions[2]:
try_move(-1, 0)
elif action == actions[3]:
try_move(1, 0)
else:
return
s2 = player
r += score
return s, action, r, s2
def max_Q(s):
val = None
act = None
for a, q in Q[s].items():
if val is None or (q > val):
val = q
act = a
return act, val
def inc_Q(s, a, alpha, inc):
Q[s][a] *= 1 - alpha
Q[s][a] += alpha * inc
set_cell_score(s, a, Q[s][a])
def run():
global t
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
# run again after 100ms
if running:
master.after(100, run)
def on_delete():
global running
running = False
master.destroy()
# --- main ---
master = Tk()
master.resizable(False, False)
cell_score_min = -0.2
cell_score_max = 0.2
WIDTH = 100
(x, y) = (5, 5)
actions = ["up", "down", "left", "right"]
board = Canvas(master, width=x * WIDTH, height=y * WIDTH)
player = (0, y - 1)
score = 1
restart = False
walk_reward = -0.04
walls = [(1, 1), (1, 2), (2, 1), (2, 2)]
specials = [(4, 1, "salmon1", -1), (4, 0, "medium sea green", 1)]
cell_scores = {}
discount = 0.3
states = []
Q = {}
for i in range(x):
for j in range(y):
states.append((i, j))
for state in states:
temp = {}
for action in actions:
temp[action] = 0.1
set_cell_score(state, action, temp[action])
Q[state] = temp
for (i, j, c, w) in specials:
for action in actions:
Q[(i, j)][action] = w
set_cell_score((i, j), action, w)
render_grid()
master.bind("<Up>", call_up)
master.bind("<Down>", call_down)
master.bind("<Right>", call_right)
master.bind("<Left>", call_left)
me = board.create_rectangle(player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10, fill="sandy brown",
width=1, tag="me")
board.grid(row=0, column=0)
#t = threading.Thread(target=run)
#t.setDaemon(True)
#t.start()
running = True
alpha = 1
t = 1
run() # run at once
#master.after(100, run) # run after 100ms
master.protocol("WM_DELETE_WINDOW", on_delete)
start_game()
我在 PyCharm 中根据我的需要调整此 code,它运行良好,没有任何异常和错误。当我在 Jupyter Notebook 中尝试它时它起作用了,但是当我关闭 Tkinter window 时,我得到异常 Exception in thread Thread-:
和错误 RuntimeError: main thread is not in main loop
.
追溯是:第 90 行,在 运行 - 第 51 行,在执行操作 - 第 30 行,在 try_move
我试图找到解决方案,但我只找到了 Python2 的 mtTkinter。
由于我是线程的新手,我不知道如何解决这个问题,也不知道为什么它只显示在 Jupyter Notebook 中。 Jupyter Notebook 是否可能是问题的根源?
密码是:
from tkinter import *
import threading
import time
def render_grid():
global specials, walls, WIDTH, x, y, player
for i in range(x):
for j in range(y):
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="misty rose", width=1)
temp = {}
cell_scores[(i, j)] = temp
for (i, j, c, w) in specials:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill=c, width=1)
for (i, j) in walls:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="wheat4", width=1)
def set_cell_score(state, action, val):
global cell_score_min, cell_score_max
def try_move(dx, dy):
global player, x, y, score, walk_reward, me, restart
if restart:
restart_game()
new_x = player[0] + dx
new_y = player[1] + dy
score += walk_reward
if (new_x >= 0) and (new_x < x) and (new_y >= 0) and (new_y < y) and not ((new_x, new_y) in walls):
board.coords(me, new_x * WIDTH + WIDTH * 2 / 10, new_y * WIDTH + WIDTH * 2 / 10, new_x * WIDTH + WIDTH * 8 / 10,
new_y * WIDTH + WIDTH * 8 / 10)
player = (new_x, new_y)
for (i, j, c, w) in specials:
if new_x == i and new_y == j:
score -= walk_reward
score += w
if score > 0:
print("Success! score: ", score)
else:
print("Fail! score: ", score)
restart = True
return
# print "score: ", score
def call_up(event):
try_move(0, -1)
def call_down(event):
try_move(0, 1)
def call_left(event):
try_move(-1, 0)
def call_right(event):
try_move(1, 0)
def restart_game():
global player, score, me, restart
player = (0, y - 1)
score = 1
restart = False
board.coords(me, player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10)
def has_restarted():
return restart
def start_game():
master.mainloop()
master = Tk()
master.resizable(False, False)
cell_score_min = -0.2
cell_score_max = 0.2
WIDTH = 100
(x, y) = (5, 5)
actions = ["up", "down", "left", "right"]
board = Canvas(master, width=x * WIDTH, height=y * WIDTH)
player = (0, y - 1)
score = 1
restart = False
walk_reward = -0.04
walls = [(1, 1), (1, 2), (2, 1), (2, 2)]
specials = [(4, 1, "salmon1", -1), (4, 0, "medium sea green", 1)]
cell_scores = {}
discount = 0.3
states = []
Q = {}
for i in range(x):
for j in range(y):
states.append((i, j))
for state in states:
temp = {}
for action in actions:
temp[action] = 0.1
set_cell_score(state, action, temp[action])
Q[state] = temp
for (i, j, c, w) in specials:
for action in actions:
Q[(i, j)][action] = w
set_cell_score((i, j), action, w)
def do_action(action):
s = player
r = -score
if action == actions[0]:
try_move(0, -1)
elif action == actions[1]:
try_move(0, 1)
elif action == actions[2]:
try_move(-1, 0)
elif action == actions[3]:
try_move(1, 0)
else:
return
s2 = player
r += score
return s, action, r, s2
def max_Q(s):
val = None
act = None
for a, q in Q[s].items():
if val is None or (q > val):
val = q
act = a
return act, val
def inc_Q(s, a, alpha, inc):
Q[s][a] *= 1 - alpha
Q[s][a] += alpha * inc
set_cell_score(s, a, Q[s][a])
def run():
global discount
time.sleep(1)
alpha = 1
t = 1
while True:
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
time.sleep(0.1)
render_grid()
master.bind("<Up>", call_up)
master.bind("<Down>", call_down)
master.bind("<Right>", call_right)
master.bind("<Left>", call_left)
me = board.create_rectangle(player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10, fill="sandy brown",
width=1, tag="me")
board.grid(row=0, column=0)
t = threading.Thread(target=run)
t.setDaemon(True)
t.start()
start_game()
可能所有 GUI 都不喜欢在线程中 运行 并且小部件中的所有更改都应该在主线程中(但计算仍然可以在单独的线程中)
在 tkinter
中,您可以使用 master.after(milliseconds, function_name)
而不是 thread
和 while
- 定期循环到 运行 代码 - 这将像循环一样工作但是在当前线程中。
def run():
global t
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
# run again after 100ms
master.after(100, run)
然后作为正常功能启动它
#master.after(100, run) # run after 100ms
run() # run at once
start_game()
完整的工作代码:
编辑:
您也可以使用全局变量 - 即。 running = True
- 在销毁 GUI 之前停止循环。
当你点击关闭按钮[X]
master.protocol("WM_DELETE_WINDOW", on_delete)
来执行功能
from tkinter import *
#import threading
import time
def render_grid():
global specials, walls, WIDTH, x, y, player
for i in range(x):
for j in range(y):
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="misty rose", width=1)
temp = {}
cell_scores[(i, j)] = temp
for (i, j, c, w) in specials:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill=c, width=1)
for (i, j) in walls:
board.create_rectangle(i * WIDTH, j * WIDTH, (i + 1) * WIDTH, (j + 1) * WIDTH, fill="wheat4", width=1)
def set_cell_score(state, action, val):
global cell_score_min, cell_score_max
def try_move(dx, dy):
global player, x, y, score, walk_reward, me, restart
if restart:
restart_game()
new_x = player[0] + dx
new_y = player[1] + dy
score += walk_reward
if (new_x >= 0) and (new_x < x) and (new_y >= 0) and (new_y < y) and not ((new_x, new_y) in walls):
board.coords(me, new_x * WIDTH + WIDTH * 2 / 10, new_y * WIDTH + WIDTH * 2 / 10, new_x * WIDTH + WIDTH * 8 / 10,
new_y * WIDTH + WIDTH * 8 / 10)
player = (new_x, new_y)
for (i, j, c, w) in specials:
if new_x == i and new_y == j:
score -= walk_reward
score += w
if score > 0:
print("Success! score: ", score)
else:
print("Fail! score: ", score)
restart = True
return
# print "score: ", score
def call_up(event):
try_move(0, -1)
def call_down(event):
try_move(0, 1)
def call_left(event):
try_move(-1, 0)
def call_right(event):
try_move(1, 0)
def restart_game():
global player, score, me, restart
player = (0, y - 1)
score = 1
restart = False
board.coords(me, player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10)
def has_restarted():
return restart
def start_game():
master.mainloop()
def do_action(action):
s = player
r = -score
if action == actions[0]:
try_move(0, -1)
elif action == actions[1]:
try_move(0, 1)
elif action == actions[2]:
try_move(-1, 0)
elif action == actions[3]:
try_move(1, 0)
else:
return
s2 = player
r += score
return s, action, r, s2
def max_Q(s):
val = None
act = None
for a, q in Q[s].items():
if val is None or (q > val):
val = q
act = a
return act, val
def inc_Q(s, a, alpha, inc):
Q[s][a] *= 1 - alpha
Q[s][a] += alpha * inc
set_cell_score(s, a, Q[s][a])
def run():
global t
# Pick the right action
s = player
max_act, max_val = max_Q(s)
(s, a, r, s2) = do_action(max_act)
# Update Q
max_act, max_val = max_Q(s2)
inc_Q(s, a, alpha, r + discount * max_val)
t += 1.0
if has_restarted():
restart_game()
time.sleep(0.01)
t = 1.0
# run again after 100ms
if running:
master.after(100, run)
def on_delete():
global running
running = False
master.destroy()
# --- main ---
master = Tk()
master.resizable(False, False)
cell_score_min = -0.2
cell_score_max = 0.2
WIDTH = 100
(x, y) = (5, 5)
actions = ["up", "down", "left", "right"]
board = Canvas(master, width=x * WIDTH, height=y * WIDTH)
player = (0, y - 1)
score = 1
restart = False
walk_reward = -0.04
walls = [(1, 1), (1, 2), (2, 1), (2, 2)]
specials = [(4, 1, "salmon1", -1), (4, 0, "medium sea green", 1)]
cell_scores = {}
discount = 0.3
states = []
Q = {}
for i in range(x):
for j in range(y):
states.append((i, j))
for state in states:
temp = {}
for action in actions:
temp[action] = 0.1
set_cell_score(state, action, temp[action])
Q[state] = temp
for (i, j, c, w) in specials:
for action in actions:
Q[(i, j)][action] = w
set_cell_score((i, j), action, w)
render_grid()
master.bind("<Up>", call_up)
master.bind("<Down>", call_down)
master.bind("<Right>", call_right)
master.bind("<Left>", call_left)
me = board.create_rectangle(player[0] * WIDTH + WIDTH * 2 / 10, player[1] * WIDTH + WIDTH * 2 / 10,
player[0] * WIDTH + WIDTH * 8 / 10, player[1] * WIDTH + WIDTH * 8 / 10, fill="sandy brown",
width=1, tag="me")
board.grid(row=0, column=0)
#t = threading.Thread(target=run)
#t.setDaemon(True)
#t.start()
running = True
alpha = 1
t = 1
run() # run at once
#master.after(100, run) # run after 100ms
master.protocol("WM_DELETE_WINDOW", on_delete)
start_game()