make modifications instantly in tkinter - python

I created a program used by several users via a hosting system.
The purpose of this program is when a user A click on the button change value, the buttons Color change and Generate text change state ( normal to disable) instantly.
The users B must see the changement when they click on the tab 1 without restarting the program. The users don't have to restart the program to see the change. But here, my code works but the users have to restart the program to see the change made by other users...
I don't want that. Is there any solution?
Thank you
from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkinter.ttk import *
import sqlite3
root = Tk()
conn = sqlite3.connect( '/database' )
c = conn.cursor()
query = "SELECT var FROM state WHERE id=1"
c.execute( query )
var = c.fetchall()[0][0]
tab = ttk.Notebook( root ) # create notebook
tab.pack( expand = True, fill = tk.BOTH )
def changevalue() :
global var
query = "SELECT var FROM state WHERE id=1"
c.execute( query )
var = c.fetchall()[0][0]
if var == 1 :
query = "UPDATE state SET var=0 WHERE id=1"
conn.execute( query )
conn.commit()
button_1['state'] = 'normal'
button_2['state'] = 'normal'
if var == 0 :
query = "UPDATE state SET var=1 WHERE id=1"
conn.execute( query )
conn.commit()
button_1['state'] = 'disabled'
button_2['state'] = 'disabled'
# create Frames for tab
frame1 = ttk.Frame( tab )
frame1.pack( fill = "both" )
frame2 = ttk.Frame( tab )
frame2.pack( fill = "both" )
frame3 = ttk.Frame( tab )
frame3.pack( fill = "both" )
# Add frames
tab.add( frame1, text = 'Mytab1' )
tab.add( frame2, text = 'Mytab2' )
tab.add( frame3, text = 'Mytab3' )
# Button in each tab
button_1 = Button( frame1, text = "Color change" ).pack()
button_2 = Button( frame2, text = "Generate text" ).pack()
button_3 = Button( frame3, text = "change value", command = changevalue ).pack()
if var == 1 :
button_1 = Button( frame1, text = "Color change", state = 'disabled' )
button_2 = Button( frame2, text = "Generate text", state = 'disabled' )
else :
button_1 = Button( frame1, text = "Color change", state = 'normal' )
button_2 = Button( frame2, text = "Generate text", state = 'normal' )
root.mainloop()

Since you have used sqlite3 table to share the state across processes, you should check the table and update the state of the buttons periodically using after().
Below is a modified code:
import tkinter as tk
from tkinter import ttk
import sqlite3
conn = sqlite3.connect("/database")
c = conn.cursor()
def get_value():
c.execute("SELECT var FROM state WHERE id = 1")
return c.fetchone()[0]
def change_value():
c.execute("UPDATE state SET var = 1 - var WHERE id = 1")
conn.commit()
def check_value():
state = 'disabled' if get_value() == 1 else 'normal'
button_1.config(state=state)
button_2.config(state=state)
root.after(100, check_value)
root = tk.Tk()
tab = ttk.Notebook(root)
tab.pack(fill='both', expand=1)
frame1 = ttk.Frame(tab)
frame2 = ttk.Frame(tab)
frame3 = ttk.Frame(tab)
tab.add(frame1, text='Mytab1')
tab.add(frame2, text='Mytab2')
tab.add(frame3, text='Mytab3')
button_1 = ttk.Button(frame1, text='Color change')
button_1.pack()
button_2 = ttk.Button(frame2, text='Generate text')
button_2.pack()
ttk.Button(frame3, text='Change value', command=change_value).pack()
check_value() # check value and update state of buttons periodically
root.mainloop()
Note that:
better to avoid using from xxx import *
you don't need to call .pack() on those frames
you should split button_1 = Button(...).pack() into two lines, same applies on button_2

Related

Python Tkinter mixing radio and default user input box in canvas?

I like to mixed my radio button selection with a few user input boxes.
I managed to output them separately but I can't combine them due to the one using canvas1.pack and another using row.pack.
This is my first radio button interface where user will select Auto or Manual and there is a box for user to input stock symbols manually.
This interface by default will show the default parameters such as volume or dividend amount and the user can change this parameter.
When I tried to put them together, they overlaps. The stock symbol input box was also shifted down. How can I move the parameter boxes below the auto and manual radio button without shifting the stock symbol box to the bottom?
Below is a sample of my code that is ready to be executed on jupyter.
from tkinter import *
from tkinter import simpledialog
from tkinter import messagebox
import tkinter as tk
#default filter values
parameter1 = 100000
parameter2 = 3
global answer
global user_list
# Prepare parameters
fields = ['Min. parameter1', 'Min. parameter2', 'Min. 3parameter3',
'Min. parameter4','Min. parameter5', 'Max. parameter6']
default_values = [parameter1,parameter2,parameter3,parameter4,
parameter5,parameter6]
captured_values = []
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
sys.stdout = orig_stdout
f.close()
sys.exit("Application closed by user")
def makeform(root, fields,default_values):
entries = {}
for i in range(len(fields)):
row = tk.Frame(root)
lab = tk.Label(row, width=24, text=fields[i]+": ", anchor='w')
ent = tk.Entry(row)
ent.insert(0, default_values[i])
row.pack(side=tk.TOP,
fill=tk.X,
padx=5,
pady=5)
lab.pack(side=tk.LEFT)
ent.pack(side=tk.RIGHT,
expand=tk.YES,
fill=tk.X)
entries[fields[i]] = ent
return entries
# Button click event
def btn_click (e):
global answer
answer_choice = rdo_var.get()
answer = rdo_txt[answer_choice]
global user_list
user_list = entry1.get()
captured_values.append(e['Min. parameter1'].get())
captured_values.append(e['Min. parameter2'].get())
captured_values.append(e['Min. parameter3'].get())
captured_values.append(e['Min. parameter4'].get())
captured_values.append(e['Min. parameter5'].get())
captured_values.append(e['Max. parameter6'].get())
root.destroy()
return answer
# Generate Tk class
root = tk.Tk()
# Screen size
root.geometry ('270x250')
# Screen title
root.title ('Enter parameters')
# set default parameters
ents = makeform(root, fields, default_values)
# box for manual input
canvas1 = tk.Canvas(root, width = 350, height = 400)
canvas1.pack()
entry1 = tk.Entry (root)
canvas1.create_window(165, 45, window=entry1)
# List radio button labels
rdo_txt = ['Auto','Manual']
# Radio button status
rdo_var = tk.IntVar ()
# Create and place radio buttons dynamically
for i in range (len (rdo_txt)):
rdo = Radiobutton (root, value = i, variable = rdo_var, text = rdo_txt [i])
rdo.place (x = 20, y = 15 + (i * 20))
# Create button
confirm_button = tk.Button (root, text = 'Confirm', command = (lambda e=ents: btn_click(e)))
confirm_button.place (x = 180, y = 200)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop ()
if(answer == 'Manual'):
print('Manual run selected.')
manual_run = 1
temp_user_list = []
user_list = user_list.split(',')
for i in range(len(user_list)):
temp_user_list.append(user_list[i].strip().upper())
print('Symbol(s) entered : ' + str(temp_user_list))
else:
manual_run = 0
print('Auto run selected.')
# new captured values
parameter1 = float(captured_values[0])
parameter2 = float(captured_values[1])
Here is an expanded answer.
Complete code example.
from tkinter import *
from tkinter import simpledialog
from tkinter import messagebox
import tkinter as tk
#default filter values
parameter1 = 100000
parameter2 = 2
parameter3 = 3
parameter4 = 4
parameter5 = 5
parameter6 = 6
global answer
global user_list
# Prepare parameters
fields = ['Min. parameter1', 'Min. parameter2', 'Min. parameter3',
'Min. parameter4','Min. parameter5', 'Max. parameter6']
default_values = [parameter1,parameter2,parameter3,parameter4,
parameter5,parameter6]
captured_values = []
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
sys.stdout = orig_stdout
f.close()
sys.exit("Application closed by user")
def makeform(root, fields,default_values):
entries = {}
for i in range(len(fields)):
row = tk.Frame(root)
lab = tk.Label(row, width=28, text=fields[i]+": ", anchor='e')
ent = tk.Entry(row)
ent.insert(0, default_values[i])
row.pack(side=tk.TOP,
fill=tk.X,
padx=5,
pady=5)
lab.pack(side=tk.LEFT)
ent.pack(side=tk.RIGHT,
expand=tk.YES,
fill=tk.X)
entries[fields[i]] = ent
return entries
# Button click event
def btn_click (e):
global answer
answer_choice = rdo_var.get()
answer = rdo_txt[answer_choice]
global user_list
user_list = entry1.get()
captured_values.append(e['Min. parameter1'].get())
captured_values.append(e['Min. parameter2'].get())
captured_values.append(e['Min. parameter3'].get())
captured_values.append(e['Min. parameter4'].get())
captured_values.append(e['Min. parameter5'].get())
captured_values.append(e['Max. parameter6'].get())
root.destroy()
return answer
# Generate Tk class
root = tk.Tk()
# Screen size
root.geometry("410x260")
# Screen title
root.title('Enter parameters')
# set default parameters
ents = makeform(root, fields, default_values)
# box for manual input
manual = makeform(root, ['Manual input'], ["Enter value here"])
entry1 = manual["Manual input"]
entry1["background"] = "yellow" # make it standout
del manual
# List radio button labels
rdo_txt = ['Auto','Manual']
# Radio button status
rdo_var = tk.IntVar()
# Create and place radio buttons dynamically
for i in range (len (rdo_txt)):
rdo = Radiobutton (root, value = i, variable = rdo_var, text = rdo_txt [i])
rdo.place (x = 20, y = 15 + (i * 20))
# Create button
confirm_button = tk.Button (root, text = 'Confirm', command = (lambda e=ents: btn_click(e)))
confirm_button.place (x = 205, y = 220)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
if(answer == 'Manual'):
print('Manual run selected.')
manual_run = 1
temp_user_list = []
user_list = user_list.split(',')
for i in range(len(user_list)):
temp_user_list.append(user_list[i].strip().upper())
print('Symbol(s) entered : ' + str(temp_user_list))
else:
manual_run = 0
print('Auto run selected.')
# new captured values
parameter1 = float(captured_values[0])
parameter2 = float(captured_values[1])

How do I delete or edit records from data base

I apologize in advance for my bad English...
I am new in the programming world so I don't really know what I'm doing. I'm trying to make a basic address book in Python, Tkinter. I managed somehow to write code to add records in the database but cannot write it to delete or edit selected records. Help would be appreciate
import datetime
import tkinter
from tkinter import *
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
import sqlite3
def date_for_humans():
date = datetime.datetime.now().date()
date = str(date)
x = date.split("-")
return x[2] + "." + x[1] + "." + x[0] + "."
# creating windows for show contact
def add():
kontakti = Toplevel()
kontakti.title("Lista kontakta")
kontakti.iconbitmap(r"phonebookicon.ico")
kontakti.geometry("400x500")
kontakti.resizable(False, False)
def submit():
# create data base or connect to one
conn = sqlite3.connect("Imenik.db")
# create cursor
c = conn.cursor()
# insert into a table
c.execute("INSERT INTO Kontakti VALUES (:f_name, :l_name, :number)",
{
"f_name": f_name.get(),
"l_name": l_name.get(),
"number": number.get()
})
# commint changes
conn.commit()
conn.close()
f_name.delete(0,END)
l_name.delete(0, END)
number.delete(0, END)
# creating and coloring top frame
topframe = tk.Frame(kontakti, height=150, bg="#ffffff")
topframe.pack(fill=X)
# creating and coloring bottom farame
bottomframe = tk.Frame(kontakti, height=350, bg="#34ebeb")
bottomframe.pack(fill=X)
# creating text at the top of app:
text2 = Label(kontakti, text="DODAVANJE KONTAKTA", font="ariel 15 bold", bg="#ffffff", fg="black")
text2.place(x=80, y=20)
# creating close button
button1 = Button(kontakti, text="Zatvori prozor", bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=kontakti.destroy)
button1.place(x=295, y=465)
# create text boxes
f_name = Entry(kontakti, width=30)
f_name.place(x=80, y=200, height=20)
l_name = Entry(kontakti, width=30)
l_name.place(x=80, y=230, height=20)
number = Entry(kontakti, width=30)
number.place(x=80, y=260, height=20)
# create text box labels
f_name_label = Label(kontakti, text="Ime", bg="#34ebeb")
f_name_label.place(x=20, y=200)
l_name_label = Label(kontakti, text="Prezime", bg="#34ebeb")
l_name_label.place(x=20, y=230)
number_label = Label(kontakti, text="Broj", bg="#34ebeb")
number_label.place(x=20, y=260)
# create sumbit button
submint_btn = Button(kontakti, text="Dodaj kontakt", bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=submit)
submint_btn.place(x=40, y=320)
def edit():
c.execute("UPDATE Kontakti SET f_name=?, l_name=?, number=? WHERE f_name= ? AND l_name = ? AND number=?",
(new_value_for_f_name, new_value_for_l_name, new_value_for_number, f_name, l_name, number))
conn.commit()
def delete():
f_name = listbox.curselection()[0]
l_name = listbox.curselection()[1]
number = listbox.curselection()[2]
c.execute("DELETE * FROM Kontakti WHERE f_name = ? AND l_name = ? AND number = ?", (f_name, l_name, number))
conn.commit()
def leave():
root.destroy()
# creating a main window:
root = Tk()
root.title("Imenik App")
root.iconbitmap(r"phonebookicon.ico")
root.geometry("650x550")
root.resizable(False, False)
# creating and coloring top frame:
topFrame = tk.Frame(root, height=150, bg="#ffffff")
topFrame.pack(fill=X)
# creating and coloring bottom frame:
bottomFrame = tk.Frame(root, height=500, bg="#34ebeb")
bottomFrame.pack_propagate(False)
bottomFrame.pack(fill=X)
listbox = Listbox(bottomFrame)
listbox.place(x=40, y=40, height=340, width=200)
scrollbar = Scrollbar(bottomFrame)
scrollbar.place(height=340, x=240, y=40)
# Insert elements into the listbox
conn = sqlite3.connect("Imenik.db")
c = conn.cursor()
a = c.execute("SELECT *,oid FROM Kontakti")
records = c.fetchall()
for record in records:
listbox.insert(END, str(record[0]) + " " + str(record[1]))
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
# creating text at the top of app:
text1 = Label(root, text="IMENIK", font="ariel 35 bold", bg="#ffffff", fg="black")
text1.place(x=240, y=40)
# displaying date and time at the top of app:
datel = Label(root, text="Danasnji datum: " + date_for_humans(), font="ariel 10 bold", bg="#ffffff", fg="black")
datel.place(x=450, y=125)
# displaying icon at the top of the app:
image1 = Image.open("phonebook1.png")
image1 = image1.resize((90, 90), Image.ANTIALIAS)
image = ImageTk.PhotoImage(image1)
label1 = tkinter.Label(image=image, bg="#ffffff")
label1.image = image
label1.place(x=80, y=30)
conn.commit()
conn.close()
'''
# create data base or connect to one
conn = sqlite3.connect("Imenik.db")
# create cursor
c = conn.cursor()
# create table
c.execute("""CREATE TABLE kontakti (
first_name txt,
last_name txt,
number integer
)""")
# commint changes
conn.commit()
conn.close()
'''
# adding button 1, add contacts
viewButton = Button(root, text="Dodaj kontakt", pady=10, padx=70, bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=add)
viewButton.place(x=380, y=200)
# adding button 2, edit contacts
addButton = Button(root, text="Izmeni kontakt", pady=10, padx=67, bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=edit)
addButton.place(x=380, y=260)
# adding button 3, delete contacts
deleteButton = Button(root, text="Obrisi kontakt", pady=10, padx=70, bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=delete)
deleteButton.place(x=380, y=320)
# adding button 4, exit button
exitButton = Button(root, text="Izlaz", pady=5, padx=50, bg="white", fg="black",
activebackground="#A9A9A9", font=("Helvetica", 10, "bold"), command=leave)
exitButton.place(x=505, y=510)
root.mainloop()
If anything is unclear please ask I really need help.
Thanks in advance!
Hi and welcome to Stack Overflow. For you to know which data is selected with the mouse, you can use the following way:
name_of_listbox.curselection()
This will return a list of the contents of the rows currently selected. It gives us a list because there is an option to select multiple rows of data in a ListBox.
You can iterate through each and grab the data out of them.
Store the data in a variable and use them for UPDATE and DELETE commands.
EDIT:
For deleting records:
f_name = listbox.curselection()[0]
l_name = listbox.curselection()[1]
number = listbox.curselection()[2]
c1.execute("DELETE * FROM Kontakti WHERE f_name = ? AND l_name = ? AND number = ?", (f_name, l_name, number))
conn1.commit()
For modifying the values:
c1.execute("UPDATE Kontakti SET f_name=?, l_name=?, number=? WHERE f_name= ? AND l_name = ? AND number=?",(new_value_for_f_name,new_value_for_l_name,new_value_for_number, f_name, l_name, number))
conn1.commit()
I quite did not get the way you were selecting first name, last name and number from a single listbox. So I have kept the name of the listbox the same.
You are using literal sql script and basically you can delete and update like below.
An advice ORM (Object Relational Mapping) is more effortless rather than raw query.
For Delete
DELETE <TableName> WHERE Id = <Value>
conn = sqlite3.connect("Imenik.db")
c = conn.cursor()
sql = "DELETE TableName WHERE Id = ?"
id = 1
c.execute(sql, (id,))
For Update
UPDATE <TableName> SET <ColumnName> = <NewValue> WHERE Id = <Value>
conn = sqlite3.connect("Imenik.db")
c = conn.cursor()
sql = "UPDATE TableName SET ColumnName = ? WHERE Id = ?"
id = 1
new_value = 'hello'
# params order left to right (important).
c.execute(sql, (new_value, id))

Tkinter entry output

I am creating a Data finder using a db file and i use tkinter entry. however in the console it returns the output [] and the code is this
import sqlite3
import tkinter
db = sqlite3.connect ('covidjakartadb.db')
window = tkinter.Tk()
window.geometry("500x300")
label = tkinter.Label(window, text="Please enter a area")
label.pack()
entry = tkinter.Entry(window)
entry.pack()
select_all = "SELECT * FROM locations WHERE '%{0}%'".format(entry)
cursor = sqlite3.Cursor(db)
cursor.execute(select_all)
def Search_Completed():
label = tkinter.Label(window, text="aaaaa")
Button = tkinter.Button(window, text="Search data", command=Search_Completed)
Button.pack()
positive = cursor.fetchall()
print (positive)
window.mainloop()
This project is due today so a answer today would be greatful
The code to select from the database needs to be in the search_completed function. As written it runs before the GUI is even open.
The search should be using the contents of the Entry, entry.get() not entry.
import sqlite3
import tkinter
db = sqlite3.connect ('covidjakartadb.db')
window = tkinter.Tk()
window.geometry("500x300")
label = tkinter.Label(window, text="Please enter a area")
label.pack()
entry = tkinter.Entry(window)
entry.pack()
def Search_Completed():
# select_all = "SELECT * FROM locations WHERE '%{0}%'".format(entry)
# select_all = "SELECT * FROM locations WHERE '%{0}%'".format( entry.get() )
# This will work
select_all = "SELECT * FROM locations WHERE City LIKE '%{0}%'".format( entry.get() )
# Or this.
# select_all = "SELECT * FROM locations WHERE City == '{0}'".format( entry.get() )
cursor = sqlite3.Cursor(db)
cursor.execute(select_all)
positive = cursor.fetchall()
print (positive)
label = tkinter.Label(window, text="aaaaa")
Button = tkinter.Button(window, text="Search data", command=Search_Completed)
Button.pack()
window.mainloop()
I'm unable to test the code as I don't have the database so this may have a few errors in it.

How do I get a label to update after function calls within a TopLevel window?

I'm trying to build a toplevel window within python that has a single label within it called "text". It's textvariable is called "v". As you can see, there are 3 function calls within dialogueBox(). What I want the program to do is have the label "text" display the phrase "Event one", wait one second, display the phrase "Event two", wait one second, and then display the phrase "Event three". Instead of doing this, the top level window is opened displaying only "Event three".
I suspect that this is a lambda issue but I'm still not sure how to use it in Tkinter.
from tkinter import*
import time
def event1():
v.set("Event one")
def event2():
v.set("Event two")
def event3():
v.set("Event three")
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
time.sleep(1)
event2()
time.sleep(1)
event3()
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()
You were very close, but your best bet is using the after() method.
Here's your modified code, with comments added:
from tkinter import*
import time
def event1():
v.set("Event one")
root.after(1000, event2) # NEW
def event2():
v.set("Event two")
root.after(1000, event3) # NEW
def event3():
v.set("Event three")
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
#time.sleep(1)
#event2()
#time.sleep(1)
#event3()
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()
The only real change is employing the after method from event1() to call event2(), and from event2() to call event3(). With these after() calls, the last 4 lines in your dialogueBox() go away.
What is happening? Tkinter is a GUI, event-driven system. It doesn't like sitting there and waiting for anything. While you're sleeping, resources are wasted, and the GUI cannot refresh and update itself. By employing the after() method, the GUI can continue doing what it does best: waiting for events and input. The after() method schedules an event to occur later on. When that time comes, the event gets processed. The first arg to after() is the time delay in ms (milliseconds). The second arg is a function name, to be called after the designated time delay.
Now, I said that after() is your best bet, but there is another way to do this, albeit less "polite." You could add .update() method calls to your dialogueBox(), as follows:
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
text.update() # NEW -- RUDE!
time.sleep(1)
event2()
text.update() # NEW -- RUDE!
time.sleep(1)
event3()
The .update() calls rudely tell the GUI, "Stop everything you're doing and do this for me right now!" This will also allow you to see the event1, event2, event3 messages. But the after() is really the better, proper way to do this.
In event1() use root.after(1000, event2) and it will run event2 one second after event1
And you have to remove sleep() and functions event2() event3() from dialog_box()
import tkinter as tk
# --- functions ---
def event1():
v.set("Event one")
root.after(1000, event2) # run event2 after 1000ms (1s)
def event2():
v.set("Event two")
root.after(1000, event3) # run event3 after 1000ms (1s)
def event3():
v.set("Event three")
root.after(1000, close_it) # run close_it after 1000ms (1s)
def close_it():
top.destroy() # close TopLevel window
def dialogue_box():
global v
global top
top = tk.Toplevel()
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = tk.StringVar()
text = tk.Label(top, textvariable=v)
text.pack()
event1() # run event1 at once
# --- main ---
root = tk.Tk()
email = tk.StringVar()
password = tk.StringVar()
title = tk.Label(root, text="Root window", font=11)
title.pack()
label1 = tk.Label(root, text="Username")
label1.pack()
field1 = tk.Entry(root, textvariable=email)
field1.pack()
label2 = tk.Label(root, text="Password")
label2.pack()
field2 = tk.Entry(root, show="*", textvariable=password)
field2.pack()
button = tk.Button(root, text="Get data", command=dialogue_box)
button.pack()
root.mainloop()
See demo of after here, also with itertools "show off"
from tkinter import *
import time
from itertools import cycle
label_iter = cycle(('Event One', 'Event Two', 'Event Three'))
def change_label():
v.set(next(label_iter))
root.after(1000, change_label)
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
root.after(1000, change_label)
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()

Python tkinter: access child widgets of a widget

I have a string 'currentMessage' and a Label to display it.
I have a Toplevel widget, which contains a Text widget to provide new value for 'currentMessage':
from tkinter import *
from tkinter import ttk
root = Tk()
mainFrame = ttk.Frame(root)
mainFrame.grid()
currentMessage = 'current Message'
ttk.Label(mainFrame, text = currentMessage).grid(padx = 10, pady = 10)
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5)
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
theButton = ttk.Button(mainFrame, command = changeValues, text = 'Click')
theButton.grid(padx = 10, pady = 10)
mainFrame.mainloop()
I tried to get the content of 'textBox' Text widget of the Toplevel by using this function:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
But I got an error
'Toplevel' object has no attribute 'textBox'
So how do I access content of the widget 'textBox', which is a child widget of 'popup' (this Toplevel widget is only created when function changeValues() is called)?
I think probably this is what you are looking for -- although I'm just guessing, because you are asking for a solution for a specific problem you think you have, however if I were you I would rethink what exactly do I want to do:
from tkinter import *
from tkinter import ttk
# Create Tk Interface root
root = Tk()
# Initialize mainFrame
mainFrame = ttk.Frame( root )
mainFrame.grid()
# Initialize label of mainframe
theLabel = ttk.Label( mainFrame, text='Current Message' )
theLabel.grid( padx=10, pady=10 )
def createPopup():
# Initialize popup window
popup = Toplevel( mainFrame )
popup.grid()
# Initialize text box of popup window
textBox = Text( popup, width=20, height=5 )
textBox.grid( column = 0, row = 0 )
textBox.insert( END, 'New Message Here' )
# Initialize button of popup window
button = ttk.Button( master = popup,
command = lambda: theLabel.config(text=textBox.get(0.0, END)),
text = 'Update')
button.grid( column=0, row=1, padx=5, pady=5 )
# Initialize button of main frame
theButton = ttk.Button( mainFrame, command=createPopup, text='Click' )
theButton.grid( padx=10, pady=10 )
# Enter event loop
mainFrame.mainloop()
There is a way indeed, like this:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.nametowidget('textBox').get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5, name = 'textBox')
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
You can choose whatever you want for the 'name'.

Categories