Move two windows together tkinter - python

I have two types of windows: Main and Child. When I move main, all child windows must move also.
So I tried to write a method, but I am new to Tkinter so it is a bit hard. Isn't there a mehtod which Tkinter already provides?
There are two errors which occure:
line 21, in move_me if second_window != None:
NameError: name 'second_window' is not defined
wm_geometry() takes from 1 to 2 positional arguments but 3 were given
''' import tkinter as tk
from tkinter import *
from tkinter import Tk
from functools import partial
from tkinter import filedialog
import tkinter as tk
root=Tk()
def second_window_X():
global second_window
second_window=Tk()
label=Label(second_window, text='window')
label.pack()
button=Button(root, text='second window', command=second_window_X)
button.pack()
def move_me(event):
if second_window != None:
x = root.winfo_x()
y = root.winfo_y()
second_window.geometry(x,y)
root.bind("<Configure>", move_me)
root.mainloop()````
Is there someone who can give me an example how to link both windows togehter and make them move at the same time? And who can explain to me, why move me doesn't knows second_window even if i declared it as global?
Thank you very much already
Sorry for all the imports

As I suggested in a comment, you shouldn't have two instances of Tk in an application. Your second window should be an instance of Toplevel.
The below code moves the second window when the first window is moved/resized.
from tkinter import *
root=Tk()
second_window = None
def second_window_X():
global second_window
second_window=Toplevel(root)
label=Label(second_window, text='window')
label.pack()
button=Button(root, text='second window', command=second_window_X,width=100)
button.pack()
def move_me(event):
try:
if second_window != None:
x = root.winfo_x()
y = root.winfo_y()
second_window.geometry(f"+{x}+{y}")
except NameError:
pass
root.bind("<Configure>", move_me)
root.mainloop()

Related

simple window with an enter field

i'm a new programmer and there are certainly several errors but this shouldn't be difficult to spot. I need to create a simple window with a field named "Concorrente 1:" and an entry field displayed by function named lacopertina(). I don't understand where is the error:
import tkinter as tk
from tkinter import *
from tkinter.ttk import *
from tkinter import ttk
class schermoiniziale(tk.Frame):
def lacopertina():
print(gio1)
#return (tot1)
def __init__(self):
global gio1
#tot1=0
#schermo1=Tk()
self.gio1=tk.StringVar()
lab1=ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1=ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
pulsante = ttk.Button(self, text="Inizio", textvariable=self.gio1, command=self.lacopertina)
pulsante.pack()
def main():
schermoiniziale().mainloop()
if __name__== "__main__":
main()
I would suggest you to go through some tutorials on Python OOP.
I have modified your code as below with some comment:
# avoid using wildcard import
import tkinter as tk
from tkinter import ttk
class schermoiniziale(tk.Frame):
def __init__(self, master, **kw):
# need to call __init__() of inherited class
super().__init__(master, **kw)
self.gio1 = tk.StringVar()
lab1 = ttk.Label(self, text="Concorrente 1:")
lab1.pack()
ent1 = ttk.Entry(self, textvariable=self.gio1)
ent1.pack()
# removed textvariable=self.gio1 as I think you actually don't need it
pulsante = ttk.Button(self, text="Inizio", command=self.lacopertina)
pulsante.pack()
def lacopertina(self):
# use .get() to get the content of a StringVar
print(self.gio1.get())
def main():
# need to create the root window before creating other widget
root = tk.Tk()
# pass root window as the parent of the widget
frame = schermoiniziale(root)
frame.pack()
# start the tkinter mainloop
root.mainloop()
if __name__== "__main__":
main()

Is there a method to create a messagebox in top-level in tkinter?

This code opens a message box on the first window. But I want to open the message box on the second window.
From tkinter import *
From tkinter import messagebox as m
Def b():
A=m.askquestion (" question ","really want to go back")
if(A=1):
R2.destroy()
Def a():
global R2
R2=Toplevel()
Label(R2,text='This is second window').pack()
Button(R2 ,text='back',command=b).pack()
Def c():
global Root
Root=Tk()
Button(root, text='next',command=a).pack()
c()
I'm looking for any suggestions about how to open the message box on the second window.
There is a solution very easy: you have to give the parent to messagebox:
From tkinter import *
From tkinter import messagebox as m
Def b():
A=m.askquestion (" question ","really want to go back", parent = R2)
if(A=1):
R2.destroy()
Def a():
global R2
R2=Toplevel()
Label(R2,text='This is second window').pack()
Button(R2 ,text='back',command=b).pack()
Def c():
global Root
Root=Tk()
Button(root, text='next',command=a).pack()
c()

python spawn multiple message boxes at once

I need my program to spawn multiple message boxes.
They have to be spawned in cascade at once.
(think of it as mimicry of malicious activity)
I tried do this using Tkinter:
import Tkinter
import tkMessageBox
for i in range(0,5):
tkMessageBox.showerror("", "oops")
but it seems program waits for user interaction with each message before showing next which is not quite what I need
and optional there is an empty form at top left corner. any idea to get rid of it?
The solutions might be to use TopLevel() here. This will allow all windows to pop up and you will be able to set a customer messagebox style as well.
Here is a simple example that will open all the windows at once while also hiding the root window. The below will stack all the windows on top of each other and you can move them. You can also provide some tracked variables to open each windows in a different location if you like.
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
for i in range(0,5):
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text = "oops").pack()
ttk.Button(x, text = " OK ", command = x.destroy).pack(side=tk.BOTTOM)
root.mainloop()
In response to your comment on using a counter see below code:
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
counter = 0
def close_window(top_window):
global counter
top_window.destroy()
counter -= 1
if counter == 0:
print("destroying root window")
root.destroy()
for i in range(0,5):
counter += 1
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text="oops").pack()
ttk.Button(x, text=" OK ", command=lambda tw=x: close_window(tw)).pack(side=tk.BOTTOM)
# this protocol() method is used to re-rout the window close event to a customer function.
# this will allow us to keep our counter and close windows as needed.
x.protocol("WM_DELETE_WINDOW", lambda tw=x: close_window(tw))
root.mainloop()
Better yet here is an example that places the items inside of a list so we do not need a counter.
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
list_of_windows = []
def close_window(tw):
i = list_of_windows.index(tw)
list_of_windows[i].destroy()
del list_of_windows[i]
if len(list_of_windows) == 0:
root.destroy()
print("root destroyed!")
for i in range(0,5):
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text="oops").pack()
ttk.Button(x, text=" OK ", command=lambda tw=x: close_window(tw)).pack(side=tk.BOTTOM)
x.protocol("WM_DELETE_WINDOW", lambda tw=x: close_window(tw))
list_of_windows.append(x)
root.mainloop()
My conclusion:
Using tk message boxes wasn't best approach to the task,
because message boxes are modal, and there is no direct way to change that.
So instead I've just got a form shaped like a message box and spawned them with desirable quantity.
Ended up with following code:
from Tkinter import *
di = {}
for i in range(5):
di[i] = Tk()
offset = 300 + i*10
di[i].geometry('150x50+'+str(offset)+'+'+str(offset))
di[i].title('')
di[i].resizable(False, False)
la = Label(di[i],text = 'oops').pack()
button = Button(di[i], text = 'OK', command=di[i].destroy).pack()
di[0].mainloop()
And it serves my needs well. Thanks to Nae and Vasilis G. for their kind responses leading me to a working code.

Changing state of tkinter entry box depending on value of OptionMenu

I am using python 2.7 and trying to change the state of a tkinter entry box depending on the value of an OptionMenu widget. I found an example of how to do it online here, it's for python 3 but I don't think that's the issue (correct me if I am wrong). Some example code is below,
from Tkinter import *
class App:
def _disable_f2(self):
if self.filt.get() == 'bandpass':
self.filter_menu.configure(state='normal')
else:
self.filter_menu.configure(state='disabled')
def __init__(self, master):
self.f2var = Tkinter.StringVar()
self.f2var.set('5.0')
self.f2_entry = Tkinter.Entry(master, textvariable=self.f2var,
width=5)
self.f2_entry.pack()
self.filt = Tkinter.StringVar()
self.filt.set('bandpass')
self.filter_menu = Tkinter.OptionMenu(master, self.filt,
'bandpass', 'lowpass ',
'highpass',
command=self._disable_f2)
self.filter_menu.pack(ipadx=50)
root = Tk()
app = App(root)
root.mainloop()
however, I keep getting the following error even though I am not passing two arguments. Anyone know what the cause is?
TypeError: _disable_f2() takes exactly 1 argument (2 given)
If you just accept one more argument and print it, you can find out what the argument is that is passed by the OptionMenu:
def _disable_f2(self, arg):
print arg
You will see it prints the new value of the OptionMenu. Because this argument is passed you need the function to accept it, and you actually are using it (with self.filt.get()) so it's fine that it's passed.
You can rewrite your _disable_f2 function to:
def _disable_f2(self, option):
if option == 'bandpass':
self.f2_entry.configure(state='normal')
else:
self.f2_entry.configure(state='disabled')
In your original code you disabled the optionmenu when the option was not 'bandpass', but I assume you want to disable the entry right? That's what this code does.
Also, if you use from Tkinter import *, you don't have to use Tkinter.StringVar(), but you can just use StringVar(). Same goes for Entry(...), OptionMenu(...) and Tk().
Allthough I would advise to use import Tkinter as tk, and use tk.StringVar() etc.
If _disable_f2 is being given two arguments, let it have what it wants.. try below...
:)
from Tkinter import *
class App:
def _disable_f2(self, master):
if self.filt.get() == 'bandpass':
self.filter_menu.configure(state='normal')
else:
self.filter_menu.configure(state='disabled')
def __init__(self, master):
self.f2var = StringVar()
self.f2var.set('5.0')
self.f2_entry = Entry(master, textvariable=self.f2var,
width=5)
self.f2_entry.pack()
self.filt = StringVar()
self.filt.set('bandpass')
self.filter_menu = OptionMenu(master, self.filt,
'bandpass', 'lowpass ',
'highpass',
command=self._disable_f2)
self.filter_menu.pack(ipadx=50)
root = Tk()
app = App(root)
root.mainloop()

Python 2.7 Tkinter redraw widget inside if

I have problem with my Tkinter code in Python 2.7. I have main window with one widget (button). I want to redraw window (and change value of variable -> add one widget) after click on the button. Where is problem? I think that problem can be, that every loop of mainloop change variable to 0. Thank you!
from Tkinter import *
def function():
global variable
variable = 0
main.update()
variable = 0
main = Tk() #New Tk window
if variable == 1:
Checkbutton(main, text="test").pack()
Button(main, text="Change", command=function).pack()
main.mainloop()
You never set variable to 1, and you should use functions (and classes) when working with GUIs.
from Tkinter import *
main = Tk() #New Tk window
variable = 0
def function():
global variable
variable = 1
newThing()
def newThing():
global variable
if variable==1:
Checkbutton(main, text="test").pack()
variable = 0
Button(main, text="Change", command=function).pack()
main.mainloop()

Categories

Resources