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.
Related
I'm looking for more info on this kind of syntax
function_name[data type]
I don't know what this is called so I hope someone here can point me in the right direction. I'm used to this kind of syntax with referencing values in list and dictionaries but not so much for function definitions.
I came across this when following PyQt5 tutorials, specifically this one
http://zetcode.com/gui/pyqt5/widgets/
which contains this line
sld = QSlider(Qt.Horizontal, self)
...
sld.valueChanged[int].connect(...)
From the Qt5 documentation I can see that this is the definition of the signal function
valueChanged(int value)
https://doc.qt.io/qt-5.11/qabstractslider.html#signals
Thanks,
When coding Qt in C++, you can subscribe to signals using slots with different signatures, using a C++ technique called method overloading. Qt will call the right slot based on the argument type of the changed value. The Qt documentation on slots uses an overloaded display() slot definition as an example:
public slots:
void display(int num);
void display(double num);
void display(const QString &str);
// ...
and connecting display to a signal that can send int values on changes would connect to the first one of these.
Python, on the other hand, doesn't have such a concept. Python is dynamically typed, function definitions don't include type information.
So the PyQT wrapper around QT lets you define what type of argument to expect by using Python's subscription syntax on the signal, the same syntax you'd use to address indices and slices in lists or keys in dictionaries. Using this you can connect your slot to a specific 'variant' of a signal. Signals are not methods in this scenario, they are custom wrapper objects that support subscription instead, and the result of that signal[type] is a more specific signal object, one you can then connect to or disconnect from and the slot will only ever be called for that specific type.
For your example, the QAbstractSlider.valueChanged` signal comes in just one variant, one that emits an integer:
void valueChanged(int value)
so in Python you'd bind that variant via valueChanged[int]. If a signal takes no arguments, you can use signal directly, no subscription required; e.g. sliderPressed. In fact, you can use any signal that way, but then a default is picked if there are multiple overloads; you may want to check the .signal attribute in that case to see which one is going to be used.
See the Signals and Slots documentation in the PyQT5 manual:
A bound signal has connect(), disconnect() and emit() methods that implement the associated functionality. It also has a signal attribute that is the signature of the signal that would be returned by Qt’s SIGNAL() macro.
A signal may be overloaded, ie. a signal with a particular name may support more than one signature. A signal may be indexed with a signature in order to select the one required. [...]
If a signal is overloaded then it will have a default that will be used if no index is given.
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.
I have following code for click handler in my PyQT4 program:
def click_btn_get_info(self):
task = self.window.le_task.text()
self.statusBar().showMessage('Getting task info...')
def thread_routine(task_id):
order = self.ae.get_task_info(task_id)
if order:
info_str = "Customer: {email}\nTitle: {title}".format(**order)
self.window.lbl_order_info.setText(info_str)
self.statusBar().showMessage('Done')
else:
self.statusBar().showMessage('Authentication: failed!')
thread = threading.Thread(target=thread_routine, args=(task,))
thread.start()
Is it a good practice to declare function in function for using with threads?
In general, yes, this is perfectly reasonable. However, the alternative of creating a separate method (or, for top-level code, a separate function) is also perfectly reasonable. And so is creating a Thread subclass. So, there's no rule saying to always do one of the three; there are different cases where each one seems more reasonable than the others, but there's overlap between those cases, so it's usually a judgment call.
As Maxime pointed out, you probably want to use Qt's threading, not native Python threading. Especially since you want to call methods on your GUI objects. The Qt docs article Threads, Events and QObjects in the Qt documentation gives you an overview (although from a C++, not Python, viewpoint). And if you're using a QThread rather than a threading.Thread, it is much more common to use the OO method—define a subclass of QThread and override its run method than to define a function, which makes your question moot.
But if you do stick with Python threading, here's how I'd decide.
Pro separate method:
You're doing this in a class method, rather than a function, and that the only state you want to share with the new thread is self.
Non-trivial code, longer than the function it's embedded in.
Pro local function:
Pretty specific to the info button callback; no one else will ever want to call it.
I'd probably make it a method, but I wouldn't complain about someone else's code that made it a local function.
In a different case—e.g., if the thread needed access to a local variable that had no business being part of the object, or if it were a trivial function I could write as an inline lambda, or if this were a top-level function sharing globals rather than a method sharing self, I'd go the other direction.
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.
In PyQt, there's a concept of signals and slots to connect objects to one another's functions, but I can't seem to find them referenced to functions not associated with other objects. For example, I want a dropdown list to have algorithm A or algorithm B run.
How does PyQt accomplish this functionality?
Do you want the effect of changing the drop down list to call a function?
Connect the dropdown list's appropriate signal to your function.
For example with the QComboBox currentIndexChanged() signal. Connect that to a "wrapper" function that decides (based on the index) which function to call.
Edit: The wrapper can be very simple, like so:
functions = {0: reference_to_function_1, 1: reference_to_function_2}
def wrapper(index):
functions[index]()
Edit2: If you want some alternate methods for connecting slots:
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#connecting-signals-and-slots
Note when they are talking about Py or Qt signals, and when they are talking about Python functions or methods. E.g., these are the syntax for connecting a Qt signal to a Python function and a Python method:
QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), pyFunction) #function-style
QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), pyClass.pyMethod) #method-style