so like the title says i want to update one StringVar variable based on value from another StringVar variable in tkinter that are in widow separate from the initial one as you will see. I know the code will be messy but bear with it. Initially we create couple of buttons that generate sql scripts that i hardcoded. When i press a button a new window opens where i enter information about a database name, table name, column name... When i enter correct table name in entry2 widget it prints correct columns from the database in function show_columns in string variable str. Let's assume the database name is DATABASE. What i want is to put content of str variable into column variable that's binded to entry3 widget. How do i do that?
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()
I took the liberty of translating your code into an OOP approach. In my opinion, this is easier to read, and you can use instance variables to exchange values between methods within a class without passing them directly. For example, you could introduce the variables database
, table
and column
within __init__
with the prefix self
and then within show_columns
simply set the variable with self.column.set(str)
.
Attention, in my code I have replaced str
with output
, as str
is already used in the standard (type). This version is shown in the method show_columns_v2
.
You can also pass entry3
into the show_columns
method and then insert the result into the entry
using the insert
method. Note here that you have assigned the variable entry3
with the return value of the grid
method, not with the entry
. In my code I fixed this by first creating entry3
and then applying the grid
method to it.
Note: Since I don't have your database, I have set the variable or inserted the value into the entry
in the except
bracket.
Here is my code:
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()
By the way: maybe you should not trigger the show_columns
method via table.trace_add('write'...
, unless you copy the table name into this field. Because if you type the name, the function is triggered with every letter. Instead, you can also insert a button such as 'Search columns', which then triggers the show_columns
method.