tkinter - Cant hide nested toplevel window - python

I create an instance of TopLevel class inside another class, but can't "withdraw()" the child window
with a call from parent.
import tkinter as tk
class Table(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self,master)
self.var_new_t=tk.Toplevel(self.master)
self.t2=Table_2(self.var_new_t)
#Goal is to create a child window and immediately hide it.
self.t2.hide_me()
#self.t2.withdraw() ##Tried a few differnt ways
class Table_2(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self,master)
self.master = master
label = tk.Label(self.master, bg='green', text='Second Table')
label.grid()
def hide_me(self):
self.master.withdraw()
root = tk.Tk()
n= Table(root)
tk.Button(root, text="Quit", command=root.destroy).pack()
root.mainloop()
I tried a few other variations to no avail.

Your code is creating two windows. Consider this code:
Table is a toplevel window because it inherits from Toplevel. So, this line creates the Table window:
tk.Toplevel.__init__(self,master)
Then, you create another window when you do this:
self.var_new_t=tk.Toplevel(self.master)
If you inherit from Toplevel you typically shouldn't create a second Toplevel inside unless you explicitly intend to create two windows.
Your code needs to look something like this:
class Table(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self,master)
self.t2=Table_2(self)
self.t2.hide_me()
class Table_2(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self,master)
self.master = master
label = tk.Label(self, bg='green', text='Second Table')
label.grid()
def hide_me(self):
self.withdraw()

Related

Tkinter OOP organizing widget on a class which inherits from tk.Toplevel

I have organized my GUI with a parent app class which inherits from tk.Frame. In the main main app I create a top level window object which is a pop up when a button is pressed. This class inherits from tk.Toplevel. The Toplevel should have its own widgets which need to be organized neatly. I am wondering what is the best way to organize the widgets on the Toplevel. Below is the code which shows the overall structure of the GUI I am trying to write. The submit_button class is where widgets need to be organized properly.
import tkinter as tk
from tkinter import ttk
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.title = "TITLE"
self.master = master
self.submit = ttk.Button(self, text = 'SUBMIT', command = self.click_submit_button)
self.submit.grid(row = 0, column = 2, padx = 20, pady = 20)
def click_submit_button(self):
self.submit_pop_up = submit_button(self.master)
class submit_button(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.master = master
self.title = 'TITLE'
if __name__ == "__main__":
root = tk.Tk()
app = Window(root)
app.pack()
root.mainloop()

How to create multiply tabs for class in tkinter

I'm trying to create tabs for each class in tkinter. But faced with a problem that they are laying on each other.
I already tried to create a new class for Notebook, but the result is the same. Now I stopped at this variant.
from tkinter import *
from tkinter import ttk
class Application(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.master = master
self.mainframe = ttk.Frame(master, padding='10 10 15 15')
self.mainframe.grid(column=0, row=0, sticky=N+S+W+E)
self.connectionCheck()
self.connectionConf()
self.measureFrame()
self.meas()
self.logview()
self.running = None
#It have other functions. But I think they not really necessary
class Mapframe(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.master = master
self.mapframe = ttk.Frame(master, padding='10 10 15 15')
self.mapframe.grid(column=0, row=0, sticky=N + W + E + S)
self.choosefiles()
self.meas()
window = Tk()
notebook = ttk.Notebook(window)
tab1 = Application(notebook)
tab2 = Mapframe(notebook)
notebook.add(tab1, text='Tab1')
notebook.add(tab2, text='Tab2')
notebook.grid(row=0, column=0)
notebook.mainloop()
notebook.quit()
So, as I say they lay on each other. And the tabs not even showing when the program is launch.
Upd: after change master to self.
When creating a class that inherits from a Frame, with the intention of holding other widgets, a cardinal rule is that all child widgets should be children of that class.
In your case, you're not doing that. You're creating a notebook, adding frames to the notebook, but the widgets inside each frame are being set as children of the root window. They need to be children of the frames (eg: self).
You need to define self.mainframe and self.mapframe like in the following example. Note the use of self rather than master as the first parameter:
self.mainframe = ttk.Frame(self, padding='10 10 15 15')
...
self.mapframe = ttk.Frame(self, padding='10 10 15 15')
The only place you should be using master as the parent of a widget is when calling ttk.Frame.__init__(self, master). At no other time should you be putting widgets inside of master

Python tkinter 2 frames merge together

Hey guys I have to classes that both create a Frame. The first one contains a button that is supposed to close its frame. The second frame simply contains a Label. My code should first create the frame with the button and when the button is pressed the second window should show up. What happens is that when pressing the button a "merged" window is created that contains the button and the label.
import tkinter as tk
class Window1(tk.Frame):
def __init__(self):
tk.Frame.__init__(self)
self.grid()
self.btn = tk.Button(self,text = "button",command = self.run)
self.btn.grid(row = 0,column = 0)
def run(self):
tk.Frame.quit(self)
class Window2(tk.Frame):
def __init__(self):
tk.Frame.__init__(self)
self.grid()
self.label = tk.Label(self,text = "label ")
self.label.grid(row = 0,column = 0)
w = Window1()
w.mainloop()
v = Window2()
v.mainloop()
The first picture is before you press the button, the next one after you pressed the button. The problem seems that tk.Frame.quit(self) doesn't work correctly. I tried similar ways to close the window such as:
tk.Frame.destroy(self)
but that doesn't help either.
edit: I solved it by inheriting the class from tk.TK instead of tk.Frame
Frame doesn't create window - it only group elements. Tk() creates window.
To close window you have to destroy() object create by Tk(). But you don't creat it manually root = tk.Tk() so tkinter create it automatically, but you have no access to this root to close it.
If widget doesn't have parent then it uses root and your Frame does it too.
import tkinter as tk
class Window1(tk.Frame):
def __init__(self, master):
# send `root` to `Frame` as its parent
tk.Frame.__init__(self, master)
# `Frame` will keep `master as `self.master`
# so we don't have to do `self.master = master` manually
self.grid()
self.btn = tk.Button(self, text="Hello Button", command=self.run)
self.btn.grid(row=0, column=0)
def run(self):
# use `master` (`root`) to destroy it
self.master.destroy()
class Window2(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.grid()
self.label = tk.Label(self, text="Hello Label")
self.label.grid(row=0, column=0)
root = tk.Tk() # create main window as `root`
Window1(root) # send `root` to `Window1` and later to `Frame`
root.mainloop()
root = tk.Tk()
Window2(root)
root.mainloop()

Python global text area

I have a text area created in initUI(self) function and would like to add to its contents in another one. When I initialize the text area as global on top of the class, the area is created in an another window, which is not what I want. I have seen questions related to the global variables but not something like this.
from Tkinter import*
textArea = Text() # creates another window
class test(Frame):
def __init__(self, parent):
Frame.__init__(self,parent)
self.initUI()
def initUI(self):
mainFrame = Frame(self, parent)
textArea = Text(maınFrame, height=10, width=10)
textArea.pack(side=BOTTOM)
textArea.insert(INSERT, "abc")
def changeText():
global textArea
textArea.insert(INSERT, "def")
thanks
global isn't necessary when you need a variable to be shared between two methods belonging to the same class. You can just attach the variable you need to self.
from Tkinter import*
class test(Frame):
def __init__(self, parent):
Frame.__init__(self,parent)
self.initUI()
def initUI(self):
mainFrame = Frame(self, parent)
self.textArea = Text(maınFrame, height=10, width=10)
self.textArea.pack(side=BOTTOM)
self.textArea.insert(INSERT, "abc")
def changeText(self):
self.textArea.insert(INSERT, "def")

How to use scrollbar widget function in another Tkinter class and bind it to buttons

I've created a Tkinter class, Ext() with a scrollbar for any text in the variabel self.text in the create_scrollbar() method. I want to use this method by binding it to Buttons in the class Application so that when the Button is pressed the text shows up in a scrollbar. I've tried to implement this as one class first but it lead to issues when using two init in the same class. How do I invoke create_scrollbar in Ext in the callback, self.callback in the Applications class ?
from Tkinter import *
import Tkinter as tk
class Ext(tk.Frame):
""" a scrollbar creation class, extends the class Application"""
def __init__(self, master):
""" init the frame """
tk.Frame.__init__(self)
self.text = tk.StringVar()
tk.Frame.__init__(self, master)
self.scrollbar = tk.Canvas(master, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.scrollbar, background="#ffffff")
self.txt = tk.Scrollbar(master, orient="vertical", command=self.scrollbar.yview)
self.scrollbar.configure(yscrollcommand=self.txt.set)
self.scrollbar.configure(width=500, height=200)
self.txt.pack(side="right", fill="y")
self.scrollbar.pack(side="left", fill="both", expand=True)
self.scrollbar.create_window((0,0), window=self.frame, anchor="nw",
tags="self.frame")
self.create_scrollbar()
def create_scrollbar(self):
tk.Label(self.frame, text=self.text).grid(column=1)
class Application(Frame):
def __init__(self, root):
""" init the frame """
Frame.__init__(self)
self.grid()
self.create_widgets()
def create_widgets(self):
Button = Button(self, text = "Display scrollbar!", command = self.callback)
Button.grid(row = 10, column = 1, sticky = W)
def callback(self):
self.text = "this is a test sentence
print create_scrollbar(t) # Print scrollbarwidget from the Ext() class when the Button is pressed
#Main
root = Tk()
root.title("Maltparser1.0_demo")
root.geometry("900x700")
root.mainloop()
app = Application(root)
master = tk.Tk()
master = Ext(master)
master.title("Instructions")
master.geometry("800x300")
Ext(master).pack(side="top", fill="both", expand=True)
master.mainloop()
To answer your specific question, to call the create_scrollbar method you first need to create an instance of the class. For example:
def callback:
e = Ext(self)
e.create_scrollbar()
However, this won't do what you think it will, because you never tell it what text to display. In callback, self.text lives in the App class, not the Ext class. Perhaps you want to pass the string or a textvariable to the constructor of the Ext class.
As an aside, you code is very confusing. You create a frame named self.frame -- which makes sense -- but a canvas named self.scrollbar, a scrollbar named self.txt, and a stringvar named self.text. You then have a method called create_scrollbar which creates a label. And finally, you create a button from the class Button, and then name it Button. You can't have both a class and an instance with the same exact name.
Maybe those names make sense to you, but as someone who is not you, I think your name choices make your code extremely hard to understand.

Categories

Resources