How to open a second ptinker Window separately rather than as a tab - python-3.x

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 ?

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

Python3 Tkinter - problem with expanding one frame to fit root window

Hi there (this is my first question)
I am building an app with Tkinter as the GUI. I want multiple frames to expand to fill out the entire root window.
With the code below, I expected the bottom (green) frame to expand all the way up to the top (cyan) frame. Instead, it stays at the bottom, and there is a "frame-less" white area between the two frames.
screenshot of an actual result when code is run
This is the code, I am executing (methods that do not mess with frame layout has been shortened out):
class CreateWindow:
def __init__(self, master, screen):
self.master = master
self.master.geometry('300x400')
self.master.title("THE PROGRAM")
self.screen = screen
self.menu_bar = Menu(self.master)
self.setup_menu = Menu(self.menu_bar)
self.setup_bar()
self.main_menu = Menu(self.menu_bar)
self.main_bar()
self.diary_menu = Menu(self.menu_bar)
self.diary_bar()
self.master.config(menu=self.menu_bar)
# self.master.grid_columnconfigure(0, weight=1) # What is difference between these two and the two below?
# self.master.grid_rowconfigure(0, weight=1)
self.master.columnconfigure(0, weight=1)
self.master.rowconfigure(0, weight=1)
self.top_menu(self.master) # TODO: Make this menu actively do stuff
if self.screen == "setup":
setup = SetupScreen(self.master)
elif self.screen == "main":
setup = MainScreen(self.master)
elif self.screen == "diary":
setup = DiaryScreen(self.master)
else:
raise TypeError("wrong screen")
def setup_bar(self): ...
def main_bar(self): ...
def diary_bar(self): ...
def top_menu(self, window): # Defines top frame : placeholder for future menu
top = tk.Frame(window, bg='cyan', pady=5)
top.grid(row=0, sticky='new')
button = tk.Button(top, text="Setup", command=self.do_nothing)
button.grid(row=0, column=0)
button = tk.Button(top, text="Main", command=self.do_nothing)
button.grid(row=0, column=1)
button = tk.Button(top, text="Diary", command=self.do_nothing)
button.grid(row=0, column=2)
top.columnconfigure(0, weight=1)
top.columnconfigure(1, weight=1)
top.columnconfigure(2, weight=1)
def do_nothing(self): ...
def b_exit(self): ...
"""This class contains methods, that create and manage the setup screen.
I want the green frame to expand all the way up to the cyan (top menu) """
class SetupScreen(CreateWindow):
def __init__(self, master):
self.master = master
self.menu = tk.Frame(self.master, bg='green')
self.menu.grid(row=1, sticky='new')
self.menu.columnconfigure(0, weight=1) # Again, what is difference between 'grid_'or not?
self.menu.grid_rowconfigure(1, weight=1) #I have tried setting index to both 0 and 1, no difference
self.create_buttons()
def create_buttons(self): ...
def personal_details(self): ...
def start_new(self):
pass
if __name__ == "__main__":
files = FileHandler() #Class meant to be handling file operations - currently only sets a boolean to false, that makes the app start with setup screen
ap = files.active_program
print(ap)
root = tk.Tk()
if not files.active_program: #based on the boolean from FileHandler class, this starts the setup screen
top_menu = CreateWindow(root, "setup")
else:
top_menu = CreateWindow(root, "main")
root.mainloop()
It looks like you're trying to create a notebook widget with several tabs.
So I would suggest you use ttk.Notebook instead of re-inventing it yourself.

Refresh text in tkinter message box

I have a Python code that has many steps. Every step I make is a print that says that I have finished this step. I am looking for a way to open a message window and every step that ends then the print will appear in the same window until the end. How can I do this?
This might be helpful.
from tkinter import *
class Application(Frame):
t = None
def say_hi(self):
self.t.message.insert(END, "hi there!! \n")
def createWidgets(self):
self.QUIT = Button(self)
self.QUIT["text"] = "QUIT"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.pack({"side": "left"})
self.hi_there = Button(self)
self.hi_there["text"] = "Launch",
self.hi_there["command"] = self.create_window
self.hi_there.pack({"side": "left"})
def create_window(self):
if(self.t):
self.say_hi()
else:
self.t = Toplevel(self)
self.t.wm_title("Message Window")
self.t.message = Text(self.t, height=20, width=30)
self.t.message.pack()
self.say_hi()
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
root = Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
You have the main application which opens a TopLevel Window with a textarea on it.
From the function say_hi you can write directly on the textarea from the created message window.
I hope this is what you were looking for.

Using a conditional statement to link a button press

The idea is that if one presses one of the buttons the labeled text is inputted in the top left entry box. My initial plan was to use an if statement when the button is pressed and then insert the text according.
However, I am not sure what syntax to use that would allow me to make this one line conditional statement that recognizes the button being pressed. Is this actually possible or do I need to make a separate function?
from tkinter import *
from tkinter import ttk
class GUI():
def __init__(self, master):
self.master = master
master.resizable(True, True)
master.title('Conversion Calculator')
self.tabControl = ttk.Notebook(master)
self.tab1 = ttk.Frame(self.tabControl) # tab set up
self.tabControl.add(self.tab1, text='Builder')
self.tabControl.pack(expand=1, fill="both")
self.builder_entrybox = ttk.Entry(self.tab1, width=24) # entry box set up
self.builder_entrybox.grid(column=0, row=0)
self.builder_outputbox = ttk.Entry(self.tab1, width=24) # output box set up
self.builder_outputbox.grid(column=0, row=1)
self.builder_outputbox.config(state='NORMAL')
self.builder_outputbox.config(state='readonly')
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=self.builder) # CH3 button
self.CH3_Button.grid(column=1, row=0)
self.CH2_Button = ttk.Button(self.tab1, text='CH2', command=self.builder) # CH2 button
self.CH2_Button.grid(column=2, row=0)
self.OH_Button = ttk.Button(self.tab1, text='OH', command=self.builder) # OH button
self.OH_Button.grid(column=1, row=1)
self.O_Button = ttk.Button(self.tab1, text='O', command=self.builder) # O button
self.O_Button.grid(column=2, row=1)
self.H_Button = ttk.Button(self.tab1, text='H', command=self.builder) # H button
self.H_Button.grid(column=3, row=1)
self.COOH_Button = ttk.Button(self.tab1, text='COOH', command=self.builder) # COOH button
self.COOH_Button.grid(column=3, row=0)
class Logic(GUI):
def builder (self): # adding button text to entry box (tab1)
self.builder_entrybox.insert(0, 'CH3')
if __name__ == "__main__":
root = Tk()
test = Logic(root)
Yes, you would make a new function for every button:
class GUI():
def __init__(self, master):
# ...
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=self.CH3_builder) # CH3 button
self.CH3_Button.grid(column=1, row=0)
def CH3_builder(self):
self.builder_entrybox.insert('end', 'CH3')
Python can make functions on the fly, either with functools.partial (early binding) or lambda (late binding). Using that you could write the same thing like this:
from functools import partial
class GUI():
def __init__(self, master):
# ...
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=partial(self.builder_entrybox.insert, 'end', 'CH3')) # CH3 button
self.CH3_Button.grid(column=1, row=0)
But it would be better if you make a small subclass to handle all this for you, which makes your code very reusable and therefore neat:
from tkinter import ttk
import tkinter as tk
class Copa(ttk.Button):
"""A new type of Button that moves the text into a Entry when clicked"""
def __init__(self, master=None, **kwargs):
ttk.Button.__init__(self, master, command=self.builder, **kwargs)
def builder(self):
self.master.builder_entrybox.insert('end', self['text'])
class BuilderFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.builder_entrybox = ttk.Entry(self, width=24) # entry box set up
self.builder_entrybox.grid(column=0, row=0)
self.builder_outputbox = ttk.Entry(self, width=24) # output box set up
self.builder_outputbox.grid(column=0, row=1)
self.builder_outputbox.config(state='NORMAL')
self.builder_outputbox.config(state='readonly')
self.CH3_Button = Copa(self, text='CH3') # CH3 button
self.CH3_Button.grid(column=1, row=0)
self.CH2_Button = Copa(self, text='CH2') # CH2 button
self.CH2_Button.grid(column=2, row=0)
self.OH_Button = Copa(self, text='OH') # OH button
self.OH_Button.grid(column=1, row=1)
self.O_Button = Copa(self, text='O') # O button
self.O_Button.grid(column=2, row=1)
self.H_Button = Copa(self, text='H') # H button
self.H_Button.grid(column=3, row=1)
self.COOH_Button = Copa(self, text='COOH') # COOH button
self.COOH_Button.grid(column=3, row=0)
class GUI():
def __init__(self, master):
self.master = master
master.resizable(True, True)
master.title('Conversion Calculator')
self.tabControl = ttk.Notebook(master)
self.tab1 = BuilderFrame(self.tabControl) # tab set up
self.tabControl.add(self.tab1, text='Builder')
self.tabControl.pack(expand=1, fill="both")
if __name__ == "__main__":
root = tk.Tk()
test = GUI(root)
root.mainloop()

Resources