Subclass & override PySide2 widget method; where do I find source to reference? - python

When inheriting a class and overriding a method you don't always know what's inside the original class. And if I understand correctly, various aspects of how this is handled in Python are intentionally designed to accommodate this. But I have to think that all or most of the Qt code is documented somewhere. I've found the Qt for Python documentation to be refreshing (compared to PyQt) and lists all methods for a class with a fair amount of detail but I've not been able to find the actual code for specific methods and descriptions are not always very complete. For instance, consider if I want to override the mousePressEvent for a combobox.
class mycombo(QtWidgets.QComboBox):
def __init__(self, parent = None):
super(mycombo, self).__init__()
self.setAcceptDrops(True)
self.setFocusPolicy(QtCore.Qt.NoFocus)
def mousePressEvent(self,event):
In the Qt for Python documentation I see that QComboBox inherits from QWidget
which has this to say about mousePressEvent:
https://doc.qt.io/qtforpython/PySide2/QtWidgets/QWidget.html#PySide2.QtWidgets.PySide2.QtWidgets.QWidget.mousePressEvent
There are some useful things written there but, how do I determine what's actually happening in the 'original' mousePressEvent? I don't want to interfere with other parts of the operation that are actually desired. In this case, perhaps the handling of popup widgets like the description mentions, is desired. But I also might not want to super the original method. Is there more documentation for this that I've somehow missed? It seems that some of the widgets are subclassed and modified in Python and others are only in C++?

TL; DR; There is no documentation or need as the source code can change without notifying developers.
Actually you should not know what each method does since that can change in a new version. If your goal is to add functionalities then do not override the implementation of the parent class by calling it to super().foo_method(), so you can add logic before or after the original implementation
class MyCombo(QtWidgets.QComboBox):
def __init__(self, parent = None):
super(MyCombo, self).__init__(parent)
self.setAcceptDrops(True)
self.setFocusPolicy(QtCore.Qt.NoFocus)
def mousePressEvent(self,event):
# stuff
super(MyCombo, self).mousePressEvent(event)
# another stuff
If you still want to know what happens in that function then you should check the source code:
void QComboBox::mousePressEvent(QMouseEvent *e)
{
Q_D(QComboBox);
if (!QGuiApplication::styleHints()->setFocusOnTouchRelease())
d->showPopupFromMouseEvent(e);
}
Qt has 2 types of API since it implements PIMPL/D-Pointer so analyzing the source code of the class will not be enough if you want to understand the logic, the public API rarely changes for what it is, but instead the private API has changes continuously.
In conclusion, if you want to add functionalities then just analyze the documentation as this is respected even when the code changes. Another way of understanding how it works is by modifying and analyzing the changes that occur in the GUI.
What PyQt/Qt For Python does is a wrapper to handle C++ classes, so in general what can be done in C++ can be done in Python except for some minor things that can be done in one and not in another.

Related

Designing a True Presentation Model with Kivy

After a few false starts, I've started a redesign of a Kivy project. My goal is to separate as much of the behavior and data models as possible from code using the Kivy framework. This, hopefully, would allow for more robust testing and possible reuse with other UI frameworks.
What I have in mind mirrors Martin Fowler's Presentation Model.
Presentation Model allows you to write logic that is completely independent of the views used for display. You also do not need to rely on the view to store state. The downside is that you need a synchronization mechanism between the presentation model and the view.
Code Example
The design I envision relies on explicit getters and setters in a pure Python model, which would also contain methods the Kivy classes could use as callbacks:
class PresentationModel:
def __init__(self, data1):
self._data1 = data1
def get_data1(self):
return self._data1
def set_data1(self, value)
''' Validate, call the backend, etc '''
self._data1 = value
return True
def callback(*args):
''' Do some stuff here and/or the backend '''
And then all the synchronization code would stay inside a Kivy widget subclass, assigning each PM property as and AliasProperty.
class MyBoxLayout(BoxLayout):
data1 = AliasProperty(get_data1, set_data1, bind=['_data1'], cache=True)
Questions
Has anyone attempted this? Are there any githubs or projects that would show a real-world example?
If I were to use this strategy, Kivy's Docs say all setters need to return True. From what I can tell, Python ignores return values from setters in general. Would there be any performance issue or other drawback to doing that?

How to structure methods of classes that inherit from one BaseClass?

I have a lot of different child classes that inherit from one base class. However all the different child classes implement very similar methods. So if I want to change code in the child classes, I have to change it multiple times.
For me this sounds like bad practice and I would like to implement it correcty. But after a lot of googling I still didn't find a coherent way of how this should be done.
Here is an example of what I mean:
from ABC import ABC, abstractmethod
import logging.config
class BaseModel(ABC):
def __init__(self):
# initialize logging
logging.config.fileConfig(os.path.join(os.getcwd(),
'../myconfig.ini'))
self.logger = logging.getLogger(__name__)
#abstractmethod
def prepare_data(self):
"""
Prepares the needed data.
"""
self.logger.info('Data preparation started.\n')
pass
So this is my BaseClass. Now from this class multiple other classes inherit the init and prepare_data method. The prepare_data method is very similar for every class.
class Class_One(BaseModel):
def __init__(self):
super.__init()__
def prepare_data(self):
super().prepare_data()
# Some code that this method does
class Class_Two(BaseModel):
def __init__(self):
super.__init()__
def prepare_data(self):
super().prepare_data()
# Some code that this method does
# Code is almost the same as for Class_One
class Class_Three(BaseModel):
def __init__(self):
super.__init()__
def prepare_data(self):
super().prepare_data()
# Some code that this method does
# Code is almost the same as for Class_One and Class_Two
# etc.
I suppose you could refactor the methods into another file and then call them in each class. I would love to know how to do this correctly. Thanks a lot in advance!
I'm afraid there's no generic one-size-fits-all magic answer - it all really depend on the "almost" part AND on the forces that will drive change in those parts of the code. IOW, one can only really answer on a concrete example...
This being said, there are a couple lessons learned from experience, which are mostly summmarized in the famous (but unfortunately often misunderstood) GOF "Design Patterns" book. If you take time to first read the first part of the book, you understand that most of (if not all) the patterns in the catalog are based on the same principle: separate the variant from the invariant. Once you can tell one from the other in your code (warning: there's a trap here and beginner almost always fall into it), which pattern to apply is usually obvious (sometimes to the point you only realize you used this and that patterns after you refactored your code).
Now as I said, there IS a trap: accidental duplication. Just because two pieces of code look similar doesn't mean they are duplicates - quite often, they are only "accidentally" similar now but the forces that will make one or the other change are mostly unrelated. If you try to immediatly refactor this code, you'll soon find yourself making the "generic" case more and more complicated to support changes that are actually unrelated, and end up with an overcomplicated, undecipherable mess that only make your code unmaintainable. So the trick here is to carefully examine the whole context, ask yourself what would drive change in one or the other "similar" parts, and if in doubt, wait until you know more. If it happens than each time you change A you have to make the exact same change in B for the exact same reasons then you DO have real duplicate.
For a more practical, short-term advise based on what we can guess from your way too abstract example (and from experience), there are at least two patterns that are most often involved in factoring out duplication in a class hierarchy: the template method and the strategy.
NB : I said "unfortunately often misunderstood" because most people seem to jump to the patterns catalog and try to forcefit all of them in their code (whether it makes sense for the problem at hand or not), and usually by copy-pasting the canonical textbook _implementation_ (usually Java or C++ based) instead of understanding the _concept_ and implementing it in a way that's both idiomatic and adapted to the concrete use case (example: when functions are first class object, you don't necessarily need a Strategie class with abstract base and concrete subclasses - most often plain old callback functions JustWork(tm)).
EDIT totally unrelated but this:
def __init__(self):
# initialize logging
logging.config.fileConfig(os.path.join(os.getcwd(),
'../myconfig.ini'))
self.logger = logging.getLogger(__name__)
is NOT how to use logging. Library code can use loggers, but must not configure anything - this is the application's (your main script / function / whatever) responsability, the rational being that the proper logging config depends on the context - which type of application is using the lib (a CLI app, a local GUI app and a backend web app don't have the same needs at all) and in which kind of environment (a local dev env will want much more logs than a production one for example).
Also, with the logger created with __name__ in your base class module, all child classes will send their log to the same logger, which is certainly not what you want (you want them to have their own package / module specific loggers so you can fine tune the config per package / module).
And finally, this:
os.path.join(os.getcwd(), '../myconfig.ini')
certainly doesn't work as you expect - your cwd can be just anything at this point and you have no way of knowing in advance. If you want to reference a path relative to the current file's directory, you want os.path.dirname(os.path.realpath(__file__)). And of course adding system specific path stuff (ie "../") in a os.path.join() call totally defeats the whole point of using os.path.

Python defining gui variables outside init [duplicate]

This question already has answers here:
Instance variables in methods outside the constructor (Python) -- why and how?
(7 answers)
Closed 4 years ago.
I'm using PySide2 to define my tool's interface, and I generally initialize all interface items outside __init__ as to not bloat it (any other important variables stay in __init__).
Unfortunately for me, I'm using PyCharm as my editor and it's giving me tons of warnings:
Instance attribute 'foobar' defined outside __init __
Here's a simple example of what I would be doing:
from PySide2 import QtWidgets
class MyTool(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyTool, self).__init__(parent)
self.create_gui()
def create_gui(self):
# Complains about all variables below!
self.awesome_checkbox = QtWidgets.QCheckBox(parent=self)
self.awesome_button = QtWidgets.QPushButton(parent=self)
self.awesome_label = QtWidgets.QLabel(parent=self)
self.main_layout = QtWidgets.QVBoxLayout()
self.main_layout.addWidget(self.awesome_checkbox)
self.main_layout.addWidget(self.awesome_button)
self.main_layout.addWidget(self.awesome_label)
self.setLayout(self.main_layout)
Now I know one solution would be to initialize these variables in __init__ as None, but I can have fairly complex interfaces so it would be very long winded.
My question is if what I'm currently doing truly blasphemy? I know the variables are technically outside __init__, but the method is being called in the constructor anyways!
Well, the short answer is: no, it's not "truly blasphemy".
It's considered good practice to create all the instance attribute and ensure they are in a consistant state in the initializer because it makes code easier to read (you only have one method to read to know what attributes your object has) and avoids potential AttributeError when an attribute is created by a method that might not always been called before the attribute is accessed. That's why most linters will (by default) warn you about this, and by itself it's a good thing as it can help you spot a potential bug before it makes it's way in production.
Now there are indeed cases where it makes sense to delegate part of the instance initialisation to a distinct method, ie when those attributes depends on each other and some other external factor and might have to be reset / updated together during the instance's lifecycle, or when you want to let child classes override this part of the initialization without having to override the __init__() method itself (cf the GOF's "template method" pattern).
In the case of a class with complex initialization (and this is typical of GUI components) it can also make sense to split the setup in distinct methods for readability reasons - a 50+ lines initializer is not really optimal when it comes to readability - so as far as I'm concerned I would probably do something similar with possibly a couple improvements: first make this a "protected" method (naming it _create_gui() - the leading underscore being the naming convention for protected attributes / methods) and then adding a guard to prevent the method from being executed twice (assuming this method is only supposed to be called once from the initializer and is not supposed to be part of the public API, of course). And then I would add a couple linter directives (those are specially formatted comments that the linter looks for) to make clear for both the linter and anyone reading this code that doing so was a deliberate design choice and not a rookie mistake.

Custom QTreeview expanded event method

When I create my own custom QTreeView with a defined 'expanded' method, do I need to do anything special to emit the default signal? I've commented out pseudo code representing what i'm asking about. Or am I safe to do what I'm currently doing?
class JMTreeView(QtGui.QTreeView):
changed = QtCore.Signal()
def __init__(self):
super(JMTreeView, self).__init__()
self.expanded.connect(self.expanded_item)
def expanded_item(self, event):
print "expanded"
# super(JMTreeView, self).expanded(event)
Similar to the way I handle when I override the 'showEvent' for a dialog, i call the 'super' at the end of the function. Do i need to add something similar to my 'expanded' method?
def showEvent(self, event):
geom = self.frameGeometry()
geom.moveCenter(QtGui.QCursor.pos())
self.setGeometry(geom)
super(Browser, self).showEvent(event)
The QTreeView class does not have an expanded method. There is only an expanded signal. More to the point, the signal and slots mechanism is completely separate from the event system, so there is no parallel with overriding protected methods like showEvent.
Most of the event-handlers (like showEvent) are related to activity that originates outside of the application. They usually implement some default behaviour, but sometimes do nothing at all. They are almost always virtual methods, which means you can provide your own implementation which Qt will call instead of the default. If your re-implementation needs to keep the default behaviour (or modify it in some way), it can do so by calling the base-class implementation.
By contrast, signals always originate inside the application. There are no default handlers for them - they simply broadcast messages (like a radio beacon). It is entirely up to the listeners to decide what to do with the messages. It doesn't matter if there are never any listeners, or if the messages are never processed.

How to organize classes in pyqt GUI programming

I have constructed a main window GUI using qt designer and pyqt. As the program grows more complex, using only one class may result in too many methods and attributes to manage. I figured that I should construct new classes in order to make things more manageable.
My first question is, how do I know when do I add a new class for my application? Is there any rule of thumb as a general guide? Is it a good idea to add a new class for new windows/tabs?
My second question is, if I added new classes for my application, how do my new class gain access to the Ui_MainWindow design file that I designed in Qt designer? Below is the sample code for my main window. Its a simple clock which displays the current time. Lets say if I would like to create a class for the clock display itself, how can I rewrite the code using OOP efficiently?
from PyQt4 import QtGui
from myMainWindowUI import Ui_MainWindow
class MyMainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super(MyMainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.Time)
self.timer.timeout.connect(self.Date)
self.timer.start(1000)
self.lcdNumber_time.setDigitCount(8)
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
def Time(self):
self.lcdNumber_time.display(strftime("%H"+":"+"%M"+":"+"%S"))
def Date(self):
self.label_dynamic_date.setText(strftime("%Y"+" "+"%B"+" "+"%d"+", "+"%A"))
app = QtGui.QApplication(sys.argv) # A new instance of QApplication
form = MyMainWindow()
form.show()
app.exec_()
In general, this isn't necessarily a Qt-specific problem. It isn't necessarily a python-specific problem either. You could extend this question to any language that supports class-based programming, or even any language with functions.
It makes sense to write a class when you want to encapsulate behavior. A class should usually provide a single purpose, and expose an interface to the outside that allows users of the class to interact with exactly the behavior you have designed. Once you have this single-purpose class, you now have reusable behavior. You could apply part of this reasoning to functions, where you say a given function has a specific purpose and once you design it to do the one bit of behavior, you now have a reusable function.
Applying this to Qt, it would make sense to move code into its own class when its logic is no longer trivial. An example would be where you are first creating and showing a QMessageBox from your main window. But then at some point you need to collect more types of information, and even pass some initial information in when you construct the dialog. While you could construct this on the fly in your main window, as needed, it would be better to move it into its own dialog class, with its own private logic of how to be constructed. Then you just instantiate one as needed, passing it the expected parameters to its constructor. Now your main window no longer has to also be concerned with constructing special dialogs.
Another point (which wasn't exactly clear from your question) is that Qt Designer UI files each represent a single class. It is expected that this UI definition will be applied to a single class in code. It would be bad design to have ClassA(UI_mainWindow) and ClassB, and have ClassB access members of ClassA or know anything about the internal implementation of ClassA. Back to our topic of "separation of concerns", ClassB should have its own purpose and interface, and be used by the ClassA(UI_mainWindow) to achieve that purpose. You don't want ClassB knowing anything about the main window or being able to do more than its designed purpose.
Let's assume your timer example was actually more trivial than you have shown it to be. If you moved it to another class, you should rely on custom signals to communicate intentions back to other classes like the main window. Or you could move each of the lcd and label widgets into their own custom classes with their own timer logic that made them self contained. Either way, signal/slot lets custom widgets connect with each other without needing to know anything about the other widgets.
In summary, you could say that it would be good to create individual classes in Qt when you are constructing any non-trivial UI elements in another class (when it requires many lines of code, or it requires a bunch of SLOT functions and wiring for internal logic). This will keep you from repeating your logic, and allow you to have reusable code. It will also keep your main window smaller and easier to debug, since you can keep a smaller mental model in your brain of what the main window is doing. If you try to keep your UI elements as single-purpose focused and generic as possible, you will end up having a lot of classes that can be reused.

Categories

Resources