Tkinter - Seperate 'Button' class with different TopLevel - python-3.x

I have a problem with bind_class. I want to bind some events for all buttons in my topLevel mainWindow. But my other topLevel themeWindow's buttons also effected from this.
My code:
root = tk.Tk()
mainWindow = Toplevel(root)
themeWindow = Toplevel(root)
#my buttons and labels
mainWindow.bind_class('Button', '<Enter>', onCursorButton, add='+')
mainloop()
And themeWindow's buttons keep effecting from <Enter> and <Leave> event.

Try this code:
import tkinter as tk
def get_masters(widget):
output = []
while widget.master is not None:
widget = widget.master # Get the widgets master
output.append(widget) # Append it to the list
if isinstance(widget, tk.Toplevel): # If we incounter a toplevel stop
break
return output
def function(event):
print("Is the widget's master `main_window`?: ", main_window in get_masters(event.widget))
# Check if the widget that caused the event is in `main_window`
if main_window in get_masters(event.widget):
print("Hangle event")
else:
print("Ignore event")
root = tk.Tk()
main_window = tk.Toplevel(root)
theme_window = tk.Toplevel(root)
button = tk.Button(main_window, text="Main Window")
button.pack()
button = tk.Button(theme_window, text="Theme Window")
button.pack()
main_window.bind_class("Button", "<Enter>", function, add="+")
root.mainloop()
The function get_masters returns a list of all of the frames+window that the widget is in. In function, we check if the widget that caused the even is in main_window or not. Based on that we can either handle or ignore the event.

Related

How to close current tkinter window and open a new tkinter window when the user inputs test into a tkinter Entry widget

I would like to close the current tkinter window, and open a new tkinter window when the user inputs text into an entry widget. That might sound confusing so let me explain.
First tkinter window:
When the user inputs text into the Entry widget, I would like this current window to close and the second window to open with the text the user entered displayed in a label widget.
Second window:
Here is my current code:
from tkinter import *
user_input = ''
class Startup_window:
def __init__(self, master):
self.master = master
master.title('Window 1')
def get_input(event):
global user_input
# Gets the user input from the Entry widget
user_input = self.input.get()
# Clears Entry widget
self.input.delete(0, END)
master.destroy()
self.label = Label(master, text='Input:')
self.label.grid(row=0, column=0)
self.input = Entry(master)
self.input.grid(row=0, column=1)
self.input.focus()
self.input.bind("<Return>", get_input)
class Main_window:
def __init__(self, master):
self.master = master
master.title('Window 2')
self.label = Label(master, text="You've entered (user_input)" + user_input)
self.label.pack()
root = Tk()
startup_window = Startup_window(root)
if user_input != '':
main_window = Main_window(root)
mainloop()
I am new to tkinter and object oriented programming so any help would be greatly appreciated!
This would work for you. As #CoolCloud mentioned, the if condition will be checked only once. Because mainloop() actually waits for events to be triggered (maybe through some buttons or whatever), NOT that it executes the blocks of code over and over again
import tkinter as tk
class MainApp():
def __init__(self, root):
self.root = root
self.inputBox = tk.Entry(self.root)
self.inputBox.pack()
self.inputBox.bind('<Return>', self.checkInput)
def checkInput(self, args):
if self.inputBox.get() != '':
userVal = self.inputBox.get()
self.root.destroy() # try root.quit if it doesn't work
newWindow = tk.Tk()
myLabel = tk.Label(newWindow, text='You entered: ' + userVal)
myLabel.pack()
win = tk.Tk()
MainApp(win)
win.mainloop()

How to get input from tkinter Entry widget on second window while the first window continues to run

from tkinter import *
def first():
root1 = Tk()
Button(root1, text = 'get Second', command= second).pack()
root1.mainloop()
def second():
root2 = Tk()
user_input = StringVar()
Entry(root2, text = user_input).pack()
Button(root2, text = 'submit', command = lambda : print(user_input.get(), '\t printed')).pack()
root2.mainloop()
first()
You are making a few basic mistakes in here -
You if want to use a second window, it should be Toplevel not root Tk window. There should be only one root window in the program. This should act as parent to all the windows.
Its a good practice in most of the cases to define the widgets like Button, Entry separately and then pack() them.
Entry should have 'textvariable' not 'text'
Following is the updated code which may help you -
from tkinter import *
root = Tk()
def first():
button = Button(root, text = 'get Second', command= second)
button.pack()
root.mainloop()
def second():
window2 = Toplevel(root)
user_input = StringVar()
entry = Entry(window2, textvariable=user_input)
entry.pack()
button = Button(window2, text = 'submit', command = lambda: print(user_input.get()))
button.pack()
first()

Is there a way to make sure a highlited parent widget remains highlighted when selecting a child widget

I have a radiobutton that highlights the corresponding LabelFrame.
Each LabelFrame has an Entry widget as a child.
When the Entry widget is selected to type in some input, the parent LabelFrame loses the given highlightbackground color (from cyan to gray) but keeps the same highlightthickness.
Is there a way to keep the given highlightbackground color?
(windows 7 64, pycharm 2019.2)
Thanks in advance.
from tkinter import *
from tkinter import ttk
import tkinter as tk
class doSomeStuff(Tk):
def __init__(self):
Tk.__init__(self)
self.radioBtnVar = StringVar() # radiobutton variable
# main canvas
pwdCanvas = tk.Canvas(self, bd=0, highlightthickness=0)
pwdCanvas.pack()
# choiceLabelFrame
choiceLabelFrame = ttk.LabelFrame(pwdCanvas, text='Choice LabelFrame (ttk)')
choiceLabelFrame.grid(column=0, row=11, columnspan=2, sticky='nsew')
# radio button 1
rbtn1 = ttk.Radiobutton(choiceLabelFrame, text='A', variable=self.radioBtnVar, value='PCG', command=self.colorLabels)
rbtn1.pack(side='left')
# radio button 2
rbtn2 = ttk.Radiobutton(choiceLabelFrame, text='B', variable=self.radioBtnVar, value='UG', command=self.colorLabels)
rbtn2.pack(side='right')
# LabelFrame1, left side
self.LabelFrame1 = tk.LabelFrame(pwdCanvas, text="LabelFrame 1 (tk)", bd=0) # I use tk to have access to the 'highlightbackground' option
self.LabelFrame1.grid(column=0, row=12, sticky='nsew', padx=3, pady=3)
entry1Label = ttk.Label(self.LabelFrame1, text='Entry 1')
entry1Label.grid(column=0, row=11, sticky='w')
self.labelEntry1 = ttk.Entry(self.LabelFrame1, state='disabled')
self.labelEntry1.grid(column=1, row=11, sticky='w')
# LabelFrame2, right side
self.LabelFrame2 = tk.LabelFrame(pwdCanvas, text="LabelFrame 2 (tk)", bd=0)
self.LabelFrame2.grid(column=1, row=12, sticky='nw', padx=3, pady=3)
entry2Label = ttk.Label(self.LabelFrame2, text='Entry 2')
entry2Label.grid(column=0, row=0)
labelEntry2 = ttk.Entry(self.LabelFrame2, state='disabled')
labelEntry2.grid(column=1, row=0)
def colorLabels(self): # activates and highlights the chosen option
if self.radioBtnVar.get() == 'PCG':
for child in self.LabelFrame1.winfo_children():
child.config(state='enabled')
self.LabelFrame1.config(highlightbackground='cyan', highlightthickness=2)
for child in self.LabelFrame2.winfo_children():
child.config(state='disabled')
self.LabelFrame2.config(highlightthickness=0)
elif self.radioBtnVar.get() == 'UG':
for child in self.LabelFrame2.winfo_children():
child.config(state='enabled')
self.LabelFrame2.config(highlightbackground='cyan', highlightthickness=2)
for child in self.LabelFrame1.winfo_children():
child.config(state='disabled')
self.LabelFrame1.config(highlightthickness=0)
if __name__ == "__main__":
app = doSomeStuff()
app.mainloop()
The highlightthickness attribute is specifically for highlighting which widget has the keyboard focus. It serves as a clue for the user when traversing the UI with the keyboard.
Because it is tied directly to which widget has focus, and because you can only have focus in one widget at a time, it's not possible to use that feature to highlight more than one thing at a time.
I've found a way to get what I want.
def colorLabels(self):
if self.radioBtnVar.get() == 'PCG':
for child in self.LabelFrame1.winfo_children():
child.config(state='enabled')
self.LabelFrame1.config(highlightbackground='cyan', highlightcolor='cyan', highlightthickness=2)
for child in self.LabelFrame2.winfo_children():
child.config(state='disabled')
self.LabelFrame2.config(highlightthickness=0)
elif self.radioBtnVar.get() == 'UG':
for child in self.LabelFrame2.winfo_children():
child.config(state='enabled')
self.LabelFrame2.config(highlightbackground='cyan', highlightcolor='cyan', highlightthickness=2)
for child in self.LabelFrame1.winfo_children():
child.config(state='disabled')
self.LabelFrame1.config(highlightthickness=0)
I simply added 'highlightcolor='cyan''.
As explained here effbot.org :
'highlightbackground' is used when the widget doesn’t have focus.
'highlightcolor' is used when the widget has focus.
That way my widget keeps its highlighted contour even if it's not in focus.

Python Tkinter Check if Frame exists

I am trying to do the following:
Create a Tkinter App with a 'File' menu.
The File Menu has 2 options, Add and View.
The Add option adds a Frame and then adds a Label widget (Label 1) in the frame.
If I then select the View option form the file menu, it should print out whether or not a Frame widget already exists.
Following is my attempt at it, but I receive the error
AttributeError: 'Test' object has no attribute 'tk'
when I select the View option, can someone please help point out what I am missing here?
from tkinter import Tk, Menu, Label, Frame
class Test():
def __init__(self):
self.gui = Tk()
self.gui.geometry("600x400")
menu = Menu(self.gui)
new_item1 = Menu(menu)
menu.add_cascade(label='File', menu=new_item1)
new_item1.add_command(label='Add', command=self.addlbl)
new_item1.add_command(label='View', command=self.viewlbl)
self.gui.config(menu=menu)
self.gui.mainloop()
def addlbl(self):
f=Frame()
f.pack()
lbl1 = Label(f, text="Label 1").grid(row=0, column=0)
def viewlbl(self):
print(Frame.winfo_exists(self))
T=Test()
I replicated your problem. I got the code below to work using Python3.4 on Linux. f needs to become self.f. I named it self.frame. This enables the frame to be accessed outside of the method it is created in.
from tkinter import Tk, Menu, Label, Frame
class Test():
def __init__(self):
self.gui = Tk()
self.gui.geometry("600x400")
menu = Menu(self.gui)
new_item1 = Menu(menu)
menu.add_cascade(label='File', menu=new_item1)
new_item1.add_command(label='Add', command=self.addlbl)
new_item1.add_command(label='View', command=self.viewlbl)
self.gui.config(menu=menu)
self.gui.mainloop()
def addlbl(self):
self.frame = Frame(self.gui)
self.frame.pack()
lbl1 = Label(self.frame, text="Label 1")
lbl1.grid(row=0, column=0)
def viewlbl(self):
print('frame exists {}'.format(self.frame.winfo_exists()))
T=Test()

How to open a second ptinker Window separately rather than as a tab

I am trying to open a second window in tkinter but it always appears as a tab rather than separately. Code showing the problem is as follows:
import tkinter as tk
class MainWindow:
def __init__(self, master):
self.master = master
frame = tk.Frame(self.master)
button = tk.Button(frame, text = 'New Window', width = 25, command = self.new_window)
button.pack()
frame.pack()
def new_window(self):
newWindow = tk.Toplevel(self.master)
SecondWindow(newWindow)
class SecondWindow:
def __init__(self, master):
frame = tk.Frame(master)
quitButton = tk.Label(frame, text = 'Second Window')
quitButton.pack()
frame.pack()
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
When I run this I get the following output:
Clicking the button gives:
(Ignoring the secondary issue of the size) if we expand it we get the following:
I can get a separate window by dragging the tab. How to I code this so that I get the window displaying as a separate window when I click the button ?

Resources