这是我的代码。它在Python 3.5.2中,使用tkinter和turtle。
按下按钮显示项目的位置时,乌龟窗口为空白。如果我将关于乌龟的所有代码移动到tkinter窗口后调用mainloop,则在关闭tkinter窗口并且工作正常后会打开乌龟窗口。
如何修复我的代码,以便在按下按钮时显示。
import csv
import collections
from tkinter import *
def direction(n):
import turtle
wn = turtle.Screen() #sets up window
turtle.bgpic("WilleysMap.gif") #loads picture of map
m = turtle.Turtle() #creates arrow
m.speed(100) #sets the speed
m.penup() #lifts pen so no marks are made
m.forward(160)
m.right(90)
m.forward(80)
m.speed(1) #reduces speed so path can be seen
if n == 1:#------------------------------------------------------------------NU 1
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(300)
m.left(90)
m.forward(80)
wn.mainloop()
elif n == 2: #---------------------------------------------------------------NU 2
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(235)
m.left(90)
m.forward(80)
wn.mainloop()
elif n == 3: #---------------------------------------------------------------NU 3
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(180)
m.left(90)
m.forward(80)
wn.mainloop()
elif n == 4: #---------------------------------------------------------------NU 4
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(300)
m.right(90)
m.forward(80)
wn.mainloop()
elif n == 5: #---------------------------------------------------------------NU 5
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(200)
m.right(90)
m.forward(80)
wn.mainloop()
elif n == 6: #---------------------------------------------------------------NU DECK
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.right(90)
m.forward(60)
m.left(90)
m.forward(80)
wn.mainloop()
elif n == 7: #---------------------------------------------------------------PARKING LOT
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.left(90)
m.forward(50)
m.left(45)
m.forward(140)
m.left(45)
m.forward(100)
m.left(45)
m.forward(180)
wn.mainloop()
elif n == 8: #---------------------------------------------------------------HUT AREA
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(80)
m.right(90)
m.forward(40)
wn.mainloop()
elif n == 9: #---------------------------------------------------------------SIDE STRUCTURE 1
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(20)
m.right(90)
m.forward(180)
m.left(90)
m.forward(30)
m.right(90)
m.forward(80)
wn.mainloop()
else: #----------------------------------------------------------------------SIDE STRUCTURE 2
m.pencolor("red")
m.pensize(15)
m.pendown()
m.forward(80)
m.right(90)
m.forward(60)
wn.mainloop()
with open('code.csv') as f: #loads itemDict from the code.csv file
reader1 = csv.reader(f)
itemDict = dict(reader1)
with open('loc.csv') as f: #loads itemLoc from the loc.csv file
reader2 = csv.reader(f)
itemLoc = dict(reader2)
itemLoc['Emerald Green Arborvitae'] = itemLoc.pop('Emerald Green Arborvitae') #corrects error in translation
global find
def evaluate(event):
if entry.get() in itemDict:
res.configure(text = "UPC: " + str(entry.get()) + "\n The " + itemDict[entry.get()] + " can be found at: " + itemLoc[itemDict[entry.get()]], font = "Verdana 15 bold")
else:
res.configure(text = "UPC: " + str(entry.get()) + "\n The UPC you entered is not listed", font = "Verdana 15 bold")
def show():
if itemLoc[itemDict[entry.get()]] == 'NU 1':
direction(1)
elif itemLoc[itemDict[entry.get()]] == 'NU 2':
direction(2)
elif itemLoc[itemDict[entry.get()]] == 'NU 3':
direction(3)
elif itemLoc[itemDict[entry.get()]] == 'NU 4':
direction(4)
elif itemLoc[itemDict[entry.get()]] == 'NU 5':
direction(5)
elif itemLoc[itemDict[entry.get()]] == 'NU DECK':
direction(6)
elif itemLoc[itemDict[entry.get()]] == 'PARKING LOT':
direction(7)
elif itemLoc[itemDict[entry.get()]] == 'HUT AREA':
direction(8)
elif itemLoc[itemDict[entry.get()]] == 'SIDE STRUCTURE 1':
direction(9)
else:
direction(10)
w = Tk()
w.geometry("650x700")
Label(w, text="Type UPC into entry bar. To see a visual representation of the items location, press the 'Show' button.", font = "Verdana 10").pack(anchor=W)
Label(w, text="").pack()
Label(w, text="Please enter UPC of item", font = "Verdana 10").pack()
Label(w, text="you would like to locate", font = "Verdana 10").pack()
Label(w, text="and press 'Enter'", font = "Verdana 10").pack()
entry = Entry(w)
entry.focus_set()
entry.bind("<Return>", evaluate)
entry.pack()
Label(w, text="").pack()
Button(w, text ="Show", command=show).pack()
Label(w, text="").pack()
res = Label(w)
res.pack()
Label(w, text="Scroll down to see all listed UPCs", font = "Verdana 10").pack()
scrollbar = Scrollbar(w)
scrollbar.pack(side=RIGHT, fill=Y)
T = Text(w, height=15, width=75, bg = 'blue', fg = 'white')
T.pack()
quote = ''
with open('code.csv', newline='') as f:
reader = csv.reader(f)
for row in reader:
quote += ("" + row[0] + ' '*(13-len(row[0])) + row[1] + '\n')
T.insert(END, quote)
scrollbar.config(command=T.yview)
w.mainloop()
修改 问题在于
行turtle.bgpic("WilleysMap.gif")
如果我在它前面放一个#,代码工作正常,乌龟图形只是在白色屏幕而不是地图上绘制。有谁知道如何解决这个错误?
顺便说一下,数据加载只是一个两个合并的CSV文件。好像: Arborvitate,ARB1 金柳,GW34 等等 等
修改 这是我得到的错误
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lucas\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "x-wingide-python-shell://86210440/2", line 173, in show
File "x-wingide-python-shell://86210440/2", line 29, in direction
File "<string>", line 8, in bgpic
File "C:\Users\lucas\AppData\Local\Programs\Python\Python35-32\lib\turtle.py", line 1482, in bgpic
self._setbgpic(self._bgpic, self._bgpics[picname])
File "C:\Users\lucas\AppData\Local\Programs\Python\Python35-32\lib\turtle.py", line 738, in _setbgpic
self.cv.itemconfig(item, image=image)
File "<string>", line 1, in itemconfig
File "C:\Users\lucas\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 2418, in itemconfigure
return self._configure(('itemconfigure', tagOrId), cnf, kw)
File "C:\Users\lucas\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 1321, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage2" doesn't exist
答案 0 :(得分:1)
最后我运行你的代码。
您有错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1540, in __call__
return self.func(*args)
File "<pyshell#6>", line 141, in show
direction(1)
File "<pyshell#6>", line 27, in direction
wn.mainloop()
AttributeError: '_Screen' object has no attribute 'mainloop'
您尝试执行wn.mainloop()
,但wn
没有方法mainloop()
,但turtle
有 - 所以您需要turtle.mainloop()
BTW:您可以缩短代码并将turtle.mainloop()
置于所有if/elif/else
但后台的turtle
使用tkinter
来显示窗口而tkinter
只能运行一个mainloop()
,而您已经w.mainloop()
,因此您不需要turtle.mainloop()
需要global find
BTW: find = some_variable
没有创建全局变量。在函数外部创建的所有变量都是全局的 - 因此您只需要
global
函数内部使用 RawTurtle
来通知函数使用外部变量而不是创建本地变量。
编辑:修改示例。
因为我没有您的数据,所以我只创建了一个名称为#34;示例&#34;。
我必须使用tk.Canvas
与tk.Toplevel
和canvas
来更好地控制与龟的窗口。但是你可以直接在主窗口中使用pack(pady=20)
(没有`tk.Toplevel&#39;)并且只有一个窗口。
我使用 'NU 1': 'f20 r90 f180 r90 f300 l90 f80',
在标签之间留出空间。
我用文字来描述曲目。
import tkinter as tk
from tkinter import messagebox
import turtle
def draw_track(track):
win = tk.Toplevel()
canvas = tk.Canvas(win, width=500, height=500)
canvas.pack()
m = turtle.RawTurtle(canvas)
# move to start
m.speed(100)
m.penup()
m.forward(160)
m.right(90)
m.forward(80)
m.speed(1)
# draw
m.pencolor("red")
m.pensize(15)
m.pendown()
# split text into command
track = track.split()
# execute commands
for element in track:
cmd = element[0]
number = int(element[1:])
if cmd == 'f':
m.forward(number)
elif cmd == 'r':
m.right(number)
elif cmd == 'l':
m.left(number)
def evaluate(event):
if entry.get() in itemDict:
text="UPC: {}\nThe {} can be found at: {}".format(entry.get(), itemDict[entry.get()], itemLoc[itemDict[entry.get()]])
else:
text="UPC: {}\nThe UPC you entered is not listed".format(entry.get())
res.configure(text=text, font="Verdana 15 bold")
def show():
text = entry.get().strip()
if text in item_dict:
track = data[item_loc[item_dict[text]]]
draw_track(track)
else:
messagebox.showwarning("Warning", "No '{}' in dictionary".format(text))
# --- main ---
# - data -
item_dict = {'example': 1}
item_loc = {1: 'NU 1'}
data = {
'NU 1': 'f20 r90 f180 r90 f300 l90 f80',
'NU 2': 'f20 r90 f180 r90 f235 l90 f80',
'NU 3': 'f20 r90 f180 r90 f180 l90 f80',
'NU 4': 'f20 r90 f180 r90 f300 r90 f80',
'NU 5': 'f20 r90 f180 r90 f200 r90 f80',
'NU DECK': 'f20 r90 f180 r90 f60 l90 f80',
'PARKING LOT': 'f20 l90 f50 l45 f140 l45 f100 l45 f180',
'HUT AREA': 'f20 r90 f80 r90 f40',
'SIDE STRUCTURE 1': 'f20 r90 f180 l90 f30 r90 f80',
'SIDE STRUCTURE 2': 'f80 r90 f60',
}
# - gui -
root = tk.Tk()
font = "Verdana 10"
l = tk.Label(root, text="Type UPC into entry bar.\nTo see a visual representation of the items location, press the 'Show' button.", font=font)
l.pack()
l = tk.Label(root, text="Please enter UPC of item\nyou would like to locate\nand press 'Enter'", font=font)
l.pack(pady=20)
entry = tk.Entry(root)
entry.pack()
entry.bind("<Return>", evaluate)
entry.focus_set()
b = tk.Button(root, text="Show", command=show)
b.pack(pady=20)
root.mainloop()
代码:
class InteropExamples {
/* note: these delegates fields must be kept alive in a real class too,
or else GC can collect them.
*/
// One method has out, the other [Out] attribute (in order, A out, B [Out])
readonly TryGetLocationA _tryGetLocationA;
readonly TryGetLocationB _tryGetLocationB;
// One method has ref IntPtr, the other IntPtr[] (in order, A ref IntPtr, B IntPtr[])
readonly IsEntityValidA _isEntityValidA;
readonly IsEntityValidB _isEntityValidB;
readonly int _mainThreadID;
public bool InvokeRequired => GetCurrentThreadId() != _mainThreadID;
public InteropExamples() {
var addressOne = IntPtr.Zero; // real address of the func here of course.
var addressTwo = IntPtr.Zero; // real address of the func here of course.
_tryGetLocationA =
Marshal.GetDelegateForFunctionPointer(addressOne, typeof(TryGetLocationA)) as TryGetLocationA;
_tryGetLocationB =
Marshal.GetDelegateForFunctionPointer(addressOne, typeof(TryGetLocationB)) as TryGetLocationB;
_isEntityValidA =
Marshal.GetDelegateForFunctionPointer(addressTwo, typeof(IsEntityValidA)) as IsEntityValidA;
_isEntityValidB =
Marshal.GetDelegateForFunctionPointer(addressTwo, typeof(IsEntityValidB)) as IsEntityValidB;
_mainThreadID = System.Diagnostics.Process.GetCurrentProcess().Threads[0].Id;
}
// This way works as expected with no limits.
// delegate void TryGetLocationA(IntPtr address, out Vector3 result);
public Vector3 GetLocationA(IntPtr address) {
Vector3 location;
// note: Invoke(_tryGetLocationA, address, out location) is not possible here.
_tryGetLocationA(address, out location);
return location;
}
// In this example, we use a trick to be able to
// use the out despite using params object[] args
// not allowing you to pass out or ref.
// delegate void TryGetLocationB(IntPtr address, [Out] Vector3[] result);
public Vector3 GetLocationB(IntPtr address) {
// note: if your delegate signature -
// has out and not the attribute [Out]
// it will fail.
var location = new Vector3[1];
// The result gets passed to the first index of the array, 0.
// Use our special invoke method with params object[] thus not allowing -
// us to use out directly like in example A.
Invoke(_tryGetLocationB, address, location);
return location[0];
}
// This way works fine and as expected.
public bool IsEntityValid_A(IntPtr entityAddress) {
// note: (bool) Invoke(_isEntityValidA, ref entityAddress) is not valid here.
return _isEntityValidA(ref entityAddress);
}
public bool IsEntityValid_B(IntPtr entityAddress) {
// note: no ref tag needed here, unlike the [Out] example.
// The array trick allows us to once again by pass the limit -
// of not being able to use ref in params object[] (or params of any kind).
var isEntityValid = (bool) Invoke(_isEntityValidB, new[] {entityAddress});
return isEntityValid;
}
// An example of why we might want to invoke unmanaged funcs with -
// a generic method using params[] object[] args, which sadly -
// with out using tricks will not allow use of out/ref signatures.
// Work arounds exist and shown in this class.
object Invoke<T>(T target, params object[] args) where T : class {
var targetDelegate = target as Delegate;
if (targetDelegate == null) {
throw new ArgumentException("Target method is not a delegate type.");
}
if (!InvokeRequired) {
return targetDelegate.DynamicInvoke(args);
}
var callback = new InvokeDelegateTarget {
Target = targetDelegate,
Args = args
};
/* notify some class to invoke your delegate */
Helper.ProcessDelegate(callback);
/* while callback.Result == null {} or what ever check you do */
return callback.Result;
}
[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate void TryGetLocationB(IntPtr address, [Out] Vector3[] result);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate void TryGetLocationA(IntPtr address, out Vector3 result);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate bool IsEntityValidA(ref IntPtr entityAddress);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate bool IsEntityValidB(IntPtr[] entityAddress);
}