关于 python:tkinter 循环遍历 List On Key Press

tkinter Loop Through List On Key Press

我正在尝试使用 tkinter 条目小部件和向上/向下箭头键创建命令历史记录。这是一个非常基本的 MUD 客户端,我想在业余时间想出。

1
2
3
4
5
6
7
8
9
10
11
# The list that hold the last entered commands.
self.previousCommands = []

# Binding the up arrow key to the Entry widget.
self.view.Tabs.tab1.E.bind('<Up>', self.checkCommandHistory)

# The function that should cycle through the commands.
def checkCommandHistory(self, event):
    comm = self.previousCommands[-1]
    self.view.Tabs.tab1.E.delete(0, END)
    self.view.Tabs.tab1.E.insert(0, comm)

基本上,我想要做的是使用向上和向下箭头键循环浏览包含上次输入命令历史的列表。这种行为在大多数 MUD 客户端中很常见,但我无法确切了解这是如何实现的。

使用上面的代码,我可以将向上箭头键按下绑定到 Entry 小部件,并在按下时插入最后输入的命令。如果我要继续按向上箭头键,我希望它继续循环浏览列表中最后输入的命令。


Question: cycle the elements in a list by pressing Up/Down arrow key bound to Entry widget

创建一个继承自 tk.Entryclass object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import tkinter as tk

class EntryHistory(tk.Entry):
    def __init__(self, parent, init_history=None):
        super().__init__(parent)
        self.bind('<Return>', self.add)
        self.bind('<Up>', self.up_down)
        self.bind('<Down>', self.up_down)

        self.history = []
        self.last_idx = None

        if init_history:
            for e in init_history:
                self.history.append(e)
            self.last_idx = len(self.history)

    def up_down(self, event):
        if not self.last_idx is None:
            self.delete(0, tk.END)

            if event.keysym == 'Up':
                if self.last_idx > 0:
                    self.last_idx -= 1
                else:
                    self.last_idx = len(self.history) -1
            elif event.keysym == 'Down':
                if self.last_idx < len(self.history) -1:
                    self.last_idx += 1
                else:
                    self.last_idx = 0

            self.insert(0, self.history[self.last_idx])

    def add(self, event):
        self.history.append(self.get())
        self.last_idx = len(self.history) - 1

if __name__ =="__main__":
    root = tk.Tk()
    entry = EntryHistory(root, init_history=['test 1', 'test 2', 'test 3'])
    entry.grid(row=0, column=0)
    root.mainloop()

用 Python 测试:3.5


这是一个非基于 OOP 的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import tkinter as tk

root = tk.Tk()

history = []
history_index = -1

def runCommand(event):
    command = cmd.get()
    print("Running command: {}".format(command))
    cmd.set("")
    history.append(command)
    history_index = -1
    print(history)

def cycleHistory(event):
    global history_index
    if len(history):
        try:
            comm = history[history_index]
            history_index -= 1
        except IndexError:
            history_index = -1
            comm = history[history_index]
        cmd.set(comm)

cmd = tk.StringVar(root)
e = tk.Entry(root,textvariable=cmd)
e.grid()
e.bind("<Return>",runCommand)
e.bind("<Up>",cycleHistory)
e.focus()

root.mainloop()

基本上,您只需要记录下一次用户按下向上箭头时应该显示的历史记录中的哪个项目。我使用 history_index 字段来执行此操作。 history_index 最初设置为 -1,每次访问它都会减 1。

一旦没有更多历史可从列表中读取并重新从头开始,我使用 except IndexError 异常将索引重置为 -1。

按回车键,运行命令,将其添加到历史记录并将索引重置为-1。