I have code structure something like this:-
def send_message(msg):
print msg + "\n"
x.new_message("You",msg)
class GUI(Frame):
def createWidgets(self):
self.input.bind('<Key-Return>',self.send)
def send(self, event):
send_message(self.contents.get())
self.contents.set("")
def new_message(self,sender, msg):
line = sender+": "+msg+"\n"
self.chat.contents.set(self.chat.contents.get()+line)
def __init__(self):
self.createWidgets()
x = GUI()
As you can see, this has some circular dependancies. Function send_message requires instance x as well as new_message method of GUI. GUI definition needs send_message. Thus it is not possible to satisfy all the constraints. What to do?
In the complete code you showed in die comments we can see that you call self.mainloop() in GUI.__init__. This will start the event handling of the gui and will probably not terminate until the program in finished. Only then the assignment x = GUI() will finish and x will be available.
To circumvent this you have multiple options. Generally doing an endless loop in __init__ is probably a bad idea. Instead call mainloop() after the GUI is instantiated.
def __init__(self):
# only do init
x = GUI()
x.mainloop()
As jasonharper said in python variables in functions are only looked up when you execute that function, not when defining them. Thus circular dependencies in runtime are most of the time not a problem in python.
Names within Python functions are not required to refer to anything at the time the function is defined - they're only looked up when the function is actually called. So, your send_message() is perfectly fine as it is (although it would probably be better to make x a parameter rather than a global variable).
Your GUI class is going to fail to instantiate as shown, due to references to widgets you didn't show the creation of - self.input for example. I cannot tell how much of that is due to you stripping the code down for posting.
Related
I have been trying to use classes for both of my files. I made a gui.py with:
class GuiStart:
def __init__(self, master):
self.master = master
self.master.title("DECTools 1.3")
I have another file with methods I want to execute. This file is called foo.py
class DecToolsClass:
def __init__(self):
self.gui = gui.GuiStart()
I get an error, because I don't give the it the master parameter. I can't set it to None because it doesn't have the .title method.
I execute the gui file with:
if __name__ == "gui":
root = tkinter.Tk()
my_gui = GuiStart(root)
root.mainloop()
The problem is that I need to execute a method from foo.py with my gui.py file and I need to access attributes from my gui.py file with my foo.py file. I have been trying to accomplish this and I know I can't use multiple constructors like in Java.
Is it possible what I want or do I have to rewrite my code?
Thanks in advance!
The GuiStart class starts the tkinter gui. The window with buttons and entries is created with that class. From the GuiStart class I call methods that do things like copy files to a certain location
Alright, so to sum it up, you have a class that handles user interaction, and a set of generic methods doing no user interaction, that GuiStart provides a Gui for. If I understand wrong, this answer will be much less useful.
It is indeed a good idea to split those, but for this split to be effective, you must not have direct references from one another. This means this is a definitive DON'T:
class DecToolsClass:
def __init__(self):
self.gui = gui.GuiStart()
If you actually needed the tools to access the gui, you'd inject it. But normally you would want it the other way around: Tools should be generic and not know about Gui at all. Onn the other hand, Gui knows about them. Assuming the rest of the code is correct (I don't know tkinter):
def main():
tools = DecToolsClass() # not shown, but it no longer has self.gui
root = tkinter.Tk()
my_gui = gui.GuiStart(root, tools)
root.mainloop()
if __name__ == '__main__':
main()
Which means of course GuiStart must take the toolset it will use as an argument:
class GuiStart:
def __init__(self, master, tools):
self.master = master
self.master.title("DECTools 1.3")
self.tools = tools
Now, everywhere in GuiStart, any use of tools must go through self.tools. As an added bonus, in your unittests you can pass a dummy tools object that just checks how it is called, that makes testing very easy.
I have a big problem using tkinter with self here is my code
Could people please give an answer, thanks! The error I get is something like,self could not be given a variable outside a function.
from tkinter import *
root = Tk()
class start():
global self
self = root
def __init__():
self.title('__init__')
self.geometry('300x300')
__init__(self)
class window_extra():
def canvas(self):
global self
selfc = Canvas(self, bg='black').pack()
canvas(self)
self.mainloop()
Thanks!
You should not use self as a variable name as it is used to specify if something is an attribute of the instance of the class.
You do not need to use global in classes either as class attributes are used in most cases when dealing with variables that are needed through the class.
Judging by the code you have shown I think you are trying to do something like this:
from tkinter import *
class start():
def __init__(self, root):
self.master = root
self.master.title('__init__')
self.master.geometry('300x300')
Canvas(self.master, bg='black').pack()
root = Tk()
start(root)
root.mainloop()
However I believe you are struggling with the OOP method of programing and I would suggest to not use OOP to start with if this is the case.
Maybe take a few tutorials on youtube or hit up Codecadamy.
In response to your comments:
In my Opinion using init properly is a bad idea. I use it as a regular def. I doesn't matter if I use self global, unless the function/class variable is called self.
I respect the proper use of init, but I just find the whole thing with, init and self.master I just don't get any of it!
Lack of understanding a thing does not mean said thing is bad. The use of self.master is there to provide a class attribute that ties back to the root Tk() variable. This allows any method within the class to interact with the instance of Tk(). I can't speak to other programing languages but the use of self is a very important in OOP for python. It may not be 100% required to reserve self for referencing to either the instance of the object or the class attribute but it is the accepted and known use of self and really should not be changed/overwritten.
I restructured for some simplicity, but I think that you need a better understanding of objects in Python before going too much further down the GUI route. I think that you mean something like this:
from tkinter import *
# creates a subclass of Tk() called 'Application'; class names by convention
# use CamelCase; best to stick with convention on this one
class Application(tkinter.Tk):
# you don't have to create an explicit invocation of '__init__', it
# is automatically run when you instantiate your class (last line)
def __init__():
super().__init__() # initialize the super class (the 'tkinter.Tk()')
self.title('__init__') # use 'self' to refer to this object - do not declare it as global! it is only valid within the object!
self.geometry('300x300')
self.my_canvas = tkinter.Canvas(self, bg='black') # save an instance of your canvas for easy reference later
self.my_canvas.pack() # pack as a separate step (only required if you plan to use the canvas later... or ever)
self.mainloop() # begin the tkinter loop
# this 'if __name__ ...' is a good idea in most cases, allows you to import `Application` into other
# files without actually running it unless you want to from that other file
if __name__ == '__main__':
Application() # start your class
So I'm trying to build a small game of tic tac toe and I'm using kivy to make it happen. The problem I run into is I have made a grid of 9 buttons (3x3) and now I am binding them (or trying to).
I do all of this within the __init__ method of my class BoardGrid since this should happen only when the program runs the first time.
class BoardGrid(GridLayout):
def __init__(self, **kwargs):
super(BoardGrid, self).__init__(**kwargs)
self.board = []
self.buttons = []
for i in range(9):
self.board.append('')
self.buttons.append(Button(text=self.board[i]))
self.buttons[i].bind(on_press=BoardGrid.callback(????, i))
self.add_widget(self.buttons[i])
def callback(self, btn):
print(btn)
The problem is that the on_press takes a function that it will direct to and this works fine if I let BoardGrid.callback take no arguments, but since I want it to know which button was pressed I want to send in i. This leads to a problem where I need to also pass a BoardGrid into the callback function which I havnt created within the class?
Maybe I'm attacking this from the wrong angle here, I thought I could bind my buttons to a specific input in the callback funciton but that might not be possible.
Any advice on how to get the bindings to work would be much appreciated
EDIT: Seems to be working now, sorry I couldnt reply to everyone, it's my first post and I can't quite seem to understand it yet hehe. Thanks very much for the replies!
from functools import partial
class BoardGrid(GridLayout):
def __init__(self, **kwargs):
...
self.buttons[i].bind(on_press=partial(self.callback, i))
...
def callback(self, btn):
print(btn)
Am having much trouble splitting PyQt code:
main.py
(PyQt modules)
from titles import *
appl = QApplication(sys.argv)
from main import Ui_MainWindow
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
QMainWindow.__init__(self)
self.u = Ui_MainWindow()
self.u.setupUi(self)
Titles(self)
titles.py
import sys
(PyQt modules)
(dbconnections)
class Titles():
def __init__(self, a): #<-- APP IS PASSED AS ARGUMENT AND NOW CALLED 'A'
a.u.table.setModel(titles)
a.u.lineEdit.setText("Titles Init")
a.u.add.clicked.connect(titles.insertRow)
class TitlesTableModel(QSqlTableModel):
def __init__(self):
QSqlTableModel.__init__(self)
self.setTable("titles")
self.setEditStrategy(self.OnFieldChange)
self.select()
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
titles = Titles()
Running main.py loads all data. QPushButton inserts a row, but doesn't set lineEdit to "Insert Title", because "a" isn't defined globally. Mostly tried creating a function in titles.py, triggered when main.py loads, looking like:
a = 0 #<-- THIS WAS A LAST STRAW AS WARNED BY RESEARCHING OTHERS, BUT AM LOST
def start(app):
global a
a = app
Titles(a); TitlesTableModel(a) #<-- EVEN THOUGH TITLES.PY IS IMPORTED, IT DIDN'T INCLUDE THE APP REFERENCE, SO AM TRYING TO 'REFRESH' THE TITLESTABLEMODEL
...with Titles & TitlesTableModel requiring an extra argument (self, a)
This loads data & functions, but again, insertRow doesn't update lineEdit.
Other attempt
change Songs class to
class Songs():
def __init__(self, a):
titles = Titles(a)
...(rest the same)
...and removing titles=Titles() from below the model definition. This again, shows data, but doesn't update lineEdit when pressing 'Add'.
Ultimately, it feels titles.py needs to have 'from main import *', but the main applications instance is defined after titles.py is called, and importing main.Main creates a recursion. Have tried inheriting multiple times via 'from main import Main', & writing 'class Songs(Main)' (so Songs can use the UI without passing a reference), but again, recursion occurs. Nine hours today plus three weeks prior looking at others, so am really stumped. Others somewhat recommended using a config file of even 'builtin', but that looks very bad.
Regards
In PyQt, classes generally use Signals to communicate between one another, especially when one class inherits from QWidget and the other does not inherit from that, as you've demonstrated by connecting signals (albeit wrongly, or at least you're missing bits and pieces of your code here on SO).
However, your insertRow() -> lineEdit method as it stands will never be called because it follows a return statement, meaning that the lineEdit part will never be hit. But I would be surprised if this fixed the problem.
Also, I would consider redesigning (refactoring) your code from the grounds up. Is there really a reason you have a different Titles() class?
While this is shameless self-promotion, I think you might benefit from my course on YouTube that deals with building Python applications using PySide (which is nearly identical to PyQt) - I discuss cross-thread (cross-class) communication a fair bit - link is http://youtube.com/Deusdies2
Your code has several issues, but the main problem is the snippet:
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
as you can see you're returning from the function before the line a.u.lineEdit.setText("Insert Title") get excecuted. Hence, this function willl never change the text of your QLineEdit.
Change your code b
def insertRow(self):
a.u.lineEdit.setText("Insert Title") # First change text.
return self.insertRecord(-1, self.record()) # Then insert record and return.
On the other hand: If you are working with global variables (a bad practice, I have to say) why are you passing it as arguments? Try to not use global variables at least is absolutly necesary.
I have the following program:
class MyClass(object):
def __init__(self):
pass
def hello(self):
print ("hello")
if __name__ == "__main__":
a = MyClass()
a.hello()
It could also be launched as
class MyClass(object):
def __init__(self):
self.hello()
def hello(self):
print ("hello")
if __name__ == "__main__":
MyClass()
Is there a reason to prefer one style over the other, python wise (outside of personal preferences)? In other words: is there a advantage/disadvantage to handle the program general flow and logic within __init__ vs. having that flow outside of the class?
The code is intended to run as a standalone script, pretty much like in the examples above, just more complicated.
I've invented another example that shows the motivation for having a class at all, in your second style. Obviously this is massively over-engineered for what it does. Let's just suppose that aside from your call, there's some other code somewhere that will use the class to do something other than just call one function, so that this complex interface is justified.
class MyClass(object):
def __init__(self):
self.get_config()
self.validate_config()
self.hello()
def get_config(self):
self.message = "hello"
def validate_config(self):
# I'm not claiming this is good practice, just
# an example of multiple methods that share state
if not self.message:
raise Exception()
def hello(self):
print(self.message)
if __name__ == "__main__":
MyClass()
So what do we have here? Basically you're using the call to MyClass not for the purpose of creating an object (although it does do that and you discard it), but in order to execute the object's __init__ method. It works, of course, but it's not "natural". The natural thing is that if you want to run "some stuff" you call a function containing the stuff. You don't especially want it to return some object you don't even care about. If the stuff needs to maintain some state to do its work then the function can handle that, you don't need it to show you the state at the end:
class MyClass(object):
def __init__(self):
self.get_config()
self.validate_config()
def get_config(self):
self.message = "hello"
def validate_config(self):
# I'm not claiming this is good practice, just
# an example of multiple methods that share state
if not self.message:
raise Exception()
def hello(self):
print(self.message)
def main():
MyClass().hello()
if __name__ == "__main__":
main()
This looks more like your first style than your second, so in that sense I prefer the first.
Having a main function might make it a tiny bit easier to use your module under some kind of harness, like a Python prompt or a test harness. It's not necessary, though. If someone wants to do the same as happens when __name__ == '__main__' then worst case they can copy that source.
You can always ask yourself: Is this still the behaviour I want if I instantiate 100 instances of this class?
It is tempting to load everything this object is supposed to do into a single method such as init(self), to make the main method as short as possible. As long as this stays your private script, there is no point in preferring one over the other.
However, once the code is shared, or the class is imported by another script, you increase the reusability by making init() only execute a few necessary initialization commands.
I appreciate your example is only to illustrate your point, and not because you want to print "hello" and need a class to do so ;)
The if __name__ == "__main__": in the file suggests that the file is also suitable for importing. Do you want the class to always print "hello" when instantiated? Normally, behavior is in methods and the __init__ only contains initialization.
Well, you solve different things here. Usually, the purpose of creating an object is not to have it fire off something and then disappear (that’s more a function’s job). Instead, you usually want to object to stay around, and interact with it. As such, you would definitely want to save the object reference in a variable:
obj = MyClass()
Next, you should think about if something should always be called whenever an object is created. If that’s the case, then yes, you probably should put that into the __init__. If it is not true for even just a minor case, then you should probably separate it to make it possible to do initialization and that action separately.
Your example is obviously just very simple so it doesn’t make much sense in the first place. But usually, I would see hello as a public API which I would likely to call when having an object of that type. On the other hand, I wouldn’t expect it to be called automatically just when I create the object.
There might be cases where something like this is useful and desired, but in general, you would prefer calling the method explicitely.