tkinter python function takes 1 argument, given 2 - python

I'm getting this error when I try to run my code:
File "./countdown.py", line 36, in <module>
app = Application(root)
File "./countdown.py", line 16, in __init__
self.create_buttons(self)
TypeError: create_buttons() takes exactly 1 argument (2 given)
Here's my code:
import Tkinter as tk
class Application(tk.Frame):
"""Countdown app - simple timer"""
def __init__(self, master):
"""initialize frame"""
tk.Frame.__init__(self, master)
#super(Application, self).__init__(master)
self.grid()
self.create_buttons(self)
def create_buttons(self):
self.startBttn = Button(app, text = "Start")
self.startBttn.grid()
self.stopBttn = Button(app, text = "Stop")
self.stopBttn.grid()
self.resetBttn = Button(app, text = "Reset")
self.resetBttn.grid()
### Main Code ###
# create the root window using Tk - an object of tkinter class
root = tk.Tk()
# modify the prog. window (set size, title, etc.)
root.title("Countdown")
root.geometry("200x100")
#instantiate Application
app = Application(root)
I've been looking for an answer to this for a while but haven't been able to apply other people's solutions to my code- any ideas? If I remove the tk. before Frame in the class Application declaration I get an error that says Frame not found. If I use super(Application, self).__init__(master) instead of the line above it, I get a type error must be class not class object.

Don't explicitly pass self when calling a bound method. Call it like this:
self.create_buttons()
By calling the method with self.create_buttons(self) the function receives two arguments: the implicit self that is passed when calling a bound method (Python does this automatically), and the explicit self that you pass in the method call.
There are also some other problems with create_buttons() which you can fix with this code:
def create_buttons(self):
self.startBttn = tk.Button(self, text = "Start")
self.startBttn.grid()
self.stopBttn = tk.Button(self, text = "Stop")
self.stopBttn.grid()
self.resetBttn = tk.Button(self, text = "Reset")
self.resetBttn.grid()
The changes are that you need to use tk.Button to reference the Button class, and to pass self to tk.Button which is a reference to the parent frame. Here self is the Application instance which is a subclass of tk.Frame - hence self is a frame.
Finally you need to add a call to mainloop():
#instantiate Application
app = Application(root)
root.mainloop()
Regarding the problem with super, the tkinter classes are of the "old-style" type and do not support super(). Therefore you must call the base class with tk.Frame.__init__(self, master).
There is a workaround by using multiple inheritance and including object as a base class. If you declare Application as :
class Application(tk.Frame, object):
def __init__(self, master):
"""initialize frame"""
super(Application, self).__init__(master)
then you can use super(), but it's hardly worth the effort.

Related

How do I to call a custom object with custom style methods and use it as a style for a label(and widgets in general) in tkinter?

So I am trying to import my own custom style methods into my main app to then use as a custom style in ttk.Label(), by calling the class method, but I'm having trouble finding a way to call it. Below is the example code of the main app.
import tkinter as tk
from tkinter import ttk
from custom_styles import customStyle
class MainApp:
def __init__(self, master):
self.master = master
**initialization code****
#----style methods-----#
self.styled = customStyle(self.master)
#title label
self.title_label = ttk.Label(self.master, text="test", style=self.styled.test())
self.title_label.pack()
And below is the class I am calling the methods above from, which is different file.
from tkinter import ttk
import tkinter as tk
class customStyle:
def __init__(self, master) -> None:
self.master = master
def test(self):
style = ttk.Style()
style.configure("test.TLabel",
foreground="white",
background="black",
padding=[10, 10, 10, 10])
I've tried to call just the name of the style method like this
self.title_label = ttk.Label(self.master, text="test", style='test.TLabel')
I've also tried to call the method by calling the class then method like this
self.title_label = ttk.Label(self.master, text="test", style=self.styled.test())
I knew this wouldn't work, but I still tried it
self.title_label = ttk.Label(self.master, text="test", style=self.styled.test('test.TLabel'))
I also tried not making an object out of the methods, so I took away the class and just made a list of functions, but that didn't work either. Of course, I looked on the internet and searched stack for questions, but to no avail. Maybe this structure I am trying to maintain is not efficient?
I'm honestly just looking to understand a way to call the methods w/o putting them in the same file, but I just don't know how to.
The style option requires the name of a style as a string. Since your function test returns None, it's the same as if you did ttk.Label(..., style=None)
One solution is to have your test function return the style name:
def test(self):
...
return "test.TLabel"
Of course, that means you can only use it for that one specific style. Another solution is that you leave it as-is and return nothing. In that case you can just hard-code the style. You must ensure that you call the test function, however, so that the style is initialized.
self.styled.test()
self.title_label = ttk.Label(self.master, text="test", style="test.TLabel")
Arguably, a better option would be to add attributes to the class, and initialize the styles when you instantiate the class. It might look something like this:
class customStyle:
def __init__(self, master) -> None:
self.master = master
style = ttk.Style()
style.configure("test.TLabel",...)
...
self.label = "test.TLabel"
self.button = "test.TButton"
self.scrollbar = "test.TScrollbar"
...
class MainApp:
def __init__(self, master):
self.master = master
self.styled = customStyle(self.master)
self.title_label = ttk.Label(..., style=self.styled.label)
...
There are probably even better ways to do this. The point is, you need to pass a valid style name as a string to the style parameter of a ttk widget.

Using .get() to pull a Tkinter variable from another class

I am writing a Tkinter application that requires parts of the user display to exist in two different class, both imported from another file. I need to take a piece of user input and pass it from one class to another. In the toy example below, the user is supposed to type something into my_entry_input which later the class PullVariable is supposed to access.
Code is below. I had a few thoughts, such as somehow using globals or creating a function within the original class to get the variables and then pass them back. In all cases, I get:
AttributeError: type object 'Application' has no attribute 'my_entry'
The best solution I can think of is to create a function that responds to the binding, then pass the .get() to the other class from that function. My feeling is that tkinter doesn't like .get() in between classes.
Thanks to the community for your help.
MAIN
from import_test1 import *
root=Tk()
ui = Application(root)
ui.hello_world()
ui.entry()
pv = PullVariable()
if __name__ == '__main__':
root.mainloop()
IMPORTED CODE
from tkinter import *
from tkinter import ttk
class Application(Frame):
def __init__(self, parent, *args, **kwargs):
print('Application init')
Frame.__init__(self, parent, *args, **kwargs)
self.parent=parent
self.parent.grid()
def entry(self):
self.my_entry = StringVar(self.parent)
my_entry_input = Entry(self.parent, textvariable=self.my_entry,
width=16)
my_entry_input.bind('<FocusOut>', self.show_entry)
my_entry_input.grid(column=0, row=1)
self.show_label = Label(self.parent, text = '')
self.show_label.grid(column=0, row=2)
def hello_world(self):
print('hello world')
self.hw = Label(self.parent, text='Hello World!')
self.hw.grid(column=0, row=0)
def show_entry(self, event):
PullVariable(Application).find_entry()
class PullVariable:
def __init__(self, app):
self.app = app
print('Pull initiated')
def find_entry(self, event=None):
self.pulled_entry = self.app.my_entry.get()
self.app.show_label['text'] = self.pulled_entry
my_entry is not a attribute of Application class, so you can't do Application.my_entry, by it is an attribute of instance of Application class, so you can do Application().my_entry. You can probably add either instance of Application or my_entry to the __init__ method of PullVariable. I'll use the former.
# ...
class PullVariable:
def __init__(self, app): # add app here
self.pulled_entry = app.my_entry.get() # use app here
print(self.pulled_entry)
# and then
root=Tk()
ui = Application(root)
ui.hello_world()
ui.entry()
pv = PullVariable(ui) # supply PullVariable with instance of Application

Tkinter code not showing button (v:3.6)

This is my practice from youtube, It's not showing button in window
import tkinter as tk
class Window(Frame):
def _init_ (self, master =None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title('GUI')
self.pack(fill = BOTH, expand = 1)
quitButton = Button(self, text = "Quit")
quitButton.place(x=0, y =.1)
root = tk.Tk()
root.title('GUI')
root.geometry()
app = Window(master=root)
root.mainloop()
Just change your _init_ to __init__.
Python constructor syntax has double underscore.
UNDERSTANDING SELF AND __INIT__ METHOD IN PYTHON CLASS.
__init__ is a reseved method in python classes. It is known as a constructor in object oriented concepts. This method called when an object is created from the class and it allow the class to initialize the attributes of a class.

Python, accessing widget items from outside of a class

I have an auto generated code which generates a GUI that has various widgets in it. One of the widget is a ScrolledListBox. A part of the code is shown below:
class New_Toplevel_1:
def __init__(self, top=None):
self.Scrolledlistbox4.configure(background="white")
self.Scrolledlistbox4.configure(font="TkFixedFont")
self.Scrolledlistbox4.configure(highlightcolor="#d9d9d9")
self.Scrolledlistbox4.configure(selectbackground="#c4c4c4")
self.Scrolledlistbox4.configure(width=10)
I want to access the Scrolledlistbox4 from outside this class. So for example, I would like to write to write a function that updates the ScrolledListBox whenever I call it. I am relatively new to python and would like to know how can I accomplish this.
You need to first create a Scrolledlistbox4 object as an attribute:
self.scrolled_listbox = Scrolledlistbox4(...)
then you can do all configures in outermost scope like:
a = New_Toplevel_1()
a.scrolled_listbox.configure(background='white')
...
In below example "Outside Button" changes the text option of a class' button from the outside:
import tkinter as tk
class FrameWithButton(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.btn = tk.Button(root, text="Button")
self.btn.pack()
root = tk.Tk()
an_instance = FrameWithButton(root)
an_instance.pack()
def update_button():
global an_instance
an_instance.btn['text'] = "Button Text Updated!"
tk.Button(root, text="Outside Button", command=update_button).pack()
root.mainloop()

Tkinter Toplevel in OOP script: how?

Goal of the script:
(3) different windows, each in its own class, with its own widgets and layout, are created via Toplevel and callbacks.
When a new (Toplevel) window is created, the previous one is destroyed. Thus, only one window is visible and active at a time.
Problem?
Basically, I've tried many things and failed, so I must understand too little of ["parent", "master", "root", "app", "..."] :(
Note on raising windows:
I have implemented a successful example of loading all frames on top of each other, and controlling their visibility via the .raise method.
For this problem, however, I don't want to load all the frames at once.
This is an abstracted version of a quiz program that will require quite a lot of frames with images, which makes me reluctant to load everything at once.
Script (not working; bugged):
#!/usr/bin/env python
from Tkinter import *
import tkMessageBox, tkFont, random, ttk
class First_Window(Frame):
"""The option menu which is shown at startup"""
def __init__(self, master):
Frame.__init__(self, master)
self.gotosecond = Button(text = "Start", command = self.goto_Second)
self.gotosecond.grid(row = 2, column = 3, sticky = W+E)
def goto_Second(self):
self.master.withdraw()
self.master.update_idletasks()
Second_Window = Toplevel(self)
class Second_Window(Toplevel):
"""The gamewindow with questions, timer and entrywidget"""
def __init__(self, *args):
Toplevel.__init__(self)
self.focus_set()
self.gotothird = Button(text = "gameover", command = self.goto_Third)
self.gotothird.grid(row = 2, column = 3, sticky = W+E)
def goto_Third(self):
Third_Window = Toplevel(self)
self.destroy()
class Third_Window(Toplevel):
"""Highscores are shown with buttons to Startmenu"""
def __init__(self, *args):
Toplevel.__init__(self)
self.focus_set()
self.master = First_Window
self.gotofirst = Button(text = "startover", command = self.goto_First)
self.gotofirst.grid(row = 2, column = 3, sticky = W+E)
def goto_First(self):
self.master.update()
self.master.deiconify()
self.destroy()
def main():
root = Tk()
root.title("Algebra game by PJK")
app = First_Window(root)
root.resizable(FALSE,FALSE)
app.mainloop()
main()
The problem is not really a Tkinter problem, but a basic problem with classes vs. instances. Actually, two similar but separate problems. You probably need to read through a tutorial on classes, like the one in the official Python tutorial.
First:
self.master = First_Window
First_Window is a class. You have an instance of that class (in the global variable named app), which represents the first window on the screen. You can call update and deiconify and so forth on that instance, because it represents that window. But First_Window itself isn't representing any particular window, it's just a class, a factory for creating instances that represent particular windows. So you can't call update or deiconify on the class.
What you probably want to do is pass the first window down through the chain of windows. (You could, alternatively, access the global, or do various other things, but this seems cleanest.) You're already trying to pass it to Second_Window, you just need to stash it and pass it again in the Second_Window (instead of passing self instance, which is useless—it's just a destroyed window object), and then stash it and use it in the Third_Window.
Second:
Second_Window = Toplevel(self)
Instead of creating an instance of the Second_Window class, you're just creating an instance of the generic Toplevel class, and giving it the local name Second_Window (which temporarily hides the class name… but since you never use that class, that doesn't really matter).
And you have the same problem when you try to create the third window.
So:
class First_Window(Frame):
# ...
def goto_Second(self):
# ...
second = Second_Window(self)
class Second_Window(Toplevel):
def __init__(self, first, *args):
Toplevel.__init__(self)
self.first = first
# ...
def goto_Third(self):
third = Third_Window(self.first)
self.destroy()
class Third_Window(Toplevel):
"""Highscores are shown with buttons to Startmenu"""
def __init__(self, first, *args):
Toplevel.__init__(self)
self.first = first
# ...
def goto_First(self):
self.first.update()
self.first.deiconify()
self.destroy()

Categories

Resources