For a couple of days I've been attempting to pass an instance of a variable from one of my classes to another, and until recently I have not been able to get it to work. I've read this document regarding classes and instances, I've searched online and stackoverflow and I couldn't get an answer until I tried a solution from a previous asked question and it solved my problem. However, I'm not exactly sure on the why and the how it works.
My code goes as follows, :
from tkinter import *
def main():
main_window = Tk()
app = First(main_window)
main_window.mainloop()
class First:
def __init__(self, root):
self.root = root
self.root.title('First Window')
self.entry1 = Entry(self.root)
self.entry1.pack()
btn = Button(self.root, text="click", command=self.clicked)
btn.pack()
def clicked(self):
writeDoc(First=self)
class writeDoc:
def __init__(self, First):
self.First = First
txt = self.First.entry1.get()
print(txt)
if __name__ == '__main__'
main()
Under the class writeDoc whenever I hover over the parameter First it is not a reference to the Class First, so I am unsure how it has access to entry1. The same goes for the First within writeDoc(First=self). Addtionally, why does writeDoc(First=self) work but not writeDoc(self.First)?
I assumed when I want to reference to another class and want to pass its instances over I would need to do
class First:
....
def clicked(self):
writeDoc(First)
....
class writeDoc(First):
def __init__(self, First):
super().__init__(First):
...
But, this didn't work for me at all.
I hope this isn't a loaded/jumbled question. I want to understand how this works to create better code and avoid misunderstanding how python classes works.
Inside the clicked() method, self refers to an instance of the First class. It then does
writeDoc(First=self)
which passes that instance to the writeDoc class's __init__() method, as the value of its First parameter. This is no different from passing any other object as a method parameter.
writeDoc(self.First) doesn't work because there's no First attribute in the self instance. First is the name of the class, not an attribute.
Related
I want to change a labeltext from outside of the class through a setter method in the class. Im just getting
AttributeError: type object 'gui' has no attribute 'label'. I tried changing the text through label['text']; label.config(text = 'X')
from tkinter import *
class gui:
def __init__(self):
self.root = Tk()
self.label = Label(self.root, text='Y')
self.label.pack()
self.button = Button(self.root, text='Click', command=self.__btnClick)
self.button.pack()
mainloop()
def __btnClick(self):
changeText()
def setLabelText(self):
self.label['text']= 'X'
def changeText():
gui.setLabelText(gui)
if __name__ == '__main__':
window = gui()
I dont know if it helps but heres my full code
https://pastebin.com/bT43NgpH
Thank you for your help!
You have to call setLabelText on an instance of gui not on the class itself. When you call setLabelText in __btnClick you have to give the instance of gui as a parameter to this function. You've got the instance in the parameter self.
So __btnClick should be altered to:
def __btnClick(self):
changeText(self)
And changeText should be altered to:
def changeText(the_window):
the_window.setLabelText()
I'd like to add a link to the Style Guide for Python Code. Your code is hard to read for an experienced programmer (OK, not that hard, but harder than necessary) because you don't follow the naming conventions.
As I try to make a mini calculator using a Tkinter class, the interpreter returns the "NameError: name 'evaluate' is not defined" error code. I've also tried to define my function evaluate before the "def init" but it still doesn't work.
from tkinter import *
class App(Tk):
def __init__(self):
Tk.__init__(self)
self.entree = Entry(self)
self.chaine = Label(self)
self.entree.bind("<Return>", evaluate)
self.entree.pack()
self.chaine.pack()
def evaluate(self, event):
self.chaine.configure(text="Result = " + str(eval(self.entree.get())))
app = App()
app.mainloop()
thanks for your help!
evaluate is a method inside your App class. The method is accessible anywhere inside the class using its self member. self is the initial class object itself and you cannot access anything(methods, variables etc..) inside the class without this member. Therefore, you should use:
#<---code---->
self.entree.bind("<Return>", self.evaluate)
#<---code---->
I'm sorry for my bad English.
I get an error when I try to get() the Entry named entry from outside the class.
Error:
AttributeError: 'function' object has no attribute 'entry' ""
Example Code:
class asd:
def gui(self, guiwindow, labelplacex, labelplacey, textx, texty, entryx, entryy):
self.root = tk
self.image = tk.PhotoImage(file=aimage_path)
self.label = tk.Label(image=self.image)
self.label.pack()
self.label.place(x=labelplacex , y=labelplacey)
self.text = Label(guiawindow, text="Code:")
self.text.pack()
self.text.place(x = textx,y = texty)
self.entry = Entry(guiwindow)
self.entry.pack()
self.entry.place(x = entryx,y = entryy)
self.button = Button(Tk(), text="Back Menu", command=self.asdfg)
self.button.pack()
self.root.mainloop()
asd.gui.entry.get()
How to do this??
You have two problems. First, you need to create an instance of asd, and second, you need to call the gui method.
For example, something like this:
asd_instance = asd()
asd_instance.gui(...)
asd_instance.entry.get()
Not: ... represents all the parameters that you need to pass to gui, which are irrelevant to the problem. The point being, you must first create an instance of the class before you can get an attribute of the instance. In this case the attribute you want won't exist until you call the gui method. Thus, you must first create an instance, then call the gui method, and only then can you access the attribute.
Try asd.entry.get() instead.
Assuming self.entry has already been defined, you should be able to access it by calling the class itself and then the variable, since the word 'self' means the class itself.
gui in this case is just a function and self.entry belongs to the class asd, not the function gui.
def home(self):
btn = QtGui.QPushButton("Log in", self)
self.show()
if btn.clicked:
btn.clicked.connect(btn.deleteLater)
self.Page()
else:
pass
def Page(self):
btn2 = QtGui.QPushButton("Exit", self)
self.show()
Sorry if the indenting isn't correct here, but it is in my python file:
So the btn does delete when it is pressed, but Page function isn't correctly being run because the btn2 doesn't appear.
This is only the relevant code snippet pasted.
TIA for help as to why the Page function isn't being run. I am using python 2,7 and pyqt4
It looks like btn variable is local inside home method. This means it is only visible within this method (unless it's defined outside in a higher-level scope.)
If you want to share a variable in multiple methods of the class, you should store it as an object property - that's why you'll need some OOP. For example (assuming the made-up rest of your class definition):
class YourApp(object):
def __init__(self):
# All the preparations should go here.
# If self.btn is created later dynamically,
# it's still recommended to declare it here
# and assign `None` to it
self.btn = QtGui.QPushButton("Log in", self)
def home(self):
# Do stuff with self.btn
self.btn.spam()
pass
def page(self):
# Do other stuff with self.btn
self.btn.eggs()
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()