列表框(Listbox)组件用来存放一个列表数据,可以对其数据进行添加和删除操作。
下面使用该组件实现一个栈,在头部进行压栈和出栈操作。为了让例子更加有趣,规定压栈的数据只能从“1,2,3,…,10”这个队列的头部取,也就是第一次压栈的数据是1,第二次压栈的数据是2,以此类推。问仅通过压栈和出栈操作能否得到指定的输出序列,如“10,9,8,7,6,5,4,3,2,1”,也就是说第一次出栈的是10,第二次出栈的是9,以此类推。
import sys
if sys.version_info.major == 3: # Python 3
import tkinter as tk
elif sys.version_info.major == 2: # Python 2
import Tkinter as tk
import random
class DemoApplication(tk.Frame):
def pop(self):
element_num = self.list_box1.size()
if element_num == 0:
print("Error: No Element")
else:
# 栈中有元素
# 得到最后一个元素的值,该类型是字符串类型的
las_val = self.list_box1.get(tk.END)
las_val = int(las_val) # 转换成整数类型
# 将最后一个元素放入输出队列的尾部
self.output_list.append(las_val)
# 删除最后一个元素
self.list_box1.delete(tk.END)
msg = u"输出队列:%s" % self.output_list
self.expected_label['text'] = msg
if element_num == 1:
self.button_pop.config(state=tk.DISABLED)
def push(self):
if self.next_push > 10:
self.button_push.config(state=tk.DISABLED)
else:
# 在尾部添加
self.list_box1.insert(tk.END,str(self.next_push))
self.next_push = self.next_push + 1
if self.next_push > 10:
# 不让入栈了
self.button_push.config(state=tk.DISABLED)
# 如果刚才不让执行出栈操作,那么现在可以进行出栈操作了
print("self.button_pop['state'] = %s" % self.button_pop
['state'])
if self.button_pop['state'] == tk.DISABLED:
self.button_pop.config(state=tk.NORMAL)
def createWidgets(self):
self.expected_val = random.randint(0, 101)
self.list_box1 = tk.Listbox(main_win) # 创建一个列表框
self.list_box1.pack()
self.next_push = 1
self.real_label = tk.Label(main_win, text="")
self.real_label.pack()
self.button_push = tk.Button(main_win)
self.button_push.state = 0
self.button_push["text"] = u"压栈"
self.button_push["command"] = self.push
self.button_push.pack()
self.button_pop = tk.Button(main_win)
self.button_pop.state = 0
self.button_pop["text"] = u"出栈"
self.button_pop["command"] = self.pop
# 最开始,栈中没有元素,所以不可以出栈
self.button_pop.config(state=tk.DISABLED)
self.button_pop.pack()
self.expected_label = tk.Label(main_win, text="输出队列:")
self.expected_label.pack()
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.output_list = []
self.pack()
self.createWidgets()
main_win = tk.Tk() # 创建主窗口
main_win.title(u"栈操作演示") # 设置窗口标题
main_win.geometry("200x300") # 设置窗口大小
app = DemoApplication(master=main_win) # 创建应用程序
app.mainloop() # 进入消息循环
运行后结果如 1 所示。
当全部压栈完成,并且所有元素都出栈时,显示如图 2 所示的界面。
列表框默认只能选中一个元素,但是可以通过设置参数 selectmode 的值为 MULTIPLE 来允许选中多个元素。为了演示这个属性,下面来玩一个游戏,就是在给定的数中挑出一些数,要求这些数的和要尽量接近指定的值 t。
这里用 Listbox 来存放数组 l,用户可以从中任意挑选元素。在挑选的过程中,显示目前挑选数的和。在用户完成挑选后单击“查看答案”按钮可以查看是否得到了正确的结果。
下面是完整的代码:
import sys
if sys.version_info.major == 3:
import tkinter as tk
elif sys.version_info.major == 2:
import Tkinter as tk
import random
class DemoApplication(tk.Frame):
# 背包问题的求解方法
def resolve_bag(self, bag_volume, goods_list):
biggest_valid_vol = 0
biggest_valid_selection = []
goods_num = len(goods_list)
candidate_num = 1 << goods_num
for candidate in range(candidate_num):
selection_decision = []
for x in range(goods_num):
if (candidate & 1) == 1:
selection_decision.append(True)
else:
selection_decision.append(False)
candidate = candidate >> 1
current_vol = 0
for x in range(goods_num):
if selection_decision[x] == True:
current_vol = current_vol + goods_list[x]
if current_vol <= bag_volume and current_vol > biggest_valid_
vol:
biggest_valid_vol = current_vol
biggest_valid_selection = selection_decision
result = [goods_list[x] for x in range(goods_num) \
if biggest_valid_selection[x] == True]
return result
def show_answer(self): # 显示标准答案
answer_list = self.resolve_bag(self.target, self.data)
standard_answer_sum = sum(answer_list)
if abs(self.current_sum-self.target) <= \
abs(standard_answer_sum-self.target):
# 用户的也是标准答案
user_answer_list = [self.data[x] for x in self.list_box1.
curselection()]
answer_label_text = u"标准答案是: %s" % user_answer_list
else:
answer_label_text = u"标准答案是: %s" % answer_list
self.answer_label['text'] = answer_label_text
def selection_evt_handler(self, evt): # 选中某个元素的处理函数
seleted_index_list = self.list_box1.curselection()
sum = 0
for x in seleted_index_list:
sum = sum + self.data[x]
self.current_sum = sum
actual_sum_label_text = u"当前的和为%d" % self.current_sum
self.actual_label['text'] = actual_sum_label_text
def reset(self): # 重新开始
self.generate_data()
expect_label_txt = u"期望的和为%d" % self.target
self.expected_label['text'] = expect_label_txt
self.answer_label['text'] = ""
def generate_data(self): # 产生输入数据
# 一共是8个元素,从0到7,全部删除
self.list_box1.delete(0, 7)
self.data = []
for x in range(8):
v = random.randint(1, 20)
self.data.append(v)
self.target = random.randint(20, 60)
for x in self.data:
self.list_box1.insert(tk.END,str(x))
def createWidgets(self): # 画出初始界面
self.expected_val = random.randint(0, 101)
self.list_box1 = tk.Listbox(main_win)
# 允许选中多个元素
self.list_box1["selectmode"] = tk.MULTIPLE
self.list_box1.pack()
self.list_box1.bind("<<ListboxSelect>>", self.selection_evt_
handler)
self.generate_data()
self.next_push = 1
self.real_label = tk.Label(main_win, text="")
self.real_label.pack()
expect_label_txt = u"期望的和为%d" % self.target
self.expected_label = tk.Label(main_win, text=expect_label_txt)
self.expected_label.pack()
self.current_sum = 0
actual_label_txt = u"当前的和为%d" % self.current_sum
self.actual_label = tk.Label(main_win, text=actual_label_txt)
self.actual_label.pack()
self.answer_label = tk.Label(main_win, text="")
self.answer_label.pack()
self.button_reset = tk.Button(main_win)
self.button_reset.state = 0
self.button_reset["text"] = u"重新开始"
self.button_reset["command"] = self.reset
self.button_reset.pack()
self.button_end = tk.Button(main_win)
self.button_end.state = 0
self.button_end["text"] = u"查看答案"
self.button_end["command"] = self.show_answer
self.button_end.pack()
def __init__(self, master=None): # 初始化函数
tk.Frame.__init__(self, master)
self.output_list = []
self.pack()
self.createWidgets()
main_win = tk.Tk()
main_win.title(u"选中最接近目标的元素组合")
main_win.geometry("250x350")
app = DemoApplication(master=main_win)
app.mainloop()
开始运行时的显示如图 3 所示。
在查看答案时得到如图 4 所示的窗口。