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.
Related
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.
I am creating a desktop application for windows using python. I used Tkinter for GUI. My code involves triggering GUI whenever I execute it.
My requirement is that at any given point of time I should have only a single instance of the GUI running. Can i set some parameter which blocks creation of new instances in Tkinter?
Please suggest some options for the same.
What type of behaviour do you want if someone tries to generate a GUI when one is already running?
Basically what you can do is add a num_instances attribute to your class which will be incremented each time an instance is created, then decremented in your class's __del__ method. You can then check, either in __init__ or __new__ depending on the behaviour you want.
class GUI:
num_instances = 0
def __init__(self):
if self.__class__.num_instances:
raise
self.__class__.num_instances += 1
def __del__(self):
self.__class__.num_instances -= 1
This is just a draft, so check that it indeed always behave as desired, but it should get you going.
EDIT:
I forgot to mention it but of course you can also look at the singleton pattern
EDIT 2:
for preventing multiple runs, look at this post
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.
I have an ActiveX control in a QAxWidget class and I am trying to connect an Activex Event to a Slot in python
void MoveComplete (int ID) [signal]
The documentation says
QObject::connect(object, SIGNAL(MoveComplete(int)), receiver, SLOT(someSlot(int)));
But when I try run it, I get :
NameError: global name 'MoveComplete' is not defined.
I've also tried running it like this
self.connect(self, QtCore.SIGNAL('MoveComplete(int)'), self, QtCore.SLOT(self.test2()))
But it gets called at the beginning of a function which performs a Movement and not after it has been completed.
How do I connect a slot to this signal?
I obviously can't test this, and I don't know what documentation you're referring to, but something like this should work in PyQt4:
self.connect(axwidget, QtCore.SIGNAL('MoveComplete(int)'), self.test2)
That is, the first argument is an instance of your QAxWidget class, the second argument is the signal signature, and the last argument is a python callable object (i.e. a function, method, lambda, etc).
Connecting signals in PyQt doesn't always work in the same way as it does in C++. For more details, see Old-style Signal and Slot Support in the PyQt4 docs. The New-style Signal and Slot Support is much more pythonic (and a lot less error-prone) - but I don't know whether it would work with ActiveX controls.
Using wxpython in MVC, I looked for a way to let the models tell the controllers about changes. I found (py)pubsub, which implements a global notification mechanism: Messages are sent to one place (the pubsub Publisher), which sends them to all subscribers. Each subscriber checks whether the message is interesting, and does what is needed.
From Smalltalk times, I know a more "local" approach: Each model object keeps a list of interested controllers, and only sends change notifications to these. No global publisher is involved. This can be implemented as part of the Model class, and works in much the same way, except it's local to the model and the controller.
Now is there a reason to use the global approach (which seems much less performant to me, and might be prone to all the issues related to global approaches)? Is there another package implementing a local observer?
Thanks!
I'm not really seeing the subtle difference here. As far as I know, pubsub is the way to go. It's included in wxPython in wx.lin.pubsub or you can download it from http://pubsub.sourceforge.net/. You can put the listeners just in the models and the publisher(s) just in the controller or however you need to. Here are a couple links to get you started:
http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/
http://wiki.wxpython.org/WxLibPubSub
I've been playing around for a while to do MVC with wxpython and i know what you mean about pubsub being global.
The latest idea i've come up with is each view and model have there own observer.
The observers have weak references to their handlers and it all works in a separate thread so as to not block the GUI. To call back to the GUI thread I'm using wxAnyThread Gui method decorator.
There are 3 types of signal that get sent, for the model you can set which attributes are observed they automatically send out a signal when they are changed. then on both the model and the view you can send a message signal or a keyword signal. Each of the three signal types have to be unique per view or model as they are used to make a tuple that identify them.
model attributes
controller handlers are decorated with
#onAttr('attributeName')
def onModelAttributeName(self, attributeName)
When you bind to a method that handlers attributes it straight away calls the handler with its current value and then continues to observe changes.
Sending messages
Use the method
view/model.notify('Your message'):
The controller callback is decorated with
#onNotify('Your message')
def onYourMessage(self):
Sending keywords
Use the method
view/model.notifyKw(valid=True, value='this)
The controller callback is decorated with
#onNotifyKw('valid', 'value')
def onValidValueKw(self, valid, value)
The GUI is left knowing nothing about the models the only thing you add to the GUI is the view signaler, the controller attaches it self to this, so if you don't add a controller the view will just happily fire off messages to no one.
I've uploaded what i have so far on github
https://github.com/Yoriz/Y_Signal
https://github.com/Yoriz/Y_Mvc
Both have unit test which should give a bit of an example of what it does, but i will create some wxpython examples.
I'm using python version 2.7 and the Ysignals module requires
https://pypi.python.org/pypi/futures/2.1.3 for the threading.
Please take a look ill be interested in what someone else thinks of this way of approaching mvc or to point out something i seriously overlooked.