473,386 Members | 1,754 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

The proper use of QSignalMapper

Hi.

I am trying to implement QTCore.QSignalMapper using PyQT. I finally got
to a point where I don't receive any compile or runtime error messages,
but I also do not see the final slot function fire off. Here is a
snippet of the code:

self.signalMapper = QtCore.QSignalMapper(window)
# Use qsignalmapper to use of one slot function for multiple
# widgets. The map() function sends the slot an extra param
# that identifies the sender.
for idx in range(1, maxIngredients+1):
wName = 'chkProductIngredientsDelete_'+str(idx)
w = self.__dict__[wName]
self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("self.signalMapper.map"))
self.signalMapper.setMapping(w, idx)

self.app.connect(self.signalMapper, QtCore.SIGNAL(
"self.signalMapper.mapped(int)"),
self.deleteProductIngredient)

def deleteProductIngredient(self, state, widgetIdx):
"""Delete a product ingredient."""
print "INSIDE FUNCTION\n"

The idea here is to iterate through several checkbox widgets (named
"chkProductIngredientsDelete_1, _2, etc.) and connect each object's
"stateChanged" signal to the mapper's map() function, then connect the
map() function to the actual slot, deleteProductIngredient().

By the way, I've checked to ensure the statements inside the loop are
being executed.

Jan 17 '07 #1
6 5363
borntonetwork wrote:
I am trying to implement QTCore.QSignalMapper using PyQT. I finally got
to a point where I don't receive any compile or runtime error messages,
but I also do not see the final slot function fire off. Here is a
snippet of the code:

self.signalMapper = QtCore.QSignalMapper(window)
# Use qsignalmapper to use of one slot function for multiple
# widgets. The map() function sends the slot an extra param
# that identifies the sender.
for idx in range(1, maxIngredients+1):
wName = 'chkProductIngredientsDelete_'+str(idx)
w = self.__dict__[wName]
self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("self.signalMapper.map"))
You need to pass the C++ signature to the SLOT() function. I believe
you want the form that does not accept any arguments:

self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("map()"))

Alternatively, you can pass the slot directly to the function:

self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper.map)

PyQt accepts Python methods as slots, without requiring that they be
wrapped in calls to SLOT().

David

Jan 17 '07 #2
Thanks, David, for you help.

When I change the slot function to what you show in your second
example, I get the same results: nothing. When I change it to what you
have in your first example, I get the following:

Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_1')
Object::connect: (receiver name: 'main.py')
Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_2')
Object::connect: (receiver name: 'main.py')
Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_3')
Object::connect: (receiver name: 'main.py')
Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_4')
Object::connect: (receiver name: 'main.py')
Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_5')
Object::connect: (receiver name: 'main.py')
Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_6')
Object::connect: (receiver name: 'main.py')
David Boddie wrote:
borntonetwork wrote:
I am trying to implement QTCore.QSignalMapper using PyQT. I finally got
to a point where I don't receive any compile or runtime error messages,
but I also do not see the final slot function fire off. Here is a
snippet of the code:

self.signalMapper = QtCore.QSignalMapper(window)
# Use qsignalmapper to use of one slot function for multiple
# widgets. The map() function sends the slot an extra param
# that identifies the sender.
for idx in range(1, maxIngredients+1):
wName = 'chkProductIngredientsDelete_'+str(idx)
w = self.__dict__[wName]
self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("self.signalMapper.map"))

You need to pass the C++ signature to the SLOT() function. I believe
you want the form that does not accept any arguments:

self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("map()"))

Alternatively, you can pass the slot directly to the function:

self.app.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper.map)

PyQt accepts Python methods as slots, without requiring that they be
wrapped in calls to SLOT().

David
Jan 18 '07 #3
borntonetwork wrote:
Thanks, David, for you help.

When I change the slot function to what you show in your second
example, I get the same results: nothing.
This may be due to something I missed in your code. When you
connect the signal from the signal mapper to your class, you
need to specify the signal as a C++ signature as well:

self.connect(self.signalMapper, QtCore.SIGNAL(
"mapped(int)"),
self.deleteProductIngredient)

The second example should now work.

Looking at the first example, which uses SLOT() rather than specifying
a Python method, the following might be due to the way you call
connect, though it is surprising:
When I change it to what you
have in your first example, I get the following:

Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_1')
Object::connect: (receiver name: 'main.py')
[...]

It looks like you should try something like this:

self.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("map()"))

I can't understand why calling self.app.connect() would cause the
connection to be attempted between self.signalMapper and self.app.

Maybe someone on the PyQt/PyKDE mailing list would be able to
explain the behaviour you're seeing:

http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

David

Jan 18 '07 #4
David, thanks for your help. Unfortunately, all attempts of making this
solution work have failed. I would be interested to know if anyone has
used QSignalMapper successfully in a similar situation. For any
interested, I worked around the problem using a closure, which seems a
bit cleaner from a coding point of view, although I don't have any idea
if it is more efficient or not:

def makeHandler(self, idx):
def handler(state):
print 'The state is:', str(state), 'for checkbox object',
str(idx)
return handler

Each iteration then created a new function based on the closure:

self.handlers = []
for idx in range(1, maxIngredients+1):
wName = 'chkProductIngredientsDelete_'+str(idx)
w = self.__dict__[wName]
self.handlers.append(self.makeHandler(idx - 1))
self.window.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.handlers[idx - 1])

So now the output when each checkbox is clicked is something like this:

The state is: 2 for checkbox object 0
The state is: 2 for checkbox object 1
....

David Boddie wrote:
borntonetwork wrote:
Thanks, David, for you help.

When I change the slot function to what you show in your second
example, I get the same results: nothing.

This may be due to something I missed in your code. When you
connect the signal from the signal mapper to your class, you
need to specify the signal as a C++ signature as well:

self.connect(self.signalMapper, QtCore.SIGNAL(
"mapped(int)"),
self.deleteProductIngredient)

The second example should now work.

Looking at the first example, which uses SLOT() rather than specifying
a Python method, the following might be due to the way you call
connect, though it is surprising:
When I change it to what you
have in your first example, I get the following:

Object::connect: No such slot QApplication::map()
Object::connect: (sender name: 'chkProductIngredientsDelete_1')
Object::connect: (receiver name: 'main.py')

[...]

It looks like you should try something like this:

self.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.signalMapper,
QtCore.SLOT("map()"))

I can't understand why calling self.app.connect() would cause the
connection to be attempted between self.signalMapper and self.app.

Maybe someone on the PyQt/PyKDE mailing list would be able to
explain the behaviour you're seeing:

http://mats.imk.fraunhofer.de/mailman/listinfo/pykde

David
Jan 20 '07 #5
On Saturday 20 January 2007 16:03, borntonetwork wrote:
David, thanks for your help. Unfortunately, all attempts of making this
solution work have failed. I would be interested to know if anyone has
used QSignalMapper successfully in a similar situation.
Looking again at what you originally wrote, and looking at your
solution below, I don't think it's really appropriate to use a
QSignalMapper for this purpose. (That's what I understood from the
signature of the deleteProductIngredient() method you had in your
original code.)

What you appear to want is a way of being notified about state
changes to widgets that also identifies the individual widget
that changed. You can do that by connecting the individual widgets
to the same slot and call sender() to find out which object emitted
the signal; for example:

# ...

********for*idx*in*range(1,*maxIngredients+1):
************wName*=*'chkProductIngredientsDelete_' +str(idx)
************w*=*self.__dict__[wName]
************self.connect(w,*QtCore.SIGNAL("stateCh anged(int)"),
************ self.deleteProductIngredient)

def deleteProductIngredient(self, state):
"""Delete a product ingredient."""
print self.sender(), "changed state to", state

What QSignalMapper does is collect signals from different objects,
assigning an ID to each of them, and emits a single signal with
an ID whenever it receives a signal from one of those objects.
In other words, it allows the actions of a group of objects to be
described by a parameter but discards the signal's arguments.
It's most useful for things like collections of push buttons where
you only need to know that they were clicked.
For any interested, I worked around the problem using a closure,
which seems a bit cleaner from a coding point of view, although
I don't have any idea if it is more efficient or not:
[...]
Each iteration then created a new function based on the closure:
[...]

It's good to know that you got something working in the end. There's
also another solution that involves QSignalMapper, but it may not make
the resulting code any simpler.

David
Jan 20 '07 #6
How simple. I will remember that sender() function for future
reference.
Thanks, David.

David Boddie wrote:
On Saturday 20 January 2007 16:03, borntonetwork wrote:
David, thanks for your help. Unfortunately, all attempts of making this
solution work have failed. I would be interested to know if anyone has
used QSignalMapper successfully in a similar situation.

Looking again at what you originally wrote, and looking at your
solution below, I don't think it's really appropriate to use a
QSignalMapper for this purpose. (That's what I understood from the
signature of the deleteProductIngredient() method you had in your
original code.)

What you appear to want is a way of being notified about state
changes to widgets that also identifies the individual widget
that changed. You can do that by connecting the individual widgets
to the same slot and call sender() to find out which object emitted
the signal; for example:

# ...

for idx in range(1, maxIngredients+1):
wName = 'chkProductIngredientsDelete_'+str(idx)
w = self.__dict__[wName]
self.connect(w, QtCore.SIGNAL("stateChanged(int)"),
self.deleteProductIngredient)

def deleteProductIngredient(self, state):
"""Delete a product ingredient."""
print self.sender(), "changed state to", state

What QSignalMapper does is collect signals from different objects,
assigning an ID to each of them, and emits a single signal with
an ID whenever it receives a signal from one of those objects.
In other words, it allows the actions of a group of objects to be
described by a parameter but discards the signal's arguments.
It's most useful for things like collections of push buttons where
you only need to know that they were clicked.
For any interested, I worked around the problem using a closure,
which seems a bit cleaner from a coding point of view, although
I don't have any idea if it is more efficient or not:

[...]
Each iteration then created a new function based on the closure:

[...]

It's good to know that you got something working in the end. There's
also another solution that involves QSignalMapper, but it may not make
the resulting code any simpler.

David
Jan 21 '07 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Bruce W...1 | last post by:
For include files I see both the file extensions .php and .inc used. Which one is proper? Does it matter? What's the diff? Thanks for your help.
0
by: T. Kaufmann | last post by:
Hi there, I have some lines of code in a Tkinter programm - I want to list every single file of a zip-archive in a Text widget: fp = os.popen("%s %s" % ('unzip -vl ', 'anyarchiv.zip', 'r')...
3
by: m.ramana | last post by:
Given a string it should convert it to a proper text. Example: if you passed a string 'Cat in the hat', I want 'Cat In The Hat' Curious about few things, Does sql have Instr OR Split(like VB)...
2
by: Kevin | last post by:
I am currently importing data into Access 2002 from 3 Sybase ASA 7.0 databases over a network. At this time I am using a ODBC System DSN connection using the proper ASA 7 driver. I would like to...
1
by: RC | last post by:
I have an Access 2002 database with many tables and forms (but just to keep things simple, let's say the DB has one Table "Table1" and one Form "Form1"). I have managed to cobble together so much...
0
by: bj | last post by:
hello is there any chance to get proper char width for class derived from user control - im working over text editing control, so i need proper width of every character for currently selected...
0
by: yogarajan | last post by:
hi all i need proper alignment my treeview looks like <checkbox>Fruits(parent)-134 <checkbox>Mango(child)-45 <checkbox>Orange(child)-45 ...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.