How to correctly use Control Variable in Tkinter? - python

I just started to look into tkinter to develop some simple GUI applications. However, I had a hard time figuring out how the control variables are used. I simply want to retrieve the status of a checkbutton(whether it is checked) and the text of an entry, but using the control variable seems not doing the job. I know my_entry.get() can also be used to get the text, but since most of the tutorials use control variables, I believe it is worth learning to use it correctly... Really appreciate your help!
here is the sample code I had:
import tkinter as tk
def checkbtn_callback():
print(btn_state.get())
print(entry_text.get())
top = tk.Tk()
btn_state = tk.IntVar()
checkbtn=tk.Checkbutton(top,text='testbutton',variable=btn_state,command=checkbtn_callback)
checkbtn.grid()
entry_text = tk.StringVar()
entry = tk.Entry(top, text='text entry',textvariable=entry_text)
entry.grid()
tk.mainloop()

Related

Unable to update Label text in Python Tkinter without calling pack() again

from tkinter import *
from tkinter.ttk import *
root = Tk()
first_run = True
def update(txt):
global first_run
text1 = Label(root, text='')
if first_run:
text1.pack()
text1['text'] = txt
first_run = False
update('1')
update('2')
update('3')
root.mainloop()
When I run this, the text stays at '1', and the following 2 function calls are ignored. I find out that only if I use pack() again then it will be updated, but it creates a duplicate label and I do not want that.
Of course, I know that I am supposed to use a StringVar, but I have been using this method for all other widgets (buttons, label frames etc) and all of them works. I do not know why this particular case does not work.
Running on Python 3.9.9 on Windows 11
You aren't updating the label, you are creating a new label each time the function is called. To update any widget, use the configure method. For that, you need to create the label outside of the function (or, leave it in the function but add logic so that it's only created once). Usually it's best to create it outside the function so that the function is only responsible for the update.
from tkinter import *
from tkinter.ttk import *
root = Tk()
def update(txt):
text1.configure(text=txt)
text1 = Label(root, text='')
text1.pack()
update('1')
update('2')
update('3')
root.mainloop()
Note: since you call your function multiple times before the window is drawn you'll only see the final value. There are plenty of solutions to that on this site. Without knowing more about what your real program looks like it's hard to recommend the best solution to that problem.

Python Tkinter updating text-box content via a function

Beginner programmer here, working on making a basic GUI as part of a tutorial I was following online, but none of them say how to get a Text box to update using the output of the other parts of your code.
I tried multiple other answers on the site, including one using StringVar's, which got me nowhere, another using a decorator, and the rest seemed way out of my depth.
Here's my code:
import tkinter as tk
import time
#Creating Root
root = tk.Tk()
#GUI TEMPLATE
frame =tk.Frame(root,
height = 100,
width = 400)
frame.pack()
v = StringVar()
colour = ["red","blue","green","white","yellow"]
labels = range(5)
#change number to change how many labels
for i in range(5):
l= tk.Label(root,
text = colour[i],
bg = colour[i])
l.place(x = 10 +i*70, y = 10, width=60, height=25)
T1 = tk.Text(root, height=2, width=40)
words = "Don't name your files after module names!"
T1.insert(tk.END, textvariable=v)
T1.place(x = 10, y= 40)
S = tk.Scrollbar(root)
S.config(command=T1.yview)
S.place(x = 340, y=40)
T1.config(yscrollcommand=S.set)
root.mainloop()
v.set("Something Else!")
Now, what it should output is a row of coloured labels, which works fine, and a text box with a scroll bar, which should instantly update to read 'Something Else!', which does not work fine.
Instead I get the following error:
NameError: name 'StringVar' is not defined
I know what this error means, it's just I've hit a wall when it comes to finding a solution that works for me, and doesn't need a doctorate to understand.
What I'm asking for is if someone can give me a solution that would work for this, and hopefully explain it!
Thanks in advance.
EDIT:
So after fixing the syntax error, and then finding out what I'm trying to do doesn't work, how would I go about this?
Could I use a label instead? Or is there another, better way?
Thanks again!
StringVar should accessed via tk:
v = tk.StringVar()
On another note, tk.Text.insert does not take a textvariable parameter, so the following won't work:
T1.insert(tk.END, textvariable=v)
# ^^^^^^^^^^^^??
From the docs:
Unlike for example the entry widget, text widgets don't support a
"textvariable" configuration option
Also see How can I connect a StringVar to a Text widget in Python/Tkinter? as to why this won't work.
I was experimenting with learning threading with Tkinter and have made something work to insert and update text in a Tkinter text box in Python3 which may be of help.
I found that by deleting the text I could then insert new text. Untill I deleted the existing text the instruction to insert text seamed to be ignored.
{ foo = input("Give me input: " )
self.T.delete("1.0", END) #Clear the text window so we can write.
self.T.insert(END,foo) #Write the new text.}

tkinter optionmenu swapping place

After googling and searching in SO, I come here.
I am making a program, but when I run it, the optionMenu widgets go to the end of the display, despite being set on the grid on the program. Here's a relevant example:
from tkinter import *
root=Tk()
root.title("Generador documentos")
app=Frame(root)
app.grid()
sexoPat=Label(app, text ="Gender")
sexoPat.grid(row=0,column=0)
var1 = StringVar()
sexoPatDrop= OptionMenu(root,var1,'Male','Female')
sexoPatDrop.grid(row=1,column=0)
sexoPatCheck=var1.get()
nombPat=Label(app, text ="name here")
nombPat.grid(row=2,column=0)
nombPatTXT=Entry(app)
nombPatTXT.grid(row=3,column=0)
In this sample code, I needed to write app instead of root in OptionMenu(root,...)
It was furas who gave me the answer.

How do I run a program within a Tkinter frame?

I'm trying to create a Tkinter app that incorporates the use of a touchscreen keyboard and will be run off a Raspberry Pi. I found an onscreen keyboard called Matchbox-keyboard.
My question is: is there a way to "embed" this keyboard into a GUI created by Tkinter? I would like to embed the keyboard so it opens at the bottom of the parent window.
So far all I can come up with is:
subprocess.Popen(['matchbox-keyboard'])
which works, but it opens in a separate window.
Below is a sample of my code. Keep in mind that I haven't coded the get() functions for the text fields yet, or any of the other functions for that matter.
from tkinter import *
from tkinter import ttk
import subprocess
process_one = subprocess.Popen(['matchbox-keyboard'])
root = Tk()
bottomframe = Frame(root)
bottomframe.pack(side = BOTTOM)
root.title("PinScore")
L0 = Label(root, text = "Welcome to PinScore!")
L0.pack(side = TOP)
L1 = Label(root, text = "Initials:")
L1.pack(side = LEFT)
E1 = Entry(root, bd = 5)
E1.pack(side = RIGHT)
L2 = Label(root, text = "High Score:")
L2.pack( side = RIGHT)
E2 = Entry(root, bd = 5)
E2.pack(side = RIGHT)
B = Button(bottomframe, text = "Enter High Score")
B.pack(side = BOTTOM)
root.mainloop()
The short answer: no, but there is hope, and it will require a fair amount of work. According to the github it is made in gtk. Then the question becomes "Can I put a gtk object in my tkinter program?". To my knowledge (and a lot of Googling) there is no way to embed gtk features in the Tkinter. You may want to try pyGTK instead, because these would be much easier to integrate (I know that it is possible). I might suggest that before you get any further in your project.
Use PyGTK! The github contains the gtk source and you can do it that way.
Actually, looking more at the github, you may not need to do that. The keyboard allows for command-line options, such as -v,--override Absolute positioning on the screen and -g,--geometry <HxW.y.x> Specify keyboard's geometry (taken from the github). You won't be able to control the z position (as in whether it is above or below your window).
If you truely want the embeded feeling, the github also says that you can embed it in gtk and points to examples/matchbox-keyboard-gtk-embed.c this might be what your looking for. You probably can translate it to pygtk. I found this, which talks about XEMBED. And I found this too which actually embeds something. Finally, I'll point you to the docs for gtk.socket.

Good-styled console input

I'm writing a little Chatserver/-client to learn Python.
Now I want to make the consoleinput a little bit nicer, but I don't know how to do it...
Everytime I recieve a message from the socket, I do print() in the listening thread.
But then the text already entered to input() is over the printed message and the cursor is at the bottom.
What can I do, that is works like in Minecraft-Server, so the text already entered moves to the bottom?
Would be great if someone can help :)
You can't get that level of control with the console, but you can use python's default tkinter to make a simple UI. Below is an example (Python 3) that I whipped up in a few minutes. You can type in messages, press send, and they will appear in the box above.
from tkinter import *
from tkinter import ttk
def send(view, entry):
view.insert('1.0', entry.get() + "\n")
root = Tk()
msgview = Text(root, width=100, height=20)
msgview.grid(sticky=(N,E,S,W))
mymessage = StringVar(value="type here...")
msginput = Entry(root, textvariable=mymessage)
msginput.grid(sticky=(E,W))
sendbutton = ttk.Button(root, text="send",\
command=lambda: send(msgview, msginput))
sendbutton.grid()
root.mainloop()
I suggest looking at the tkdocs tutorial over the effbot one, since it is clearer, easier to follow and is more thorough in my opinion. New Mexico Tech also provides a great reference for tkinter here

Categories