I am trying to set up a signal-slot arrangement in PyQt where the signal transmits a lot of information. I want to use a QObject as a carrier by setting the various information I want to transmit as attributes of the QObject. In theory, this should work - there is a QSignalMapper.setMapping() overload which takes a sender and a QObject as arguments.
Here's the reduced code:
self.mapper = QtCore.QSignalMapper()
self.timeline.finished.connect(self.mapper.map)
carrier = QtCore.QObject()
carrier.contents = (item1, item2)
self.mapper.setMapping(self.timeline, carrier)
self.portalMapper.mapped.connect(self.report)
def report(self, carrierObject):
print 'Triggered'
Unfortunately it doesn't work. I've traced the problem to the setMapping function by process of elimination.
This same scheme will work just fine if I switch out the QObject with an int. It also doesn't have anything to do with the attributes I added to the QObject - using a fresh-out-of-the-box QObject causes the same issue.
It seems like there is something going on here with this specific overload of the setMapping function. Any ideas about what the issue is here?
Thanks to #ekhumoro's suggestion to skip the QSignalMapper approach entirely and just create a custom signal. Worked like a charm.
Related
The django-file-resubmit module (file widgets.py) makes this import:
from django.forms import ClearableFileInput
and then it defines class based on ClearableFileInput:
class ResubmitBaseWidget(ClearableFileInput):
# ...some code
I try to use the module with different base class and it works well. But I have to patch the import command in module code. (DBAdminClearableFileInput is inherited from django.forms.ClearableFileInput in an other 3rd party module):
from db_file_storage.form_widgets import DBAdminClearableFileInput as ClearableFileInput
My question is: Could the code of django-file-resubmit module be rewritten more clever, so it could be used with DBAdminClearableFileInput as parameter?
Note: I'm not sure if this is not duplicate question. However I think here are special problems of modules design and a question if some Pull Request could be made or what is the best approach how to use both modules without changing them.
It sounds like what you might really want is co-operative multiple inheritance. E.g. You want to have
class MyFileInput(DBAdminClearableFileInput, ResubmitBaseWidget):
pass
For that to work, both DBAdminClearableFileInput and ResubmitBaseWidget would need to be written with co-operative multiple inheritance in mind. It may not even be (theoretically) possible depending on how the end-state behaviour has to look. E.g. if DBAdminClearableFileInput wants to render the widget as <foo> and ResubmitBaseWidget wants to render the widget as <bar>, one of them has to 'win' (in the absence of additional code you might write yourself in MyFileInput.
It's possible (though probably unlikely) that multiple inheritance will 'just work', depending on what methods etc both those classes override and whether they make they already make the correct calls to super().
It's probably worth a try at least, in the worst case scenario you can add some 'glue' to your MyFileInput class to make it work.
Here's a trite example
class Elephant: # Represents ClearableFileInput
def colour(self):
return "Grey"
class BrownElephant(Elephant): # Represents ResubmitBaseWidget
def colour(self):
return "Brown"
class PinkElephant(Elephant): # Represents DBAdminClearableFileInput
def colour(self):
return "Pink"
Now, at the moment, these classes do not cooperate, and so if you do multiple inheritance, you get:
class BrownAndPinkElephant(BrownElephant, PinkElephant):
pass
nelly = BrownAndPinkElephant()
print(nelly.colour())
Will print "Brown", since the Method Resolution Order starts with BrownElephant, which returns "Brown" without ever calling super().colour(), and so Pink and 'default' Elephant's methods are never even called.
You could 'fix' this in a very limited (but might be enough for your purposes) with a hacky 'glue' method like this:
class BrownAndPinkElephant(BrownElephant, PinkElephant):
def colour(self):
colours = [
BrownElephant.colour(self),
PinkElephant.colour(self),
]
return " and ".join(colours)
nelly = BrownAndPinkElephant()
print(nelly.colour())
Now the printed output is "Brown and Pink", which is more sensible (at least within the context of this example!). Hopefully you can see that you attempt to implement similar things for a subclass of DBAdminClearableFileInput, ResubmitBaseWidget to give you control over what aspects of each class end up being used in the final class.
It's worth saying, there are an awful lot of pitfalls with this approach and I wouldn't recommend it for anything 'serious'. However, when you have 2 classes with a common base class, that you want to combine, and you don't control the source code of either, then this may be a possible solution.
Consider I have a class with this kind of structure (CustomClass may/may not be on top of the hierarchy):
CustomClass
.. QTabWidget
.... QWidget
...... QTreeView
In QTreeView I have a function that is trying to refer back to CustomClass. Right now in order to do this I need to do: self.parent().parent().parent().
Although this works it just feels very sloppy, and if I ever need to change the structure this will fail. Is there some other way to get CustomClass? Usually I would pass an instance of it during its constructor which I can call directly, but wondering what's the best practice to go about this.
The question title leads to a very direct answer. The window() method on QWidget returns the ancestor widget that has (or could have) a window-system frame: typically the "top-level" widget that you want to find. The docs give changing the window title as a canonical use case:
self.window().setWindowTitle(newTitle)
It returns self if the Qwidget is a window itself.
However, the text of your question and your own answer give an alternative interpretation: you might alternatively want to find the ancestor that is of a particular type even if it is not the top level widget. In this case, iterating up through the ancestors is typically the right solution, pretty much as you have written for yourself. So that would be something like:
customClassInst = self.parent()
while customClassInst is not None and not isinstance(customClassInst,CustomClass):
customClassInst = customClassInst.parent()
Note that you should usually use isinstance rather than type() == because the former correctly handles sub-classes.
Also note that this code will return None if no CustomClass is found which may or may not be what you want ...
This feels like a decent procedural way to get it:
customClassInst = self.parent()
while customClassInst is not None and type(customClassInst) != CustomClass:
customClassInst = customClassInst.parent()
Any other answers are still welcome :)
I am refactoring some code that uses old-style signals and slots, and one of the things it does is pass built-in signals as strings (e.g., signalName="clicked()") to another function that actually connects the signals and slots. E.g.:
self.connect(widget, QtCore.SIGNAL(signalName), slot)
This works fine. The problem is, converting to new-style signals and slots (where the signal is not passed as an argument) makes this more complicated. In new-style signal and slot, the above would be something like:
widget.[signalName].connect(slot)
Where [signalName] is something that works. :) I got a lot of things to not work without using eval:
widget.signalName.connect(slot) #AttributeError: widget object has no attribute 'signalName'
Based on a related post:
signalDict={}
signalDict["clicked"]=QtGui.QAbstractButton.clicked
widget.signalDict["clicked"].connect(slot) #AttributeError: widget object has no attribute 'signalDict'
Of course there is eval, which actually works:
fullCommand="widget." + signalName + ".connect(slot)"
eval(fullCommand)
But it uses eval, which is sort of frowned-upon. Is there a better way to translate such code into new-style signals and slots, without using eval?
Note the original code, that I am trying to translate into new-style signals and slots, is here:
https://github.com/ghosert/VimProject/blob/master/pyqt/book_samples/chap06/imagechanger.pyw
It is from Chapter 6 of Summerfield's book on Qt programming.
Related question:
Passing Arguments with Newstyle signals in PyQT
How about this?
getattr(widget, signalName).connect(slot)
You may want to add a if hasattr(...) check beforehand to make sure the signal actually exists.
I have a HPaned that one of its children changes its size requirement frequently, since its text changes. The result is that the pane moves every time the text is changed. I'd like to override the Paned.compute_position method so that the size of the child will not decrease, just increase. However, I can't find a way to override it. Even
class MyHPaned(gtk.HPaned):
def do_compute_position(self, allocation, child1_req, child2_req):
print "Hi"
return gtk.HPaned.compute_position(self, allocation, child1_req, child2_req)
gobject.type_register(MyHPaned)
doesn't work. Do you have a suggestion? Thanks!
Overriding gtk_paned_compute_position is not possible, since that function is not virtual in GTK itself. Also, gtk_paned_compute_position is marked as internal and deprecated and is not called anywhere from GTK+-2.24.x sources. I suspect it was only exported so that you could find out the position of the separator, not to affect it through overriding.
Instead of attempting to override HPaned.compute_position, you should place into the paned a single-child container (e.g. a child of gtk.Bin) that implements the desired resizing policy by hooking into the size-allocate signal and calling set_size_request with the desired size. This will be automatically respected by HPaned.
Just want to know what's the common way to react on events in python. There are several ways in other languages like callback functions, delegates, listener-structures and so on.
Is there a common way? Which default language concepts or additional modules are there and which can you recommend?
Personally I don't see a difference between callbacks, listeners, and delegates.
The observer pattern (a.k.a listeners, a.k.a "multiple callbacks") is easy to implement - just hold a list of observers, and add or remove callables from it. These callables can be functions, bound methods, or classes with the __call__ magic method. All you have to do is define the interface you expect from these - e.g. do they receive any parameters.
class Foo(object):
def __init__(self):
self._bar_observers = []
def add_bar_observer(self, observer):
self._bar_observers.append(observer)
def notify_bar(self, param):
for observer in self._bar_observers:
observer(param)
def observer(param):
print "observer(%s)" % param
class Baz(object):
def observer(self, param):
print "Baz.observer(%s)" % param
class CallableClass(object):
def __call__(self, param):
print "CallableClass.__call__(%s)" % param
baz = Baz()
foo = Foo()
foo.add_bar_observer(observer) # function
foo.add_bar_observer(baz.observer) # bound method
foo.add_bar_observer(CallableClass()) # callable instance
foo.notify_bar(3)
I can't speak for common approaches, but this page (actual copy is unavailable) has an implementation of the observer pattern that I like.
Here's the Internet Archive link:
http://web.archive.org/web/20060612061259/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html
It all depends on the level of complexity your application requires. For simple events, callbacks will probably do. For more complex patterns and decoupled levels you should use some kind of a publish-subscribe implementation, such as PyDispatcher or wxPython's pubsub.
See also this discussion.
Most of the Python libraries I have used implement a callback model for their event notifications, which I think suits the language fairly well. Pygtk does this by deriving all objects from GObject, which implements callback-based signal handling. (Although this is a feature of the underlying C GTK implementation, not something inspired by the language.) However, Pygtkmvc does an interesting job of implementing an observer pattern (and MVC) over the top of Pygtk. It uses a very ornate metaclass based implementation, but I have found that it works fairly well for most cases. The code is reasonably straightforward to follow, as well, if you are interested in seeing one way in which this has been done.
Personally, I've only seen callbacks used. However, I haven't seen that much event driven python code so YMMV.
I have seen listeners and callbacks used. But AFAIK there is no Python way. They should be equally feasible if the application in question is suitable.
The matplotlib.cbook module contains a class CallbackRegistry that you might want to have a look at. From the documentation:
Handle registering and disconnecting for a set of signals and
callbacks:
signals = 'eat', 'drink', 'be merry'
def oneat(x):
print 'eat', x
def ondrink(x):
print 'drink', x
callbacks = CallbackRegistry(signals)
ideat = callbacks.connect('eat', oneat)
iddrink = callbacks.connect('drink', ondrink)
#tmp = callbacks.connect('drunk', ondrink) # this will raise a ValueError
callbacks.process('drink', 123) # will call oneat
callbacks.process('eat', 456) # will call ondrink
callbacks.process('be merry', 456) # nothing will be called
callbacks.disconnect(ideat) # disconnect oneat
callbacks.process('eat', 456) # nothing will be called
You probably do not want a dependency to the matplotlib package. I suggest you simply copy-paste the class into your own module from the source code.
I'm searching for an implementation to register and handle events in Python. My only experience is with Gobject, but have only used it with PyGtk. It is flexible, but might be overly complicated for some users. I have come across of few other interesting candidates as well, but it's not clear how exactly they compare to one another.
Pyevent, a wrapper around libevent.
Zope Event