在新窗口中根据另一个StringVar值更新包含StringVar的输入框值

0 投票
1 回答
36 浏览
提问于 2025-04-12 18:34

就像标题说的,我想根据另一个StringVar变量的值来更新一个StringVar变量,这两个变量在不同的窗口中。你会看到的。我知道代码可能会有点乱,但请耐心点。最开始我们创建了几个按钮,这些按钮会生成我写好的SQL脚本。当我按下一个按钮时,会打开一个新窗口,我在里面输入数据库名称、表名、列名等等。当我在entry2这个输入框中输入正确的表名时,函数show_columns会打印出数据库中的正确列名,并把它们放在一个叫str的字符串变量里。假设数据库的名字是DATABASE。我想把str变量的内容放到一个和entry3输入框绑定的列变量里。我该怎么做呢?

def show_columns(table):
    query = f"select * from [DATABASE].[dbo].[{table}] where 1=0"
    cursor = conn.cursor()
    str = ''
    try:
        cursor.execute(query)
        column_names = [column[0] for column in cursor.description]
        for column in column_names: str += f"[{column}],"
        print(str)
    except:
        print('Error!')



def open_window(text, button):
    # Create a new window
    new_window = Toplevel()

    # Set the window title and size
    new_window.title(text)
    new_window.geometry("600x460")
    new_window.config(bg="light gray")
    new_window.resizable(False, False)

    database = StringVar()
    table = StringVar()
    column = StringVar()


    # Create some text fields
    label1 = Label(new_window, text="Database name:").grid(row=0, column=0, pady=5)
    entry1 = Entry(new_window, textvariable=database).grid(row=0, column=1, padx=5, pady=5)

    label2 = Label(new_window, text="Table name:").grid(row=1, column=0, pady=5)
    entry2 = Entry(new_window, textvariable=table).grid(row=1, column=1, padx=5, pady=5)

    label3 = Label(new_window, text="Column name:").grid(row=2, column=0, pady=5)
    entry3 = Entry(new_window, textvariable=column).grid(row=2, column=1, padx=5, pady=5)
    
    table.trace_add('write', lambda name, index, mode, sv=table: show_columns(sv.get()))




window = Tk()

#code for connecting to database


#Set the window title, size and oclor
window.title('SQL script generator')
window.geometry("800x600")
window.config(bg="gray")
window.resizable(False, False)

command_names = ['Delete duplicates while keeping the original', 
                 'Delete duplicates without keeping the original',
                 'Retrive all data from table',
                 'Check for duplicates',
                 'Delete table',
                 'Copy data from one table to another',
                 'Update values',
                 'Add new column to exisitng table']


canvas = Canvas(window)
canvas.pack(side='left', fill='both', expand=True)


# Create two frames
search_frame = Frame(canvas)
search_frame.pack(side='top')
buttons_frame = Frame(canvas)
buttons_frame.pack(side='bottom')
canvas.create_window((0, 0), window=buttons_frame, anchor='nw')


i = 0
for i, text in enumerate(command_names):
    Button(buttons_frame, text=command_names[i], width=40, height=2, command=lambda text = text, index = i: open_window(text, index)).grid(row=i+1, column=0, pady=5, padx=5)
    i += 1


buttons_frame.update_idletasks()
window.mainloop()

1 个回答

1

我把你的代码改成了面向对象编程的方式。在我看来,这样更容易阅读,而且你可以用实例变量在类的方法之间交换值,而不需要直接传递它们。比如,你可以在 __init__ 方法里引入 databasetablecolumn 这些变量,并在前面加上 self,然后在 show_columns 方法里,直接用 self.column.set(str) 来设置变量。

注意,在我的代码里,我把 str 替换成了 output,因为 str 已经在标准库中被使用了。这一版本在 show_columns_v2 方法中展示。

你也可以把 entry3 传入 show_columns 方法,然后用 insert 方法把结果放入 entry 中。这里要注意的是,你是把 entry3 赋值为 grid 方法的返回值,而不是 entry。在我的代码中,我先创建了 entry3,然后再对它应用 grid 方法。

注意:因为我没有你的数据库,所以我在 except 语句块里设置了变量或插入了值到 entry 中。

这是我的代码:

from tkinter import Tk, Toplevel, Label, Entry, Canvas, Frame, Button, StringVar


class GUI(Tk):
    def __init__(self):  # create own GUI class which inherits from Tk → window is now self
        super().__init__()
        # Set the window title, size and oclor
        self.title('SQL script generator')
        self.geometry("800x600")
        self.config(bg="gray")
        self.resizable(False, False)

        command_names = ['Delete duplicates while keeping the original',
                         'Delete duplicates without keeping the original',
                         'Retrive all data from table',
                         'Check for duplicates',
                         'Delete table',
                         'Copy data from one table to another',
                         'Update values',
                         'Add new column to exisitng table']

        canvas = Canvas(self)
        canvas.pack(side='left', fill='both', expand=True)

        # Create two frames
        search_frame = Frame(canvas)
        search_frame.pack(side='top')
        buttons_frame = Frame(canvas)
        buttons_frame.pack(side='bottom')
        canvas.create_window((0, 0), window=buttons_frame, anchor='nw')

        # Create instance variables
        self.database = StringVar(self, value='')
        self.table = StringVar(self, value='')
        self.column = StringVar(self, value='')

        # Create Buttons with loop
        for i, text in enumerate(command_names):
            Button(buttons_frame, text=command_names[i], width=40, height=2,
                   command=lambda: self.open_window(text)).grid(row=i + 1, column=0, pady=5, padx=5)

    def open_window(self, text):
        # Create a new window
        new_window = Toplevel()

        # Set the window title and size
        new_window.title(text)
        new_window.geometry("600x460")
        new_window.config(bg="light gray")
        new_window.resizable(False, False)

        # Create some text fields
        Label(new_window, text="Database name:").grid(row=0, column=0, pady=5)
        entry1 = Entry(new_window, textvariable=self.database)
        entry1.grid(row=0, column=1, padx=5, pady=5)

        Label(new_window, text="Table name:").grid(row=1, column=0, pady=5)
        entry2 = Entry(new_window, textvariable=self.table)
        entry2.grid(row=1, column=1, padx=5, pady=5)

        Label(new_window, text="Column name:").grid(row=2, column=0, pady=5)
        entry3 = Entry(new_window, textvariable=self.column)
        entry3.grid(row=2, column=1, padx=5, pady=5)

        #self.table.trace_add('write', lambda name, index, mode, entry=entry3: self.show_columns(sv.get(), entry))
        # version to set by changing self.column directly
        self.table.trace_add('write', lambda name, index, mode: self.show_columns_v2())

    # version without instance vaiable by inserting to entry directly
    def show_columns(self, entry3):
        table = self.table.get()
        query = f"select * from [DATABASE].[dbo].[{table}] where 1=0"
        output = ''
        try:
            cursor = conn.cursor()
            cursor.execute(query)
            column_names = [column[0] for column in cursor.description]
            for column in column_names:
                output += f"[{column}],"
            print(output)
        except:
            print(f'Error for Table {table}!')
            # test to set entry
            output = 'test'
            entry3.insert(0, output)

    # version 2 setting StringVar directly
    def show_columns_v2(self):
        table = self.table.get()
        query = f"select * from [DATABASE].[dbo].[{table}] where 1=0"
        output = ''
        try:
            cursor = conn.cursor()
            cursor.execute(query)
            column_names = [column[0] for column in cursor.description]
            for column in column_names:
                output += f"[{column}],"
            print(output)
        except:
            print(f'Error for Table {table}!')
            # test to set entry
            output = 'test'
            self.column.set(output)


if __name__ == '__main__':
    gui = GUI()
    gui.mainloop()

顺便说一下:也许你不应该通过 table.trace_add('write'... 来触发 show_columns 方法,除非你把表名复制到这个字段里。因为如果你每输入一个字母,函数就会被触发。相反,你可以插入一个按钮,比如“搜索列”,这样就可以触发 show_columns 方法。

撰写回答