我在绑定功能方面遇到了麻烦。使用Dijkstra算法找到最短路径,我想要它,所以当两个comboxbox选择一个字母时,它会打印出结果,但我不知道如何去做。当我尝试运行它时,它会显示错误" shortestPath()只需要2个参数(给定1个)"。
from Tkinter import *
import ttk
import heapq
# GUI of the program.
class app():
def __init__(self):
self.root = Tk()
self.fill_Combo()
self.root.mainloop()
def fill_Combo(self):
self.combo1= ttk.Combobox(self.root,height=5, width=20)
self.combo1['values'] = ('a','b','w','x','y','z')
self.combo1.current(0)
self.combo1.place(x=5, y = 75)
self.combo1.bind("<<ComboboxSelected>>",self.shortestPath)
self.combo2= ttk.Combobox(self.root,height=5, width=20)
self.combo2['values'] = ('a','b','w','x','y','z')
self.combo2.current(0)
self.combo2.place(x=5, y=100)
self.combo2.bind("<<ComboboxSelected>>",self.shortestPath)
# Dijkstra's algorithm function.
def shortestPath(start, end):
queue,seen = [(0, start, [])], set()
while True:
(cost, v, path) = heapq.heappop(queue)
if v not in seen:
path = path + [v]
seen.add(v)
if v == end:
return cost, path
for (next, c) in graph[v].iteritems():
heapq.heappush(queue, (cost + c, next, path))
graph = {
'a': {'w': 16, 'x': 9, 'y': 11},
'b': {'w': 11, 'z': 8},
'w': {'a': 16, 'b': 11, 'y': 4},
'x': {'a': 9, 'y': 12, 'z': 17},
'y': {'a': 11, 'w': 4, 'x': 12, 'z': 13},
'z': {'b': 8, 'x': 17, 'y': 13},
}
cost, path = shortestPath(x, y)
print cost, path
app()
答案 0 :(得分:1)
(修改后反映您在问题中对代码所做的不可忽视的更改,并且更加面向对象。)
实际上,您问题中当前的代码会在NameError: name 'x' is not defined
语句中引发cost, path = shortest_path(x, y)
,并且只有在修复后才会引发类似您提及的shortestPath() takes exactly 2 arguments (1 given)
。
问题是你需要定义一个正确的Tkinter
事件处理函数,它被定义为通常只接收一个参数(如果它恰好是一个类方法,除了self
),即触发它们的event
。
因此,在这种情况下,错误的原因是:shortestPath()
期望将x
和y
值传递给它,但它只收到一个 - "<<ComboboxSelected>>"
来自Tkinter
的活动。
这就是我的意思:
from Tkinter import *
import ttk
import heapq
# Program GUI
class App(object):
def __init__(self):
self.root = Tk()
self.graph = {
'a': {'w': 16, 'x': 9, 'y': 11},
'b': {'w': 11, 'z': 8},
'w': {'a': 16, 'b': 11, 'y': 4},
'x': {'a': 9, 'y': 12, 'z': 17},
'y': {'a': 11, 'w': 4, 'x': 12, 'z': 13},
'z': {'b': 8, 'x': 17, 'y': 13},
}
self.termini = {} # storage for node ids of each terminus
self.create_gui_widgets()
self.root.mainloop()
def create_gui_widgets(self):
values = tuple(self.graph.keys()) # valid node ids
self.combo1 = self.create_combobox('start', values, 5, 75, 5, 20)
self.combo2 = self.create_combobox('end', values, 5, 100, 5, 20)
def create_combobox(self, terminus, values, x, y, height, width):
" Utility to create ComboBox of node ids for a terminus of route. "
combobox = ttk.Combobox(self.root, height=height, width=width)
combobox['values'] = values
combobox.terminus = terminus
combobox.current(0)
self.termini[combobox.terminus] = combobox.get() # set to current value
combobox.place(x=x, y=y)
combobox.bind("<<ComboboxSelected>>", self.combobox_event_handler)
return combobox
def combobox_event_handler(self, event):
" Event handler for both ComboBoxes. "
combobox = event.widget # ComboBox triggering event
self.termini[combobox.terminus] = combobox.get() # set selected node id
# if both a start and end terminus are defined and different, then
# find and display shortest path between them
start, end = self.termini.get('start'), self.termini.get('end')
if start and end and start != end:
cost, path = self.shortest_path(start, end)
print('cost: {}, path: {}'.format(cost, path))
# Dijkstra's search algorithm
def shortest_path(self, start, end):
graph = self.graph # copy to local var for faster access
queue, seen = [(0, start, [])], set()
while True:
cost, v, path = heapq.heappop(queue)
if v not in seen:
path = path + [v]
seen.add(v)
if v == end:
return cost, path
for next, c in graph[v].iteritems():
heapq.heappush(queue, (cost + c, next, path))
App()
答案 1 :(得分:0)
错误表明您的函数需要两个参数,这是真的。一个人被传入的原因仅仅是因为绑定是如何工作的。在tkinter中,当您创建绑定并且绑定触发时,该函数始终获取一个参数,该参数是包含该事件信息的对象。
解决方案很简单:为接受事件的组合框编写一个新函数,收集所需信息,然后进行计算。您不需要实际使用事件对象,但您需要接受它。
您选择使用面向对象的体系结构使这很容易实现:
self.combo1.bind("<<ComboboxSelected>>",self.on_combobox)
self.combo2.bind("<<ComboboxSelected>>",self.on_combobox)
...
def on_combobox(self, event):
start = self.combo1.get()
end = self.combo2.get()
self.shortestPath(start, end)
请注意,此解决方案假定shortestPath
是对象上的方法。您已按原样缩进,但未定义采用self
参数。如果要将其称为对象方法,则应该为其指定self
:
def shortestPath(self, start, end):
...
发布的代码还存在一些其他问题,但它们与提出的问题无关。我想提供另一条建议:避免使用place
。与使用pack
或grid
相比,它使您的GUI更难编写和维护,并且使用place
使您的GUI不太容忍系统之间的差异。例如,在我的机器上,组合框被切断,因为您计算的坐标不适合我的机器。您通常不会遇到grid
和pack
的问题。