Tkinter not displaying default Entry variable until button is added - python

I am trying to create a GUI in Python 3.9.1 with tkinter and am having issues getting a default value to show in an Entry box.
from tkinter import *
from tkinter import ttk
class GUI:
def __init__(self, root, *args):
self.root = root
self.initial_frame = ttk.Frame(self.root)
self.initial_frame.grid(row=0)
ttk.Label(self.initial_frame, text="User question here?").grid(row=1, column=1)
self.ext_len = StringVar(value=4)
ext_len_entry = ttk.Entry(self.initial_frame, textvariable=self.ext_len)
ext_len_entry.grid(row=1, column=2)
root = Tk()
GUI(root)
root.mainloop()
Note: official tkinter docs say to use from tkinter import * and from tkinter import ttk.
See this link and look in the Python section in the step-by-step walkthrough https://tkdocs.com/tutorial/firstexample.html
I've also tried using self.ext_len.set(4) after initializing the entry but before putting it on the grid. I've tried self.ext_len.insert(0,4) as well.
If I add a button with a callback that does nothing, the 4 shows up in the entry box. I found that I don't even have to render it on the grid. Just initializing it is enough. A button without a callback does not work.
Working code:
from tkinter import *
from tkinter import ttk
class GUI:
def __init__(self, root, *args):
self.root = root
self.initial_frame = ttk.Frame(self.root)
self.initial_frame.grid(row=0)
ttk.Label(self.initial_frame, text="User question here?").grid(row=1, column=1)
self.ext_len = StringVar(value=4)
ext_len_entry = ttk.Entry(self.initial_frame, textvariable=self.ext_len)
ext_len_entry.grid(row=1, column=2)
ttk.Button(self.initial_frame, text="Test button", command=self.test_func)
def test_func(self, *args):
pass
root = Tk()
GUI(root)
root.mainloop()
Why does initializing the button cause it to work?

Related

Tkinter independent windows

I have a gui that I wrote with tkinter and I want to call it again with a button how do I do this (They will be independent of each other)
I want to do like this:
import tkinter
root = Tk()
root.title("test")
def testt()
root()
Button(root, text='window +', command=testt).pack()
root.mainloop()
You also have to import some modules as shown.
Try this:
from tkinter import Tk, Button, Toplevel
def testt():
root1 = Toplevel()
root1.mainloop()
Just add TopLevel in test() function.
Code:
import tkinter as tk
root = tk.Tk()
root.title("test")
def testt():
root1 = tk.Toplevel()
tk.Button(root, text='window +', command=testt).pack()
root.mainloop()
Screenshot output:

how to make modern button in tkinter

I want to have abutton like this in tkinter (Modern window 10 buttons):
However, I get this button:
The code for my button is:
from tkinter import Tk,Button
root=Tk()
Button(root,text='OK').pack()
Another alternative to create button is to create a label and bind it to the action functions. In the below example .bind() is used to connect the label with respective function. You can design according to your requirements.
from tkinter import *
def OnPressed(event):
print('Hello')
def OnHover(event):
But.config(bg='red', fg='white')
def OnLeave(event):
But.config(bg='white', fg='black')
root = Tk()
But = Label(root, text='Hi', bg='white', relief='groove')
But.place(x=10, y=10, width=100)
But.bind('<Button-1>', OnPressed)
But.bind('<Enter>', OnHover)
But.bind('<Leave>', OnLeave)
root.mainloop()
The themed widgets are in 'themed Tk' aka ttk.
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
ok = ttk.Button(root, text='OK')
ok.pack()
root.mainloop()
Avoid from tkinter import * as both tkinter and tkinter.ttk define Button and many other widgets.
If you use this on Windows you should get something looking like a native button. But this is a theme and can be changed. On Linux or MacOS you will get a button style that is appropriate to that platform.
vol_up = Button(root, text="+",activebackground='orange',bg='yellow')
vol_up.pack(side='top')

How use event in other file?

I'm prepared two files. First with GUI class. Second file is a script where I want to use a GUI, Databases and Template classes. A Databases and Template classes works. I check it in other scripts.
Questions:
How can I use event(KeyRelase) form GUI class in script?
First:
from tkinter import *
from tkinter.font import Font
from tkinter.ttk import Separator
class GUI:
def __init__(self, master):
self.ent_InventoryNumber = Entry(self.frm_FirstColumn, font=fontStyle, width=35, borderwidth=2, justify=CENTER)
self.ent_InventoryNumber.insert(END, "Wprowadź TUTAJ numer inwentarzowy")
self.ent_InventoryNumber.grid(row=2, column=0, columnspan=2, padx=5, pady=20, ipadx=2, ipady=2)
self.ent_InventoryNumber.bind("<KeyRelease>", lambda x: self.searchChamber())
def searchChamber(self):
return self.ent_InventoryNumber.get()
Second file with script:
import Databases as Db
import Template
from GUI import GUI
def test(a):
print(a)
window = Tk()
myGUI = GUI(window)
window.mainloop()
# test(myGUI.searchChamber()) ???
bind works correctly in you code. Problem is that bind can't get value which you use with return - it can't assing it to any variable and you have to use this value directly in searchChamber or assign to some variable to use it later.
Other problem: when you close window then tkinter destroy all widgets and you have to keep value from Entry in some variable
def searchChamber(self):
self.result = self.ent_InventoryNumber.get()
and later get this variable
test(GUI.result)
In this example I use print() to see if bind executes function after every pressed key. I also use class variable self.result to keep value and use it after closing window.
GUI.py
import tkinter as tk
class GUI:
def __init__(self, master):
self.result = '' # default value as start
self.ent_InventoryNumber = tk.Entry(master)
self.ent_InventoryNumber.insert('end', "Wprowadź TUTAJ numer inwentarzowy")
self.ent_InventoryNumber.grid(row=2, column=0)
self.ent_InventoryNumber.bind("<KeyRelease>", self.searchChamber)
def searchChamber(self, event=None):
self.result = self.ent_InventoryNumber.get()
print('[DEBUG] searchChamber:', self.result)
main.py
import tkinter as tk
from GUI import GUI
window = tk.Tk()
myGUI = GUI(window)
window.mainloop()
print('result:', myGUI.result)

Tkinter troubles - Name frame is not defined

import Tkinter
class Application(Frame):
def __init__(self, master):
Frame.__init__(self,master)
self.grid()
self.CreateWidgets()
def CreateWidgets(self):
self.LoginButton = Button(Self)
self.LoginButton["text"] = "Login"
self.LoginButton.grid()
self.QUIT_Button = Button(self)
self.QUIT_Button["text"] = "Quit"
self.QUIT_Button["command"] = self.quit
self.QUIT_Button["fg"] = "red"
root = Tk()
root.title("Login")
root.geometry("500x500")
app = Application(root)
root.mainloop()
This is the youtube tutorial that I have been following: https://www.youtube.com/watch?v=YCLTv6wh3jE&index=39&list=PLB0701884E5AE1B45
And this is the error that keeps occurring:
Traceback (most recent call last):
File "C:\Users\omer\Desktop\test.py", line 3, in <module>
class Application(Frame):
NameError: name 'Frame' is not defined
I am a complete noob at Python and am still learning so any help would be appreciated.
Frame Tk, and Button are all located in the Tkinter namespace. Thus, you have to qualify them to let Python know where they are1:
import Tkinter
class Application(Tkinter.Frame):
...
Tkinter.Frame.__init__(self, master)
...
self.LoginButton = Tkinter.Button(self)
...
self.QUIT_Button = Tkinter.Button(self)
...
root = Tkinter.Tk()
That, or you could just import the names directly:
from Tkinter import Frame, Tk, Button
1If you decide to use this first solution, it would probably be best to import Tkinter like this:
import Tkinter as tk
That way, the code becomes this:
import Tkinter as tk
class Application(Tkinter.Frame):
...
tk.Frame.__init__(self, master)
...
self.LoginButton = tk.Button(self)
...
self.QUIT_Button = tk.Button(self)
...
root = tk.Tk()
which is a lot more brief.
You need to import Frame, Button, Tk.
You can either explicitly import all of them from Tkinter:
from Tkinter import Frame, Button, Tk
or import everything from Tkinter (which is not a good thing to do):
from Tkinter import *
or leave your import as is (import Tkinter) and get Frame, Button and Tk from the Tkinter namespace, e.g. for Frame:
class Application(Tkinter.Frame):
Even better would be to import tkinter in a universal way that would work for both python2 and python3:
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.grid()
self.CreateWidgets()
def CreateWidgets(self):
self.LoginButton = tk.Button(self)
self.LoginButton["text"] = "Login"
self.LoginButton.grid()
self.QUIT_Button = tk.Button(self)
self.QUIT_Button["text"] = "Quit"
self.QUIT_Button["command"] = self.quit
self.QUIT_Button["fg"] = "red"
root = tk.Tk()
root.title("Login")
root.geometry("500x500")
app = Application(root)
root.mainloop()
Also, you have a typo, replace (watch Self):
self.LoginButton = Button(Self)
with:
self.LoginButton = Button(self)
You have to import Frame in order to use it like you are. As it stands you have imported Tkinter, but that doesn't give you access to Frame, Button or Tk the way you've used them. but you either need to do:
from Tkinter import Frame
or
from Tkinter import * (* means 'all' in this case, though this isn't necessary when only using a few modules)
or you could leave your import statement as is(import Tkinter) and change your code like so:
class Application(Tkinter.Frame):
and
self.LoginButton = Tkinter.Button(Self)
However, I would recommend that if you do this, you do:
import Tkinter as tk
That way, you can do tk.Frame and tk.Button etc.
For any modules that you want to use from Tkinter you need to import them also in the same fashion.
You can do single line imports like so:
from Tkinter import Tk, Frame, Button etc.
Check out this info on importing in Python: http://effbot.org/zone/import-confusion.htm
Well it is a bit late but for someone having same error, be sure there is no tkinter.py file in the folder.
I had this same error too. The issue with mine is I had a file called tkinter.py and that was overriding the built-in file tkinter. So to fix it, I changed my filename to something else.

askdirectory() changes focus to different window

I am using Tkinter to build two windows. One the main one, pressing a button leads to the creation of the second window.
This second window does not get focus immediately when it created. That I am able to fix by calling .focus_force(). However, when I call the askdirectory() function from tkFileDialog, the focus changes back to the first window.
How can I prevent that focus switch from happening, without simply calling focus_force() all over the place?
To replicate problem:
from Tkinter import *
from tkFileDialog import *
class app:
def __init__(self, master):
Button(master, command = make_new).grid()
def make_new(self):
root = Tk()
new = new_win(root)
root.mainloop() #here the focus is on the first window
class new_win:
def __init__(self, master):
f = askdirectory() #even after placing focus on second window,
#focus goes back to first window here
I am using Python 2.7.3. Thanks!
the little-documented wm_attributes method might help:
from Tkinter import *
import tkFileDialog
root = Tk()
top = Toplevel()
top.wm_attributes('-topmost', 1)
top.withdraw()
top.protocol('WM_DELETE_WINDOW', top.withdraw)
def do_dialog():
oldFoc = top.focus_get()
print tkFileDialog.askdirectory()
if oldFoc: oldFoc.focus_set()
b0 = Button(top, text='choose dir', command=do_dialog)
b0.pack(padx=100, pady=100)
def popup():
top.deiconify()
b0.focus_set()
b1 = Button(root, text='popup', command=popup)
b1.pack(padx=100, pady=100)
root.mainloop()

Categories