Python Tkinter -- object has no attribute 'tk' - python

I am creating a gui using tkinter, i need to work with a login window and subsequent windows, i am unable to place any label on new windows as it says 'testclass' object has no attribute 'tk'
My main objective is to create a new window after logging in and hiding the login window and then work with the new window and place label and create a form
from tkinter import *
import tkinter.messagebox as tm
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.label_username = Label(self, text="Username")
self.label_password = Label(self, text="Password")
self.entry_username = Entry(self)
self.entry_password = Entry(self, show="*")
self.label_username.grid(row=0, sticky=E)
self.label_password.grid(row=1, sticky=E)
self.entry_username.grid(row=0, column=1)
self.entry_password.grid(row=1, column=1)
self.logbtn = Button(self, text="Login", command=self._login_btn_clicked)
self.logbtn.grid(columnspan=2)
self.pack()
# def verifycred(self,username,password):
def _login_btn_clicked(self):
username = self.entry_username.get()
password = self.entry_password.get()
# verify_out = self.verifycred(username,password)
self.newWindow = Toplevel(self.master)
self.app = randomclass(self.newWindow)
class randomclass(LoginFrame):
def __init__(self,master):
self.master = master
self.master.title("Random Class")
self.master.geometry("1350x750+250+150")
self.master.config(bg ='cadet blue')
self.frame = Frame(self.master, bg = 'powder blue')
self.frame.pack()
self.test = Button(self.frame,text='Random',width = 25, command = self.random)
self.test.grid(row=4,column=0)
def random(self):
self.newWindow = Toplevel(self.master)
self.app = testclass(self.newWindow)
class testclass(LoginFrame):
def __init__(self,master):
self.master = master
self.master.title("Test")
self.master.geometry("1350x750+250+150")
self.master.config(bg ='cadet blue')
self.frame = Frame(self.master, bg = 'powder blue')
self.frame.pack()
self.welcome = Label(self,text='Hello')
self.welcome.grid(row=0,column=1)
root = Tk()
lf = LoginFrame(root)
root.mainloop()

There's Only small problem that you are forgot to write self.master inside a label widget declaration of testclass.
Here's The Solution,
class testclass(LoginFrame):
def __init__(self,master):
self.master = master
self.master.title("Test")
self.master.geometry("1350x750+250+150")
self.master.config(bg ='cadet blue')
self.frame = Frame(self.master, bg = 'powder blue')
self.frame.grid(row = 0,column = 0)
self.welcome = Label(self.master,text='Hello')
self.welcome.grid(row=0,column=1)

Related

Edit/add Tkinter widget in one Tkinter class from another Tkinter class

Suppose I have two tkinter classes which act as separate windows. How could I edit any given widget from one class in the other tkinter class. ALso, how could I add a widget in one tkinter class from the other tkinter class?
from tkinter import Tk, Label, Button
class MyFirstGUI:
def __init__(self, master):
self.master = master
master.title("A simple GUI")
self.label = Label(master, text="This is
our first GUI!")
self.label.pack()
self.greet_button = Button(master,
text="Greet", command=self.greet)
self.greet_button.pack()
self.close_button = Button(master,
text="Close", command=master.quit)
self.close_button.pack()
def greet(self):
print("Greetings!")
root = Tk()
my_gui = MyFirstGUI(root)
root.mainloop()
from tkinter import Tk, Label, Button
class MyFirstGUI2:
def __init__(self, master):
self.master = master
master.title("A simple GUI")
self.label = Label(master, text="This is
our first GUI!")
self.label.pack()
self.greet_button = Button(master,
text="Greet", command=self.greet)
self.greet_button.pack()
self.close_button = Button(master,
text="Close", command=master.quit)
self.close_button.pack()
def greet(self):
print("Greetings!")
root = Tk()
my_gui = MyFirstGUI2(root)
root.mainloop()
I think it would be better to use a Toplevel widget for your two windows (or at least one of them). Right now your first window will be created and the code will stop when it gets to the root.mainloop() line. The second window will not be created until you close the first one.
And you can pass in a reference from each class.
import tkinter
from tkinter import Tk, Label, Toplevel, Button
class MainWidget:
def __init__(self, master):
self.master = master
self.widgetTwo = None
self.label = Label(self.master, text='Widget One')
self.label.pack()
class WidgetTwo(Toplevel):
def __init__(self, master, mainWidget):
Toplevel.__init__(self, master)
self.master = master
self.mainWidget = mainWidget
self.labelTwo = Label(self, text='Widget Two')
self.labelTwo.pack()
Button(self, text='Change Main Widget Text', command=self.ChangeMainWidgetLabel).pack()
def ChangeMainWidgetLabel(self):
self.mainWidget.label.config(text='Widget One text changed')
mw = Tk()
mainWidget = MainWidget(mw)
widgetTwo = WidgetTwo(mw, mainWidget)
mainWidget.widgetTwo = widgetTwo
mw.mainloop()

resizable window frame in tkinter

I created a window with tkinter for my programm but I want it to resize itself when the user resizes the window. Right now when I increase or decrease the size of the window the widgets stay at the same position and don't in-/decrease in size.
Here is my code:
import tkinter as tk
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.check1 = tk.IntVar()
self.fileopenname1 = tk.StringVar()
self.entrystring = tk.IntVar()
self.menubar = tk.Menu(self)
self.create_widgets()
def create_widgets(self):
self.filemenu=tk.Menu(self.menubar,tearoff=0)
self.menubar.add_cascade(label="File",menu=self.filemenu)
self.filemenu.add_command(label="Exit",command = root.destroy)
self.helpmenu=tk.Menu(self.menubar,tearoff=0)
self.programmstart = tk.Button(self, text = "Start Program")
self.programmstart.grid(row=10,column=8,sticky = "W")
self.checkbutton1 = tk.Checkbutton(self, text = "Drehzahl und Drehmoment",variable=self.check1,onvalue=1,offvalue=0)
self.checkbutton1.grid(row=0,column=0,columnspan=3,sticky = "W")
self.leer1 = tk.Label(self,text=" ") #erzeugt leere Zelle, sonst ist startbutton links
self.leer1.grid(row=0,column=3,columnspan=5)
self.leer2 = tk.Label(self,text=" ")
self.leer2.grid(row=5,column=8,rowspan=2)
self.leer3 = tk.Label(self,text=" ")
self.leer3.grid(row=9,column=9)
self.inputpathdisplay = tk.Label(self,textvariable=self.fileopenname1,bg="white",width=60)
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
self.inputpathdisplaylabel = tk.Label(self,text="Inputfile")
self.inputpathdisplaylabel.grid(row=0,column=8,columnspan=3)
root = tk.Tk()
app = Graphicaluserinterface(master=root)
app.master.title("Programm")
app.master.minsize(800,300)
root.config(menu=app.menubar)
app.mainloop()
You need to configure the weight on your grid's rows and columns. The following is a refactored version of your code that should act a little more as you were hoping. Please continue development from this code:
#! /usr/bin/env python3
import tkinter
from tkinter.constants import *
class GraphicalUserInterface(tkinter.Frame):
#classmethod
def main(cls):
root = tkinter.Tk()
root.title('Program')
root.minsize(560, 105)
gui = cls(root)
gui.grid(row=0, column=0, sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root['menu'] = gui.menubar
cls.create_toplevel(root, 'First Toplevel')
root.mainloop()
#staticmethod
def create_toplevel(root, window_title):
window = tkinter.Toplevel(root)
window.title(window_title)
window.minsize(560, 105)
def __init__(self, master=None):
super().__init__(master)
self.check_value = tkinter.BooleanVar()
self.filename = tkinter.StringVar()
self.menubar = tkinter.Menu(self)
self.file_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.help_menu = tkinter.Menu(self.menubar, tearoff=FALSE)
self.program_start = tkinter.Button(
self, text='Start Program',
command=lambda: self.create_toplevel(self.master, 'Another Window')
)
self.check_button = tkinter.Checkbutton(
self, text='Speed ​​& Torque', variable=self.check_value,
onvalue=True, offvalue=False
)
self.input_path_display = tkinter.Label(
self, textvariable=self.filename, bg='white', width=60
)
self.input_path_display_label = tkinter.Label(self, text='Input File')
self.create_widgets()
def create_widgets(self):
self.menubar.add_cascade(label='File', menu=self.file_menu)
self.file_menu.add_command(label='Exit', command=self.master.destroy)
pad = dict(padx=5, pady=5)
self.check_button.grid(row=0, column=0, **pad)
self.input_path_display_label.grid(row=0, column=1, sticky=EW, **pad)
self.input_path_display.grid(row=1, column=1, sticky=NSEW, **pad)
self.program_start.grid(row=2, column=1, sticky=EW, **pad)
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(1, weight=1)
if __name__ == '__main__':
GraphicalUserInterface.main()

Calling function from different class gives TypeError: missing 1 required positional argument

I was trying to build something where I wanted to give separate class to each frames. Now when I called onSet function of AddWidgets class it shows an
ERROR: TypeError: onSet() missing 1 required positional argument: 'text'
What am I doing wrong? And how to solve this? My Code is given below:
import tkinter as tk
from tkinter import ttk
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.wm_iconbitmap('icon.ico')
self.master.geometry("360x240+100+100")
self.frame1 = ttk.Frame(self.master)
self.frame1.grid(row=0, column=0, padx=16, pady=16)
self.frame2 = ttk.Frame(self.master)
self.frame2.grid(row=0, column=1, padx=16, pady=16)
self.add = AddWidgets(self.frame1)
self.edit = EditWidgets(self.frame2)
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
def onSet(self, text):
self.label1.configure(text=text)
class EditWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
def onEdit():
self.send_text = self.entry_text.get()
AddWidgets.onSet(self.send_text)
self.entry_text = tk.StringVar()
self.entry1 = ttk.Entry(self.master, textvariable=self.entry_text)
self.entry1.grid(row=0, column=0, padx=4, pady=4)
self.button1 = ttk.Button(self.master, text="edit", command=onEdit)
self.button1.grid(row=0, column=1, padx=4, pady=4)
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
I am new to Python and tkinter. I want to build a desktop app/software. I want to develop the software by following MVC pattern. So any resource for MVC in tkinter and suggestions on how can I improve my coding, software development process would be appreciated.
The method onSet requires the instance of the class as a first argument, while you're only passing the text argument. So when you call your onSet method you should pass the instance of the AddWidgets class as first argument.
You're instantiating this class in the MainWindow class:
self.add = AddWidgets(self.frame1)
So you should pass the self.add variable to the onSet function. In order to do that you should have your EditWidget class accept an additional parameter widget:
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.wm_iconbitmap('icon.ico')
self.master.geometry("360x240+100+100")
self.frame1 = ttk.Frame(self.master)
self.frame1.grid(row=0, column=0, padx=16, pady=16)
self.frame2 = ttk.Frame(self.master)
self.frame2.grid(row=0, column=1, padx=16, pady=16)
self.add = AddWidgets(self.frame1)
self.edit = EditWidgets(self.frame2, self.add) <--Add parameter self.add
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
def onSet(self, text):
self.label1.configure(text=text)
class EditWidgets:
def __init__(self, master, widget): <-- add parameter widget
self.master = master
self.create_widgets()
self.widget = widget
def create_widgets(self):
def onEdit():
self.send_text = self.entry_text.get()
self.widget.onSet(self.send_text) <--call onSet from widget instance
[...]
EDIT:
If you want to create different tabs, all with the same widgets, one approach could be the following: you create a MainWindow class, where you add all the tabs to your window using the Notebook class.
Then you create a Add Widgets class that adds the required widgets to a frame. You instantiate this class on each of the created tabs, in order to populate them with the widgets.
In order to get the values of the variables you set in each tab you can write a method getEntryValue (or whatever name) that returns the value set on the entry. Something like this:
class MainWindow:
def __init__(self, master):
self.master = master
self.master.title("Class Function")
self.master.geometry("360x240+100+100")
n = ttk.Notebook(master)
self.f1 = ttk.Frame(n) # Create first tab
self.f2 = ttk.Frame(n) # Create second tab
n.add(self.f1, text='One')
n.add(self.f2, text='Two')
n.pack()
self.widget1 = AddWidgets(self.f1)
self.widget2 = AddWidgets(self.f2)
class AddWidgets:
def __init__(self, master):
self.master = master
self.create_widgets()
def create_widgets(self):
def onEdit():
send_text = self.entry_text.get()
self.label1.configure(text = send_text)
self.label1 = ttk.Label(self.master, text="0")
self.label1.grid(row=0, column=0, padx=4, pady=4)
self.entry_text = tk.StringVar()
self.entry1 = ttk.Entry(self.master, textvariable=self.entry_text)
self.entry1.grid(row=0, column=1, padx=4, pady=4)
self.button1 = ttk.Button(self.master, text="edit", command=onEdit)
self.button1.grid(row=0, column=2, padx=4, pady=4)
def getEntryText(self):
return self.entry_text.get()
Hope it helps.

How to close a current window and open a new window at the same time?

This code opens a button, which links to another button. The other button can close its self, but the first button can't close itself and open a new one at the same time, How do I fix this?
import tkinter as tk
class Demo1:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.HelloButton = tk.Button(self.frame, text = 'Hello', width = 25, command = self.new_window,)
self.HelloButton.pack()
self.frame.pack()
def close_windows(self):
self.master.destroy()
self.new_window
def new_window(self):
self.new_window = tk.Toplevel(self.master)
self.app = Demo2(self.new_window)
class Demo2:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.master.destroy()
def main():
root = tk.Tk()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
Try redefine your Demo1.new_window() as below:
def new_window(self):
self.master.destroy() # close the current window
self.master = tk.Tk() # create another Tk instance
self.app = Demo2(self.master) # create Demo2 window
self.master.mainloop()
Try this:
import tkinter as tk
class windowclass():
def __init__(self, master):
self.master = master
self.btn = tk.Button(master, text="Button", command=self.command)
self.btn.pack()
def command(self):
self.master.withdraw()
toplevel = tk.Toplevel(self.master)
toplevel.geometry("350x350")
app = Demo2(toplevel)
class Demo2:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.master.destroy()
root = tk.Tk()
root.title("window")
root.geometry("350x350")
cls = windowclass(root)
root.mainloop()
Or maybe sometimes, you want to do something else, you can hide it.
def __init__(self, parent):
self.root = parent
self.root.title("Main")
self.frame = Tk.Frame(parent)
self.frame.pack()
btn = Tk.Button(self.frame, text="New", command=self.openFrame)
btn.pack()
def hide(self):
self.root.withdraw()
def openFrame(self):
self.hide()
otherFrame = Tk.Toplevel()
otherFrame.geometry("400x300")
handler = lambda: self.CloseOtherFrame(otherFrame)
btn = Tk.Button(otherFrame, text="Close", command=handler)
btn.pack()
def CloseOtherFrame(self, otherFrame):
otherFrame.destroy()
self.show()

Creating a dynamic multiplication application using scales

I am currently really stuck trying to make a program that dynamically multiples two numbers as a scale is moved from left to right.
# Module imports
import Tkinter as tk
# Function Definitions
class Application(tk.Frame):
def __init__(self, parent = None):
tk.Frame.__init__(self, parent)
self.parent = parent
self.setupUI()
self.createWidgets()
def setupUI(self):
self.parent.title("Multiplication Scale")
self.grid()
self.centerWindow()
def centerWindow(self):
app_width = 400
app_height = 250
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw - app_width)/2
y = (sh - app_height)/2
self.parent.geometry('%dx%d+%d+%d' % (app_width, app_height, x, y))
def quit_pressed(self):
self.parent.destroy()
def createWidgets(self):
self.value1 = tk.IntVar()
self.scaleFirstN = tk.Scale(self, from_=0, to=100,tickinterval=10,orient=tk.HORIZONTAL)
self.scaleFirstN.grid(row=0,column=0,columnspan=5,ipadx=100,padx=40,pady=10,sticky="n")
self.value1 = tk.IntVar()
self.scaleSecondN = tk.Scale(self, from_=0, to=100,tickinterval=10, orient=tk.HORIZONTAL)
self.scaleSecondN.grid(row=1,column=0,columnspan=5,ipadx=100,padx=40,pady=0,sticky="n")
self.value2 = tk.IntVar()
self.label1 = tk.Label(self,textvariable=self.value1, text=0,foreground="blue")
self.label1.grid(row=5,column=0,columnspan=5, ipadx=5, sticky="wes")
self.label2 = tk.Label(self,textvariable=self.value1, text=0,foreground="blue")
self.label2.grid(row=1,column=0,columnspan=5, ipadx=5, sticky="we")
self.label3 = tk.Label(self,textvariable=self.value1, text=0,foreground="blue")
self.label3.grid(row=1,column=0,columnspan=5, ipadx=5, sticky="we")
def onScale(self, val):
value = self.scale.get()
self.value.set(value)
# Main body
root = tk.Tk()
app = Application(root)
root.mainloop()
You were creating value1 twice and not doing anything with value2, then onScale() wasn't doing anything. You must set each Scale widget's command option to the desired callback function (onScale in this case).
def createWidgets(self):
self.value1 = tk.IntVar()
self.scaleFirstN = tk.Scale(self, from_=0, to=100,tickinterval=10,orient=tk.HORIZONTAL, command=self.onScale, var=self.value1)
self.scaleFirstN.grid(row=0,column=0,columnspan=5,ipadx=100,padx=40,pady=10,sticky="n")
self.value2 = tk.IntVar()
self.scaleSecondN = tk.Scale(self, from_=0, to=100,tickinterval=10, orient=tk.HORIZONTAL, command=self.onScale, var=self.value2)
self.scaleSecondN.grid(row=1,column=0,columnspan=5,ipadx=100,padx=40,pady=0,sticky="n")
self.label1 = tk.Label(self,textvariable=self.value1, text=0,foreground="blue")
self.label1.grid(row=5,column=0,columnspan=5, ipadx=5, sticky="wes")
self.label2 = tk.Label(self,textvariable=self.value2, text=0,foreground="blue")
self.label2.grid(row=6,column=0,columnspan=5, ipadx=5, sticky="we")
self.label3 = tk.Label(self, text=0,foreground="blue")
self.label3.grid(row=7,column=0,columnspan=5, ipadx=5, sticky="we")
def onScale(self, val):
self.label3.config(text=self.value1.get() * self.value2.get())

Categories

Resources