I need to change the content of an entry whenever the tkinter frame is shown. Below is what I have so far, and it doesn't seem to work. I have tried to use data = self.read() and then now.insert(0, data) and that has not worked either. If the value is displayed then it doesn't get changed every time the class ReadLabel1 is called.
class ReadLabel1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent, bg="blue")
label = tk.Label(self, text="SomeData:", font = "Times 12", bg="blue")
label.place(x=10, y=100) #ack(pady=5,padx=30)
self.smStr = tk.StringVar()
now=tk.Entry(self, width=22, textvariable=self.read())
now.place(x=120, y=103)
def read(self):
# code to get data
return data
You need to turn 'change the content of an entry' into a one parameter callback, turn 'whenever the tkinter frame is shown' into an event, and then bind together the app, the event, and the callback. Here is a minimal example.
import time
import tkinter as tk
root = tk.Tk()
now = tk.StringVar()
lab = tk.Label(root, textvariable=now)
lab.pack()
def display_now(event):
now.set(time.ctime())
root.bind('<Visibility>', display_now)
root.bind('<FocusIn>', display_now)
Minimizing the window to a icon and bringing it back up triggers the Visibility event. Covering and merely uncovering with a different window did not, at least not with Windows. Clicking on the uncovered, or merely inactivated, window triggered FocusIn. You can experiment more with your system. I used this tkinter reference
Related
When I click on a label to open an external window (tertiary.py), the window opens normally but is empty inside. I don't get errors, but I don't see Tkinter widgets and miscellaneous items.
This is the secondary window where there is the label on which I click in order to open an external window. I add, for information purposes only, that this window is called secondary because it is displayed in a frame (with a vertical menu on the left) where the main window is called home = tk.Tk(). The secondary window opens and displays correctly in the frame.
Inside the secondary window there is the label thanks to which I want to open an external window (not in the frame) called tertiary
How can I solve?
secondary.py
import tkinter as tk
from tkinter import *
from tkinter import ttk
import other_options
from other_options import form_other_options
class Page2(tk.Frame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
self.configure(bg='white')
bar1=Frame(self, width=2200, height=35, background="#960000", highlightbackground="#b40909", highlightthickness=0) #grigio chiaro #b40909
bar1.place(x=0, y=0)
other_options = Label(self, text="Other Options", bg="#960000", foreground='white', font='Ubuntu 10')
other_options.place(x=1025, y=7)
other_options.bind("<Button-1>", lambda event: other_options.form_other_options(self))
tertiary.py
from tkinter import *
from tkinter import ttk
import tkinter as tk
def form_other_options(parent):
other_options = tk.Toplevel(parent)
other_options.title("Other options")
other_options.geometry("1000x800")
other_options.config(bg="white")
other_options.state("normal")
other_options.transient(parent)
class checkbox():
def __init__(self, master, **kw):
super().__init__(master, **kw)
labelframe1 = LabelFrame(self, text="checkbox", width=600,height=190, bg="white", foreground='#e10a0a')
labelframe1.place(x=10, y=13)
Checkbutton1 = IntVar()
Button1 = Checkbutton(self, text = "option1",
variable = Checkbutton1,
onvalue = 1,
offvalue = 0,
height = 2,
width = 10)
Button1.pack()
other_options.mainloop()
The first reason why the window is empty is that you never create an instance of the class checkbox, so the code that creates the widgets never runs.
So, the first step is to make sure you create an instance of that class:
other_options = tk.Toplevel(parent)
...
cb = checkbox(other_options)
When you do that, you will discover other bugs in your code. The first positional argument when creating a tkinter widget must be another widget. If you want the widget to be inside a Toplevel, the parent needs to be the toplevel or a descendant. You're using self which isn't a widget at all.
A simple fix is to use master instead of self, since you're passing the toplevel window as the master parameter:
labelframe1 = LabelFrame(master, ...)
Button1 = Checkbutton(master, ...)
You also need to remove the call to other_options.mainloop(). Unless there is a very compelling reason to do otherwise, an entire application should only call mainloop() exactly once.
There are other problems in the code that, strictly speaking, aren't related to the question being asked. For example, you're importing tkinter twice: once as import tkinter as tk and once as from tkinter import *. You only need to import tkinter once, and PEP8 recommends to use the first form:
import tkinter as tk
You'll need to add the prefix tk. to every place where you call a tkinter function. This will help make your code easier to understand and helps prevent pollution of the global namespace.
You also should use PEP8 naming standards. Specifically, class names should begin with an uppercase character. This will also make your code easier to understand.
There's also no reason why your checkbox class should be indented. You should move it out of the function.
Also, instead of checkbox not inheriting from anything, and then creating a LabelFrame, you should just inherit from LabelFrame. That way you can use your class more like a real widget, and would enable you to use self rather than master when creating the other widgets.
class Checkbox(tk.LabelFrame):
def __init__(self, master, **kw):
super().__init__(master, **kw)
...
button1 = tk.Checkbutton(self, ...)
...
There are probably other problems, but those are the most obvious.
I am trying to open a toplevel widget from a button press, and generate a list within that frame from an example I found. However, when I try to place the widget within the generated frame, I get the following error:
_tkinter.TclError: can't put .!treeview inside .!errorexample.!toplevel.!mclistdemo.!frame.!frame
I have narrowed down the problem to
self.tree.grid(in_=f, row=0, column=0, sticky=NSEW)
within the _create_treeview method. When the in_ command is removed, the widget is generated correctly in the parent window. I suspect that the problem has something to do with my parent/self naming conventions, but I am still struggling to grasp that subject.
Most of the questions I've run across that are described similarly seem to be a matter of trying to place the widget while generating it, but that doesn't seem to be the case in this code.
from tkinter import *
from tkinter import ttk
from tkinter.font import Font
class ErrorExample(Frame):
def __init__(self, parent):
Frame.__init__(self,parent)
self.grid()
self.parent=parent
self.b4=Button(
self,
text="Load",
command=lambda: self.createWindow())
self.b4.grid()
def createWindow(self):
self.t = Toplevel(self)
MCListDemo(self)
class MCListDemo(ttk.Frame):
def __init__(self, parent, isapp=True):
ttk.Frame.__init__(self, parent.t)
self.grid()
self.isapp = isapp
self._create_widgets()
def _create_widgets(self):
if self.isapp:
self._create_demo_panel()
def _create_demo_panel(self):
demoPanel = Frame(self)
demoPanel.grid()
self._create_treeview(demoPanel)
self._load_data()
def _create_treeview(self, parent):
f = ttk.Frame(parent)
f.grid()
self.dataCols = ('country', 'capital', 'currency')
self.tree = ttk.Treeview(columns=self.dataCols,
show = 'headings')
self.tree.grid(in_=f, row=0, column=0, sticky=NSEW)
start=Tk()
ErrorExample(start)
if __name__=="__main__":
main()
You don't give the treeview a parent, so it has the root window as a parent. Widgets live in a hierarchy, and widget's can't be placed in a different part of the hierarchy.
The official documentation describes it like this:
The master for each slave must either be the slave's parent (the default) or a descendant of the slave's parent. This restriction is necessary to guarantee that the slave can be placed over any part of its master that is visible without danger of the slave being clipped by its parent.
If you want the treeview to be in f, the simplest way is to make f be the parent:
self.tree = ttk.Treeview(f, ...)
self.tree.grid(row=0, column=0, sticky=NSEW)
I want to create a multiple page app but have troubles with raising different frames above another. I have followed sentdex's tutorials on this and tried a lot of different approaches but have a problem with all frame widgets being displayed on the same frame, not on different frames as I wanted.
The button and "Start page text" should be on the first frame and once I press the button I should invoke another frame to be raised above this one. The second frame's text ("Question page text") should let you know you are on another frame.
This does not happen. Both texts as well as the button are displayed on the same frame.
You can run the code bellow to see what I mean.
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Verdana", 12)
class Quiz(Tk):
frames = []
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self, height=50, width=90)
self.frames.append(container)
container.pack()
self.show_frame(StartPage(container, self))
def show_subject(self):
container = self.frames[0]
self.show_frame(self, Question(container, self))
def show_frame(self, frame):
frame.tkraise()
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
text = Text(width=40, height=2, spacing1=15)
text.insert(INSERT, "Start page text")
text.pack()
button = ttk.Button(text="Geo", command=Quiz.show_subject(Quiz)).pack(fill=X)
class Question(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
text = Text(width=40, height=2, spacing1=15)
text.insert(INSERT, "Question page text")
text.pack()
app = Quiz()
app.mainloop()
Any suggestions would be very appreciated because I have been trying to solve this problem for quite some time now.
One of the cornerstones of the design you are copying is that everything within a page should be a child of that page. That's the whole point -- each "page" is treated as a self-contained widget. You aren't doing that.
If you want something to appear on a specific page, make it part of the page. If it's supposed to be visible globally, don't put it on one of the pages. Instead, stick it in the root window.
I create a check button / box, with the following call
x=ttk.Checkbutton(tab1,state='disabled',command = lambda j=i,x=k: fCheckButton(j,x))
x.state(['selected'])
The box appears fine and is selected, but it appears on load up, with a black box in it, which seems to have nothing to do with the state of it.
I have looked for reasons why, but can't actually find anyone with the same problem.
thanks
I hit this problem when creating a Checkbutton object from within a class. I was declaring a local variable instead of a member variable in the class. The local variable was getting out of scope causing the checkbox value to not be either a 0 or a 1.
Wrong:
import tkinter as Tk
from tkinter import IntVar
from tkinter.ttk import Frame, Checkbutton
class TestGui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
var1 = IntVar()
var1.set(1)
button = Checkbutton(parent,
text="Pick me, pick me!",
variable=var1)
button.grid()
root = Tk.Tk()
app = TestGui(root)
root.mainloop()
Fixed:
import tkinter as Tk
from tkinter import IntVar
from tkinter.ttk import Frame, Checkbutton
class TestGui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.var1 = IntVar()
self.var1.set(1)
button = Checkbutton(parent,
text="Pick me, pick me!",
variable=self.var1) # note difference here
button.grid()
root = Tk.Tk()
app = TestGui(root)
root.mainloop()
I've had a similar issue on Windows 7.
After loading the app, one of my checkbuttons contained a filled square. But after clicking on it, it became a normal checkbutton:
In my case, it was because I had multiple checkbuttons sharing the same variable... After creating a separate Tk.IntVar() variable for each checkbutton, the problem disappeared.
import Tkinter as Tk
import ttk
root = Tk.Tk()
checkVar = Tk.IntVar()
x = ttk.Checkbutton(root, variable=checkVar, text="check 1")
x.pack()
checkVar2 = Tk.IntVar()
y = ttk.Checkbutton(root, variable=checkVar2, text="check 2")
y.pack()
root.mainloop()
def createWidgets(self):
self.INSTRUCTIONS = Button(self) #creating button linked to instructions_window
self.INSTRUCTIONS["text"] = "Instructions"
self.INSTRUCTIONS["fg"] = "green"
self.INSTRUCTIONS["command"] = self.instruction_window #command which opens instructions_window
self.INSTRUCTIONS.pack({"side": "left"})
Currently, if I press the button multiple times then the instructions window will open multiple times. How do I ensure that when the button is pressed, if the window is already open then it will flash to show that the same window can't be opened. Is there a command? Or do I need to use a validation of some sort?
Here's a great article dealing with more complicated examples of dialog boxes.
Essentially what you are looking for is almost like a modal dialog window except it seems with the additional ability to still interact with the parent window to a degree. At this point it may be worth considering making it totally modal, but I do not know your use case. If not, you can definitely adapt the scripts given on the tutorial website to fit your needs.
The way I do this is to create a function that will create the window if it doesn't exist, and then display the window. Personally I don't think there's a need to flash the window, but you could do that if you want. Tkinter doesn't know how to flash a window, but you can do something simple like changing the colors briefly.
Here's an example:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.instruction_window = None
self.instructions = tk.Button(self, text="Instructions", foreground="green",
command=self.show_instructions)
self.instructions.pack(side="left")
def show_instructions(self):
'''show the instruction window; create it if it doesn't exist'''
if self.instruction_window is None or not self.instruction_window.winfo_exists():
self.instruction_window = InstructionWindow(self)
else:
self.instruction_window.flash()
class InstructionWindow(tk.Toplevel):
'''A simple instruction window'''
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.text = tk.Text(self, width=40, height=8)
self.text.pack(side="top", fill="both", expand=True)
self.text.insert("end", "these are the instructions")
def flash(self):
'''make the window visible, and make it flash temporarily'''
# make sure the window is visible, in case it got hidden
self.lift()
self.deiconify()
# blink the colors
self.after(100, lambda: self.text.configure(bg="black", fg="white"))
self.after(500, lambda: self.text.configure(bg="white", fg="black"))
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()