This is a problem I've found the solution to, but not the answer to. The following is the relevant part of my code:
class MyClass(QGraphicsPolygonItem, MyAbstractGraphicsShapeItem, MyGraphicsItem)
def __init__(self):
super(MyClass, self).__init__()
The first class is the type of graphics object I'm trying to create. For me, the first one I did was a polygon. The second class is one which needed to inherit QAbstractGraphicsShapeItem to change the objects color through. The third class works with any QGraphicsItem. To make everything modular and reusable, this was my setup.
The issue I faced was as such:
If the first class was after the second class, MyClass would no longer recognize it had a polygon I could set.
If the third class was before the second class, MyClass would stop painting itself, showing up in no way on screen.
As you can see, the sequence shown in my code is the only one that works. One of the sequences (third, first, second) even crashes the program. Here is what I think happens:
The graphic item classes inherit in this order, from superclass <--- subclass.
QGraphicsItem <--- QAbstractGraphicsShapeItem <--- QGraphicsPolygonItem
When the initialization priority is the same as the inheritance direction from subclasses to superclasses, the inheritance works.
The Point
This is what I think the initialization order looks like in these situations:
MyAbstractgraphicsShapeItem, QGraphicsPolygonItem, MyGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsItem
QGraphicsPolygonItem, MyGraphicsItem, MyAbstractgraphicsShapeItem, QAbstractGraphicsShapeItem, QGraphicsItem
QGraphicsPolygonItem, MyAbstractgraphicsShapeItem, MyGraphicsItem, QAbstractGraphicsShapeItem, QGraphicsItem
Where the third is the working one.
I cannot see the difference between them. I know how it should work but not why. The initialization order shouldn't matter, as the super call should order them like this, where there are no conflicts between functionality. I know that QAbstractGraphicsShapeItem doesn't have boundingRect or paint functions, but I believe they should be overwritten by QGraphicsPolygonItem class functions. I would like an answer, because this was a really baffling issue to solve.
Edit:
I'll add the other two classes, just the relevant parts:
class MyGraphicsItem(QGraphicsItem):
def __init__(self):
super(MyQGraphicsItem, self).__init__()
class MyAbstractGraphicsShapeItem(QAbstractGraphicsShapeItem):
def __init__(self):
super(MyAbstractGraphicsShapeItem, self).__init__()
For additional detail, MyGraphicsItem allows me to place graphics items in relation to the parent as I wish, while MyAbstractGraphicsShapeItem allows me to create button like behavior (since QAbstractButton only works with QWidgets).
Related
In writing a tkinter root window as a class, I'm using the following code:
class RootWin(Tk):
def __init__(self,...args go here...):
super().__init__()
Although the code is correct, and works, I am uncomfortable writing code that I don't fully understand, and despite the many explanations I have come across, none have clarified this for me.
I understand that the line class RootWin(Tk): indicates that I am creating a class called RootWin that inherits from Tk. In the next line, self refers to the instance of this class I will create later in my code, and the args specify the parameters I want to pass to this specific instance. That much is very clear.
Then, the explanations I've come across indicate that super().__init__() runs the init method of Tk (the parent class).
But why is it necessary to run the init method of the Tk class? If class RootWin(Tk) already indicates that my new RootWin class inherits from Tk, then why would anything more be required?
Perhaps the best way to pose this question is to ask it in three explicit parts, and request three answers, with apologies, if that's asking a lot. I really want to understand this!
Question 1: What is accomplished by the line
class RootWin(Tk):
Question 2: What is accomplished by the line
def __init__(self,...args go here...):
Question 3: what is accomplished by the following line that has not already been accomplished by the two previous lines?
super().__init__()
Any advice appreciated.
But why is it necessary to run the init method of the Tk class?
Your own class has some initialization it performs, correct? There is code in your __init__ that must run for your class to be useful. This is where, for example, you would create other widgets for your app, variables, etc.
The tkinter base classes are the same way. They have code in their own __init__ method that must be run for the class to be useful. This code doesn't run automatically if you create your own __init__. Therefore, you must call it so that the widget is properly initialized.
Question 1: What is accomplished by the line class RootWin(Tk):
Answer: it begins the definition of a new class name RootWin that inherits from the class Tk
Question 2: What is accomplished by the line def __init__(self,...args go here...)
Answer: it defines a method that is automatically called by python when you create an instance of your custom class. It also defines the arguments that your function may require.
When you do foo = RootWin(), python will automatically call RootWin.__init__ and pass in the instance (self) as the first argument. The rest are to be supplied by the caller.
Question 3: what is accomplished by the following line that has not already been accomplished by the two previous lines? super().__init__()
Answer: First, it has not been accomplished by the two previous lines. Because of the two previous lines, python will not automatically call the __init__ method of the base class. That responsibility becomes yours when you define a custom __init__. When you call super().__init__() you are explicitly requesting that the __init__ method of the base class be called.
The advantage to requiring you to explicitly call it is that you now have a choice of when or if to call it. While you almost always should, you might choose to do some custom initialization either before or after the base class has been initialized.
Note that none of this is unique to tkinter. This is how all python objects work.
I've been working in python on a project where I have a GUI which I split up a bunch of the work between classes. I don't know a lot of the best practices for passing data around between classes, and I've frequently run into the issue, where I have to implement something, or change something for work, and I've resorted to making a lot of the classes objects of another class in order to give it the data I need.
Any ideas or suggests would be greatly appreciated on how to keep my classes independent for later modification and still pass the relevant data around without affecting interfaces too much?
As an example
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork(Window):
def __init__(self, parent=None):
self.parent=parent
I often find myself doing stuff like the above giving objects to class Window
or simply inheriting everything from them as in ParseMyWork
There must be better and cleaner ways of passing data around without making my classes utterly dependent on eachother, where one little change creates a cascade effect that forces me to make changes in a bunch of other classes.
Any answers to the question don't necessarily have to be in python, but it will be helpful if they are
If I'm understanding your question correctly, I would say that inheritance is not necessary in your case. Why not give ParseMyWork a function for dealing with a specific Window task?
class Window():
def __init__(self, parent=None):
self.parent = parent
def doStuff(self):
#do work here
class ParseMyWork():
def __init__(self, parent=None):
self.parent=parent`
def doWindowActivity(self, window):
window.doStuff
Then you can use the function like this
work_parser = ParseMyWork()
window = Window()
work_parser.doWindowActivity(window);
That way you can use your work_parse instance with any window instance.
Apologies in advance for my Python, it's been a while so if you see any rookie mistakes, do point them out.
Keep it simple.py:
def doStuff(window):
#do work here
return window
def parseStuff(stuff):
pass
really.py:
from simple import doStuff, parseStuff
def really_simple(window):
okay = doStuff(window)
return parseStuff(okay)
don't complicate the class:
from really import really_simple
really_simple(window)
imo: classes are overly complicated objects, and in a lot of cases more confusing than they need to be, plus they hold references and modify stuff, and can be difficult to decouple once they have been tied to other classes. if there isn't a clear reason why a class needs to be used, then it probably doesn't need to be used.
Classes are super powerful, so it's good you're getting started with em.
Discalimer: Haven't worked in python for a while now, so things might not be exact. The general idea still applies though.
Getting into your question now:
I would say the best way to achieve what you want is to create an instance of the first object where you will extract information from.
Now when creating a class, it's vital that you have attributes within them that you will want to be stored within it that you would like to retrieve once the class is instantiated.
For example, using your Window class example above, let's say that you have an attribute called resolution. It would look something like this:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
Now the resolution information associated with your Window class is forever part of any Window class instance. Now, the next step would be to create a get method for resolution. This should be done as follow:
class Window():
def __init__(self, parent = None):
self.parent = None
self.resolution = '40x80'
def getResoultion():
return self.resolution
Now, the reason we created this get method is because we can now set a variable to the information that is returned with it.
So let's say that you have everything associated with your Window class in its own file (let's say the file name is called Window.py). In a separate file (let's call it main.py), you can do the following:
import Window
windowInstance = Window()
windowResolution = windowInstance.getResolution()
If you print out the variable windowResolution, you should get that 40x80 printed out.
Now, as a side note, I do believe it is possible to get the information associated with an attribute with an instance of a class by simply doing something like
windowResolution = windowInstance.resolution
but that is bad practice in general. The reason, in a nutshell, is because you are now exposing attribute names of your class which you do not want to do because it makes it easy for a person outside of your code to learn the name where that information is held and change it. This can then lead to a myriad of other problems when it comes to making an overall program work. That is why it is best practice to use getters and setters. I already showed what getters are. Simply a get method for attributes. Setters, as you can probably assume, allow for one to set the information of an attribute to something else. Now you might say "Gabe, if we can create setter methods, what's the point of it if they just change it". My answer to that is to not give a setter method to all attributes. For attributes you don't mind for a person to change, give it a setter method, but for attributes you do not want any outside users to touch, simply don't create a setter method for it. Same goes with getter methods too. Users don't need to see all of the information of all attributes that makes your program work. Here's a better explanation: https://en.wikipedia.org/wiki/Mutator_method
Now, back to your example. Now let's say you have your ParseMyWork class in its own file like we did with your Window class, and let's say that ParseMyWork needs the resolution info from Window class. You can do the following :
import Window
import ParseMyWork
windowInstance = Window()
windowResolution = windowInstance.getResolution()
parseInstance = ParseMyWork(windowResolution)
This will only pass the window resolution information associated with your Window class. Hope this helps.
I'm learning to use PyQt5 and have run across a problem. My code is attempting to just draw a simple black box in the QMainWindow object by writing a second class PaintWidget which inherits from QWidget. I've posted my code first, and the correct one below it.
class PaintWidget(QWidget):
def __init__(self):
super().__init__()
self.qp = QPainter()
self.initUI()
def initUI(self):
self.qp.fillRect(1,1,100,100, Qt.black)
Correct:
class PaintWidget(QWidget):
def paintEvent(self, event):
qp = QPainter(self)
qp.fillRect(1, 1, 100, 100, Qt.black)
This is what confuses me. In order to create this class, we need to inherint from the super class QWidget, inorder to do so we use the function super().__init__() under __init__(self). We then set up the QPaint object which we will use in our method initUI() which actually does the work. Now this doesn't work when I run it.
The second, correct class, doesn't even seem to inherent, since it has no super().__init__(), even worse, it is setting up a method that is never even called (paintevent(self, event)), which takes an argument that seemingly comes from nowhere. Can someone point out why I'm wrong?
There is absolutely no difference to inheritance between the two cases. In both cases you say class PaintWidget(QWidget), so you are inheriting the QWidget.
The difference is in where you draw. In constructor (__init__), the widget is not yet mapped to the screen, so if you try to draw there, it won't have effect.
When the widget is actually displayed on screen, the system will invoke the paintEvent, which is a virtual method of the QWidget, and that is where you must draw the content. You only define that method in the second example.
Note that you need fresh QPainter in each invocation of the paintEvent. Creating one in the constructor and then using it in paintEvent would not work.
Also, most windowing systems don't remember the content of the widget when it is not actually visible on screen and rely on being able to call the paintEvent whenever the widget becomes visible again. So the method will likely be called many times. In contrast, the constructor, __init__, is only called once when creating the object.
I really don't know how to word this problem, so I'll try to explain it with an example.
Let's say I have three GUI classes:
Base Surface class
Detailed Surface Class
Sprite Class
All of them are independent of each other, no inheritance among them.
Now I have a function "drag()" that makes a surface/sprite dragable, and I want to implement this function as a method for all three of them.
Since it's the exact same code for all implementations I find it annoying, cumbersome and bad practice to rewrite the code.
The only thing I came up with so far was to make a saperate class for it and inherit this class. But that also doesn't seem to be the way to go.
I'd be very thankfull for some advice.
EDIT
Another example with a slightly different setup - I have the following classes:
BaseSurface
Dragable
Resizable
EventHandler
Only the first one is independent, the others depend on the first (must be inherited).
The end user should, without any effort, be able to choose between a simple BaseSurface, one with that implements dragable, one with resizable, one with eventHandler, and any combination. By "without any effort" I mean the end user should not have to make e custom Class and inherit the desired classes plus call the appropriate methods (init, update, ...) that some classes share.
So what I could do is make a class for every possible combination, eg.
"BaseSurfaceDrag", "BaseSurfaceDragResize", ...
which will get messy really quickly. Whats a different and better approach to this?
This is exactly the kind of case that you should use a parent class for. In both cases it looks like your parent class (logically) should be something like:
class Drawable(object):
def drag(self, *args, **kwargs):
"""Drag and drop behavior"""
# Your code goes here
Then each of your other classes inherits from that
class BaseSurface(Drawable):
# stuff
class DetailedSurface(Drawable):
# stuff
class Sprite(Drawable):
# stuff
In the second case what you have are interfaces, so you could logically do something like:
class DragInterface(object):
"""Implements a `drag` method"""
def drag(self):
"""Drag and drop behavior"""
# Your code goes here
class ResizeInterface(object):
"""Implements a `resize` method"""
def resize(self):
"""Drag and drop resize"""
# Code
class EventHandlerInterface(object):
"""Handles events"""
def handle(self, evt):
# Code
class MyNewSurface(BaseSurface, DragInterface, ResizeInterface):
"""Draggable, resizeable surface"""
# Implement here
So... I'm working on trying to move from basic Python to some GUI programming, using PyQt4. I'm looking at a couple different books and tutorials, and they each seem to have a slightly different way of kicking off the class definition.
One tutorial starts off the classes like so:
class Example(QtGui.QDialog):
def __init__(self):
super(Example, self).__init__()
Another book does it like this:
class Example(QtGui.QDialog):
def __init__(self, parent=None):
super(Example, self).__init__(parent)
And yet another does it this way:
class Example(QtGui.QDialog):
def__init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
I'm still trying to wrap my mind around classes and OOP and super() and all... am I correct in thinking that the last line of the third example accomplishes more or less the same thing as the calls using super() in the previous ones, by explicitly calling the base class directly? For relatively simple examples such as these, i.e. single inheritance, is there any real benefit or reason to use one way vs. the other? Finally... the second example passes parent as an argument to super() while the first does not... any guesses/explanations as to why/when/where that would be appropriate?
The first one simply doesn't support passing a parent argument to its base class. If you know that you'll never need the parent arg, that's fine, but this is less flexible.
Since this example only has single inheritance, super(Example, self).__init__(parent) is exactly the same as QtGui.QDialog.__init__(self, parent); the former uses super to get a "version" of self that calles QtGui.QDialog's methods instead of Example's, so that self is automatically included, while the latter directly calls the function QtGui.QDialog.__init__ and explicitly passes the self and parent arguments. In single inheritance there's no difference AFAIK other than the amount of typing and the fact that you have to change the class name if you change inheritance. In multiple inheritance, super resolves methods semi-intelligently.
The third example actually uses QWidget instead of QDialog, which is a little weird; presumably that works because QDialog is a subclass of QWidget and doesn't do anything meaningful in its __init__, but I don't know for sure.