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")
Related
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()
I'm trying to make it so whenever i select a radiobutton it will .insert() a value inside of an empty entry that is declared in another class and instanced in the application class.
import tkinter as tk
class DataDisplay(tk.Frame):
""" Provides the GUI, powered by the Tkinter module. """
def __init__(self, parent):
super().__init__()
tk.Frame.__init__(self, parent)
self.parent = parent
self.grid()
self.create_widgets(parent)
def create_widgets(self, parent):
print("Creating widgets... ")
# Radio buttons frame
radiobuttons = Radiobuttons(parent)
radiobuttons.grid(column=1, row=0, sticky=tk.NE)
# ID, calibration date, arrival date frame.
data_entry_frame = tk.Frame(parent, borderwidth=3, relief='ridge')
data_entry_frame.grid(column=0, row=0, sticky=tk.NE)
# Producer info frame
product_info = ProductInfo(data_entry_frame)
product_info.pack(side=tk.TOP)
class Radiobuttons(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
# Setting border-width and border-type
self.configure(borderwidth=3, relief='ridge')
# Setting self.radio to be an integer for function use.
self.radio = tk.IntVar()
# Defining radio-buttons
rb = tk.Radiobutton(self, text='Molybdenum-99', variable=self.radio, value=1, indicatoron=0,
width=15, overrelief='sunken',
command= lambda: DataDisplay.product_info.iso_half_life_value_label.insert(0, 'test'))
rb.pack(anchor=tk.W)
rb = tk.Radiobutton(self, text='Technetium-99M', variable=self.radio, value=2, indicatoron=0,
width=15, overrelief='sunken',
command=lambda: print('Radiobutton selected Technetium99M'))
rb.pack(anchor=tk.W)
def get(self):
return self.radio.get()
class ProductInfo(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.label = tk.Label(self, text='Insert here: ')
self.label.grid(column=0, row=5)
self.iso_half_life_value_label = tk.Entry(self)
self.iso_half_life_value_label.grid(column=1, row=5)
print('Finished creating widgets.')
if __name__ == "__main__":
root = tk.Tk()
app = DataDisplay(root)
root.title("DataDisplay")
root.geometry('800x800')
root.resizable(True, True)
root.mainloop()
The error i'm getting with my current attempt: AttributeError: type object 'DataDisplay' has no attribute 'product_info'
Expected result is to have a custom value based on radiobutton selection inserted into the product_info label.
As is the case with any python object, you need a reference to the object in order to change it. The simplest solution is to pass a reference to your objects to the other objects that need them.
For example, if you pass the instance of DataDisplay to Radiobuttons, Radiobuttons can then access the attributes of DataDisplay. For example:
class DataDisplay(...):
def create_widgets(...):
...
radiobuttons = Radiobuttons(parent, data_display=self)
...
class Radiobuttons(tk.Frame):
def __init__(self, parent, data_display):
...
rb = tk.Radiobutton(..., command= lambda: data_display.product_info.iso_half_life_value_label.insert(0, 'test'))
...
The other part of the problem is that you're not saving product_info as an attribute of the object. You need to do that when you create it:
self.product_info = ProductInfo(...)
Solved by making product_info a global variable. Not sure if this is best practice however.
I am trying to update a label, but the code I have written creates a new label each time. I am relatively new to tkinter so I couldn't understand how to apply other answers to my code.
from tkinter import *
import random
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master=master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton=Button(self, text="Press", command=calc)
testButton.pack()
l1=Label(text="")
def testbutton(ans): #creates a new instance of l1 each time, I want to update existing l1
var=StringVar()
l1=Label(textvariable=var) #l1.configure() gives error l1 not defined
var.set(ans)
l1.pack()
def calc():
list1=["a","b","c"]
index=random.randint(0,2)
answer=list1[index]
Window.testbutton(answer)
root=Tk()
root.geometry("400x300")
app=Window(root)
root.mainloop()
Each time the button is pressed, a new label is created, instead of updating the text on the existing label.
This is a simplified version of my actual project, but highlights the issue with labels.
I've tried to use l1.configure(...) inside the testbutton function but then it runs an error that l1 isn't defined.
To avoid creating a new Label each time, you need to make one and save it as an attribute of the Window instance. To make it accessible to the calc() function, you'll also need to pass the Window instance to it as an argument (to avoid using global variables). A common why to do that with tkinter is by using a lamba function as the Button's command= argument and making self the default value for its argument as shown below.
from tkinter import *
import random
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton = Button(self, text="Press",
command=lambda win=self: calc(win))
testButton.pack()
self.l1 = Label(text="")
self.l1.pack()
def testbutton(self, ans):
self.l1.configure(text=ans)
def calc(window): # note window argument added
list1 = ["a","b","c"]
index = random.randint(0,2)
answer = list1[index]
window.testbutton(answer)
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
You can just use class methods and attributes.
Use a StringVar to change label text:
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton = Button(self, text="Press", command=self.calc)
testButton.pack()
self.ltext = StringVar()
l1 = Label(textvariable=self.ltext)
l1.pack()
def testbutton(self, ans):
self.ltext.set(ans)
def calc(self):
list1 = ["a", "b", "c"]
index = random.randint(0, 2)
answer = list1[index]
self.testbutton(answer)
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
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.
Similar questions have been asked, but none of them address the particular way my script is constructed:
from Tkinter import *
from ttk import *
class Gui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent) #Gui inherits from built in Frame Class
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Shoes Ware")
self.pack(fill=BOTH, expand=1)
run_val = Entry(self)
run_val["width"] = 5
run_val.place(x=80, y=40)
quit_B = Button(self, text="Submit", command=self.submit)
quit_B.place(x=130, y=170)
def submit(self):
value = run_val.get()
print value
self.quit()
def main():
root = Tk()
root.geometry("300x200+50+50")
app = Gui(root)
root.mainloop()
if __name__ == '__main__':
main()
I get "NameError: global name 'run_val' is not defined" when I hit the submit button. What am I doing wrong here. Right now the print statement is just to check my work. Later on, I'll be using that value in a program.
You are not storing the reference to the Entry widget in initUI.
def initUI(self):
# ...
self.run_val = Entry(self)
self.run_val["width"] = 5
self.run_val.place(x=80, y=40)
Then you can retrieve the value of self.run_val.get() without any problem.