小能豆

如何将变量从顶层窗口获取到主窗口?

py

我有一个代码,可以获取键盘输入并将其显示在主窗口顶层窗口的输入框上。在主窗口中,我有一个列表框,我希望在顶层按下确认按钮时,获取输入框上显示的键盘输入。

我尝试了多种方法来进入evt.keysym我的列表框但都失败了。

class EntryBox(tk.Entry):
    def __init__(self, master, cnf = {}, **kw):
        kw = tk._cnfmerge((kw, cnf))
        kw['justify'] = kw.get('justify', 'center')
        kw['width'] = 15
        kw['state'] = 'readonly'
        super(EntryBox, self).__init__(master=master, **kw)
        self.unbind_class('Entry', '<BackSpace>')
        self.unbind_class('Entry', '<Key>')
        self.bind_class(self, '<Key>', self._display)

    def _display(self, evt):
        self['state'] = 'normal'
        self.delete('0', 'end')
        self.insert('0', str(evt.keysym))
        self['state'] = 'readonly'

class Keyboard:
    def __init__(self):
        self.kb = tk.Toplevel()

        kb_frame = ttk.Frame(self.kb)
        kb_frame.grid(column=0, row=1, pady=(7, 19))
        ttk.Label(kb_frame, text='Enter Key').grid(column=0, row=0, pady=4)
        entry = EntryBox(kb_frame)
        entry.grid(column=0, row=1)

        # Confirm button
        self.co_button = ttk.Button(self.kb, text='Confirm')
        self.co_button.grid(column=0, row=2)

class Main:
    def __init__(self):
        self.win = tk.Tk()
        # listbox
        lb_frame = tk.Frame(self.win)
        lb_frame.grid(column=0, row=0)
        scrollbar = tk.Scrollbar(lb_frame, orient='vertical')
        scrollbar.grid(column=1, row=0, sticky='NS', pady=(12, 4))
        listbox = tk.Listbox(lb_frame, selectmode='extended', width=25, 
                             height=16,
                             yscrollcommand=scrollbar.set, activestyle='none')
        listbox.grid(column=0, row=0, sticky='NSEW', padx=(6, 0), pady=(12, 4))
        scrollbar.config(command=listbox.yview)

        # button to open toplevel
        bt_frame = ttk.Frame(self.win)
        bt_frame.grid(column=2, row=0, rowspan=2)

        self.kb_button = ttk.Button(bt_frame, text='KeyBoard', command=KeyBoard)
        self.kb_button.grid(column=0, row=0)

main = Main()
main.win.mainloop()

阅读 16

收藏
2024-12-09

共1个答案

小能豆

您的代码中的问题是,EntryBox 类的 self.insert('0', str(evt.keysym)) 会在键盘输入时替换整个输入框的内容,而 evt.keysym 是按键的符号名称(如 'a''Enter' 等),这可能并不是您希望的内容。要正确获取输入框中的值并将其传递到主窗口中的 Listbox,您需要按照以下步骤进行修改。

主要问题:

  1. 键盘事件的处理:您通过 self.insert('0', str(evt.keysym)) 直接在输入框中显示键盘符号,这不允许您正常输入和显示字符。您需要确保将按键输入添加到已有文本中,而不是覆盖整个文本。
  2. 获取输入框的内容:当确认按钮按下时,您需要从 EntryBox 获取键盘输入并将其显示在主窗口的 Listbox 中。

改进的代码:

  1. 修改 EntryBox 类,确保字符按下时被添加到输入框中的已有文本,而不是覆盖文本。
  2. 通过 confirm 按钮的回调函数,将输入框中的文本传递给主窗口中的 Listbox

以下是修改后的代码:

import tkinter as tk
from tkinter import ttk

class EntryBox(tk.Entry):
    def __init__(self, master, cnf = {}, **kw):
        kw = tk._cnfmerge((kw, cnf))
        kw['justify'] = kw.get('justify', 'center')
        kw['width'] = 15
        kw['state'] = 'normal'  # Allow normal input, not readonly
        super(EntryBox, self).__init__(master=master, **kw)
        self.bind_class(self, '<Key>', self._display)  # Bind to key event

    def _display(self, evt):
        """ This method is called when a key is pressed in the EntryBox """
        # Append the key pressed to the current text
        current_text = self.get()
        new_text = current_text + evt.keysym
        self.delete(0, 'end')  # Clear the current text
        self.insert(0, new_text)  # Insert the new text


class Keyboard:
    def __init__(self, master, listbox):
        self.kb = tk.Toplevel(master)

        kb_frame = ttk.Frame(self.kb)
        kb_frame.grid(column=0, row=1, pady=(7, 19))

        ttk.Label(kb_frame, text='Enter Key').grid(column=0, row=0, pady=4)
        self.entry = EntryBox(kb_frame)
        self.entry.grid(column=0, row=1)

        # Confirm button
        self.co_button = ttk.Button(self.kb, text='Confirm', command=lambda: self.confirm(listbox))
        self.co_button.grid(column=0, row=2)

    def confirm(self, listbox):
        """ When the confirm button is pressed, add the input text to the Listbox """
        input_text = self.entry.get()  # Get the text from the EntryBox
        listbox.insert(tk.END, input_text)  # Insert the text into the Listbox
        self.kb.destroy()  # Close the keyboard window


class Main:
    def __init__(self):
        self.win = tk.Tk()

        # Listbox setup
        lb_frame = tk.Frame(self.win)
        lb_frame.grid(column=0, row=0)
        scrollbar = tk.Scrollbar(lb_frame, orient='vertical')
        scrollbar.grid(column=1, row=0, sticky='NS', pady=(12, 4))
        self.listbox = tk.Listbox(lb_frame, selectmode='extended', width=25, 
                                  height=16, yscrollcommand=scrollbar.set, activestyle='none')
        self.listbox.grid(column=0, row=0, sticky='NSEW', padx=(6, 0), pady=(12, 4))
        scrollbar.config(command=self.listbox.yview)

        # Button to open the keyboard
        bt_frame = ttk.Frame(self.win)
        bt_frame.grid(column=2, row=0, rowspan=2)

        self.kb_button = ttk.Button(bt_frame, text='KeyBoard', command=lambda: Keyboard(self.win, self.listbox))
        self.kb_button.grid(column=0, row=0)

        self.win.mainloop()

# Start the program
main = Main()

主要修改:

  1. EntryBox:我们在 _display 方法中确保每次按下按键时,将字符添加到现有文本中,而不是覆盖它。self.get() 获取输入框中的当前文本,然后将按键符号添加到其末尾。
  2. Keyboard:添加了 confirm 方法,它在点击确认按钮时,将 EntryBox 中的文本插入到主窗口的 Listbox 中,并且关闭键盘窗口。
  3. MainKeyboard 类的实例现在接收 self.listbox 作为参数,这样它可以在 confirm 方法中访问并修改 Listbox 中的内容。

解释:

  • 按键处理:按键事件会将按下的键的符号(evt.keysym)添加到输入框中,并且文本显示会随着按键的输入而更新。
  • 确认按钮:在点击确认按钮时,EntryBox 中的文本会被传递到主窗口中的 Listbox,并且键盘窗口会被关闭。

结果:

当您点击 “KeyBoard” 按钮时,您会看到弹出一个新的输入框窗口,允许您输入键盘符号并将其添加到 Listbox 中。

2024-12-09