Toplevel in tkinter is creating another empty window at the side - python-3.x

I am new in python.
I was trying to write a code with tkinter.
In click of a button it should open another window and close the previous window.
The code is closing the previous window correctly.
But the problem is it is also opening another empty window at the side on the screen.
Here's my code:
# The first part got no problem
from tkinter import *
import time
class Start:
def __init__(self):
self.first_screen = Tk()
self.win_width = 500
self.win_height = 500
self.screen_width = self.first_screen.winfo_screenwidth()
self.screen_height = self.first_screen.winfo_screenheight()
self.x_position = (self.screen_width / 2) - (self.win_width / 2)
self.y_position = (self.screen_height / 2) - (self.win_height / 2)
self.first_screen.title("Number game")
self.first_screen.config(bg="#ffff00")
self.first_screen.geometry("%dx%d+%d+%d" % (self.win_width, self.win_height, self.x_position, self.y_position))
self.btn_play = Button(self.first_screen, text="Start", command=self.btn_play_click_action, width="10")
self.btn_play.pack(side="top")
self.btn_play.place(height=40, width=200, x=150, y=200)
self.first_screen.mainloop()
# This is where the problem happened
def btn_play_click_action(self):
time.sleep(1)
self.first_screen.destroy()
self.second_screen = Toplevel()
self.second_screen.geometry("%dx%d+%d+%d" % (self.win_width, self.win_height, self.x_position, self.y_position))
self.second_screen.title("Number game")
self.second_screen.config(bg="#eeee00")
self.label1 = Label(self.second_screen, width=50, bg="#000000")
self.label1.pack(side="top")
self.second_screen.mainloop()
Start()
Edit:
When I remove the " self.first_screen.destroy()" line, then the there is no problem.
Maybe it is because Toplevel needs a parent window. But I need to close the previous window. In this case what should I do?

You can not destroy the root window of the program which is self.first_screen = Tk().
Also, you dont need a mainloop for Toplevel window.
You can use .withdraw() method to hide root window instead of .destroy()
Here is you updated code -
from tkinter import *
import time
class Start:
def __init__(self):
self.first_screen = Tk()
self.win_width = 500
self.win_height = 500
self.screen_width = self.first_screen.winfo_screenwidth()
self.screen_height = self.first_screen.winfo_screenheight()
self.x_position = (self.screen_width / 2) - (self.win_width / 2)
self.y_position = (self.screen_height / 2) - (self.win_height / 2)
self.first_screen.title("Number game")
self.first_screen.config(bg="#ffff00")
self.first_screen.geometry("%dx%d+%d+%d" % (self.win_width, self.win_height, self.x_position, self.y_position))
self.btn_play = Button(self.first_screen, text="Start", command=self.btn_play_click_action, width="10")
self.btn_play.pack(side="top")
self.btn_play.place(height=40, width=200, x=150, y=200)
self.first_screen.mainloop()
# This is where the problem happened
def btn_play_click_action(self):
time.sleep(1)
self.first_screen.withdraw()
self.second_screen = Toplevel()
self.second_screen.geometry("%dx%d+%d+%d" % (self.win_width, self.win_height, self.x_position, self.y_position))
self.second_screen.title("Number game")
self.second_screen.config(bg="#eeee00")
self.label1 = Label(self.second_screen, width=50, bg="#000000")
self.label1.pack(side="top")

There is unnecessary to make another window in Toplevel(). You can make it easier → Instead of self.second_screen = Toplevel() you can type self.second_screen = Tk().

Related

How to center launch second window in the middle of the main window with python 3 tkinter/guizero?

I am trying to open a second window in the center of the main window. It needs to work where ever the main window is located and for what ever the main window's size is. I have set up some some test widget to make sure that when the second window is close it enables all the main windows functionality.
What I'm using.
Windows 10
Python 3.7.9
Guizero 1.2.0/tkinter
Thonny 3.3.10 ide
Example of what I'm trying to do.
My code.
from guizero import *
app = App(bg='#121212',title='Main window',width=575,height=550)
app.tk.resizable(False, False)
def SecondWindow_closed():
secondWindow.destroy()
app.enable()
app.focus()
def System_secondWindow():
global secondWindow
secondWindow = Window(app,bg='#121212',title='Settings window',width=355,height=425)
secondWindow.tk.resizable(False, False)
About_project=Text(secondWindow,text='About this project ',align='bottom')
About_project.text_color='white'
secondWindow.tk.grab_set()
secondWindow.when_closed=SecondWindow_closed
Settings_button = PushButton(app, text='Settings ⚙',command=System_secondWindow)
Settings_button.text_color='white'
Test_widget=TextBox(app,)
Test_widget.bg='white'
app.display()
This code creates a new window that is in the center of the old one. The problem is that it uses pure tkinter instead of guizero.
import tkinter as tk
def create_second_window():
new_root = tk.Toplevel()
new_root.update()
x = root.winfo_rootx() + root.winfo_width()/2 - new_root.winfo_width()/2
y = root.winfo_rooty() + root.winfo_width()/2 - new_root.winfo_height()/2
new_root.geometry("+%i+%i" % (x, y))
root = tk.Tk()
root.geometry("500x500")
button = tk.Button(root, text="Click me", command=create_second_window)
button.pack()
root.mainloop()
Updated for guizero
from guizero import *
app = App(bg='#121212',title='Main window',width=575,height=550)
app.tk.resizable(False, False)
def SecondWindow_closed():
secondWindow.destroy()
app.enable()
app.focus()
def System_secondWindow():
global secondWindow
secondWindow = Window(app,bg='#121212',title='Settings window',width=355,height=425)
secondWindow.tk.resizable(False, False)
About_project=Text(secondWindow,text='About this project ',align='bottom')
About_project.text_color='white'
x = app.tk.winfo_rootx() + app.tk.winfo_width()/2 - secondWindow.tk.winfo_width()/2
y = app.tk.winfo_rooty() + app.tk.winfo_width()/2 - secondWindow.tk.winfo_height()/2
secondWindow.tk.geometry("+%i+%i" % (x, y))
secondWindow.tk.grab_set()
app.disable()
secondWindow.when_closed=SecondWindow_closed
Settings_button = PushButton(app, text='Settings ⚙',command=System_secondWindow)
Settings_button.text_color='white'
Test_widget=TextBox(app,)
Test_widget.bg='white'
app.display()

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()

Tkinter error: bad window path name when deleting frames dynamically

Im trying to recreate a little version of trello in tkinter. Right now im stuck I have a problem when I want to delete frames in a different order. For example: I click on the button and a new frame is generated if I delete that everything works. If I create 3 frames I have to remove them in the same order as I have created them. So I think my problems lies in the pop function but I dont know how to access them manually. When i change the pop function to (1) then I have to delete the second creation first instead of the first.
Here is the code:
from tkinter import *
class Window:
def __init__(self, width, height):
self.root = Tk()
self.width = width
self.height = height
self.root.geometry(width + "x" + height)
class Frames:
def __init__(self):
self.l = Frame(window.root, bg="red", height=300, width=300, relief="sunken")
self.l.place(relwidth=0.3, relheight=0.3)
self.deleteB = Button(self.l, text="X", command=self.delete_frame, bg="blue")
self.deleteB.place(rely=0, relx=0.92)
self.addB = Button(self.l, text="Add", command=self.add_note, bg="blue")
self.addB.place(rely=0, relx=0.65)
def delete_frame(self):
self.l.pack()
self.l.pack_forget()
self.l.destroy()
frames.pop()
def add_note(self):
self.note_Label = Label(self.l, text="Clean the room")
self.note_Label.pack(padx=20, pady=10)
self.delete_Note = Button(self.note_Label, text="X", command=self.del_Note)
self.delete_Note.pack(padx=5, pady=5)
def del_Note(self):
self.note_Label.pack_forget()
self.note_Label.destroy()
class Note:
def __init__(self):
pass
class DragNDrop:
def __init__(self):
pass
def make_draggable(self, widget):
widget.bind("<Button-1>", self.on_drag_start)
widget.bind("<B1-Motion>", self.on_drag_motion)
def on_drag_start(self, event):
widget = event.widget
widget._drag_start_x = event.x
widget._drag_start_y = event.y
def on_drag_motion(self, event):
widget = event.widget
x = widget.winfo_x() - widget._drag_start_x + event.x
y = widget.winfo_y() - widget._drag_start_y + event.y
widget.place(x=x, y=y)
class Buttons:
def __init__(self):
self.button = Button(window.root, width=20, height=20, bg="blue", command=self.add_frames)
self.button.pack()
def add_frames(self):
frames.append(Frames())
print(frames)
window = Window("800", "600")
frames = []
drag = DragNDrop()
button = Buttons()
while True:
for i in frames:
drag.make_draggable(i.l)
window.root.update()
If someone has an Idea or workaround that would be nice to know.
Also I have another Idea instead of destroying them I could just hide them but in the end that makes the programm really slow at some point.
Here is the error: _tkinter.TclError: bad window path name ".!frame2"
Your code needs to remove the frame from the list. Instead, you're calling pop which always removes the last item. That causes you to lose the reference to the last window, and one of the references in frames now points to a window that has been deleted (which is the root cause of the error)
Instead, call remove:
def delete_frame(self):
self.l.destroy()
frames.remove(self)

Widget in a second frame in a main class does not appear

I am trying to add a second frame inside my main class and put there a few widgets. I created a frame by using a method and assigned one of the widget to that frame but the problem is it does not appear.
I provided below piece of code with window configuration and 2x Labels which are at the main frame (Both appear correctly) and one in the new frame which appearing problem.
If you have some idea, please help me :)
import tkinter as tk
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
# Adding a background picture
self.background_img = tk.PhotoImage(file="in office.png")
back_ground_img_label = tk.Label(self, image=self.background_img)
back_ground_img_label.pack(fill="both", expand=True)
# Adjusting the window
width_of_window = 1012
height_of_window = 604
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x_coordinate = int((screen_width / 2) - (width_of_window / 2))
y_coordinate = int((screen_height / 2) - (height_of_window / 2) - 30)
self.geometry(
f"{width_of_window}x{height_of_window}+{x_coordinate}+{y_coordinate}"
)
self.bet_frame()
bet_value_label_bg = tk.Label(self)
bet_value_label_bg.place(x=462, y=300)
coin_button_1 = tk.Button(self.frame)
coin_button_1.place(x=233, y=435)
def bet_frame(self):
self.frame = tk.Frame(width=1012, height=604)
self.frame.pack()
if __name__ == "__main__":
MainApplication().mainloop()
The only thing you put in the self.frame is the coin_button_1, but as you place it at (233, 435) is is hidden below the main window self.
Personally I would not use place but rather either pack or even better grid to place the widgets on the screen (see Setting Frame width and height)
So if you change def bet_frame(self) as follows it will be visible
...
bet_value_label_bg = tk.Label(self, text='value')
bet_value_label_bg.place(x=462, y=300)
def bet_frame(self):
self.frame = tk.Frame(master=self, width=1012, height=604)
self.frame.pack()
coin_button_1 = tk.Button(self.frame, text='coin button')
coin_button_1.pack()
...
Note the bet_value_label_bg shows up in the middle of the picture and you may have to expand the main window to make the self.frame visible, depending on the size of the picture.

Getting function NOT to run on import

I have tried EVERY " if name=='main' " suggestion and it still fails (or maybe I'm doing it wrong or not understanding it). I am also Not trying to run things from a command line. While testing things out in Pycharm, I am trying to get the main file to pop-up with a gui and then when I click on the button, trying to get the first window to go away and the second file/gui to pop up in its place.
Any help would be greatly appreciated.
this is the main one I am trying to start with but opens up with the second gui first
from tkinter import *
from tryingstuff import EmdMain
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
#firebutton
self.fphoto = PhotoImage(file="../icon/fireorig.png")
self.fbutton = Button(frame, image=self.fphoto)
self.fbutton.config( height=228, width=200)
self.fbutton.pack(side=LEFT)
#emsbutton
self.mphoto = PhotoImage(file="../icon/ems.png")
self.emsButton = Button(frame, image=self.mphoto, command=EmdMain)
self.emsButton.config( height=224, width=197)
self.emsButton.pack(side=RIGHT)
root = Tk()
root.title("ProQA Card set")
app = App(root)
root.mainloop()
This is the second file
from tkinter import *
def EmdMain():
frame = Frame()
frame.pack()
abdominalPnB = Button(frame, text="01_Abdominal Pain")
abdominalPnB.config(anchor="w", width=20, height=1)
abdominalPnB.grid(row=0, column=0)
root = Tk()
app = EmdMain()
root.mainloop()
if __name__=='__main__':
EmdMain()

Resources