4

I'm trying to get statistics on how many time a button was clicked in PySide.

Data is stored in a dictionnary, and I'd like the key to be the clicked-function name:

Example : {"myAwesomeFunc" : 15, "anotherFunc" : 4}

I start with converting my existing (Autodesk) Maya-UI with hundreds of buttons into a QObject.

Then, I list all the buttons using the findChildren(QPushButton) method and I connect to each of them my own getStats() function, using btn.clicked.connect(getStat).

Doing so, the buttons will then execute two functions when clicked, the original one from the UI, and my stat function that will increment the dictionnary.

So, where I'm stuck is how can I query the original function name associated to the button's "clicked" method ?

Example:

def myAwesomeFunc():
    return

btn = QtGui.QPushButton()
btn.clicked.connect(myAwesomeFunc)

And then, what I'm looking for would be something like this :

funcList = btn.clicked.getFunctions()
myFunc = funcList[0]

print myFunc.__name__
result : "myAwesomeFunc"
NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
Ben
  • 244
  • 2
  • 9
  • At least in C++/Qt, it is impossible, but also it means problem with programm architecting, so tell us what you try to achieve. Maybe there is another solution. Also it is you (programmer) establish connection, so you can add it to some list or dict manually if you need this, because there is no built-in approach to achieve this. – Jablonski Aug 18 '15 at 15:34
  • I've updated the question with what I wanna do exactly. Let me know if it doesn't make sense! – Ben Aug 18 '15 at 16:10
  • 1
    Hm, you said: `how many time a button was clicked` and also `I'd like the KEY to be the CLICKED-FUNCTION` , why not a pointer to button (button itself)? – Jablonski Aug 18 '15 at 16:16
  • "I'd like the KEY to be the CLICKED-FUNCTION **NAME*" So, when the UI was created, if someone made a button in it with the function "extractNames()", then, I'd like the key to be "extractNames". The UI can change anytime as it's used by several people who can add buttons to it whenever they want. What do you mean by pointer to the button. I already have the button when its being listed by the findChildren() method? (Sorry my Qt skills are pretty limited as I only recently started...) – Ben Aug 18 '15 at 16:37
  • I just think in C++ so i used word `pointer`, in python it is just a button. Accordingly to this answer: http://stackoverflow.com/questions/2755694/determine-signals-connected-to-a-given-slot-in-qt there is no way to do it, as I said earlier. As I understood, you need to collect and show statistic (how many times button was clicked, not a how many times slots was invoked), so in my opinion your findChildren() and getStats is correct approach and you need to store dict with {QPushButton: 15, "anotherQPushButton" : 4} – Jablonski Aug 18 '15 at 16:50
  • That is kind of what I'm doing at the moment : using the button.text() (label) as the key, but I noticed that within the UI (that has several tabs, and stuff) some buttons have the same labels, some doesn't have one, etc... So it's hard for me to precisely identify the function that's being executed by the button. The idea behind this is to get rid of the less used tools in the UI. – Ben Aug 18 '15 at 17:12
  • You shouldn't use text() as a key, because it is of course not unique. Try to use object as key, because every button is unique. – Jablonski Aug 18 '15 at 17:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/87296/discussion-between-ben-and-chernobyl). – Ben Aug 18 '15 at 17:21

1 Answers1

1

A signal can be connected to many slots and these connection can change over time. While in principle the framework knows which signals to call, it isn't easy to get to know these slots (see also Determine signals connected to a given slot in Qt). However, in PyQt5 there is QSignalSpy which actually does that, so maybe consider using PyQt5.

It seems you are merely interested to get a meaningful key string value for your statistics dictionary. This could either be an identifier of the object holding the signal or an identifier of the slot (the first connected slot as you indicated above). Using the signals as keys would give you a statistics how often each signal (the buttons) are emitted and using the slots as keys would give you a statistics how often each slot is called by a signal. This does not have to be the same, because different signals could be connected to the same slot for example.To avoid this you would actually have to store both the name of the signal and the name of the slot as keys in your dictionary (so you know who called whom).

The easiest way I can think of is to wrap the signal connect calls and insert code calling the statistics using manually chosen key strings.

So search and replace all

btn.clicked.connect(myAweSomeFunc)

by

my_connect(btn.clicked, myAweSomeFunc, 'myAweSomeFunc')

with

from functools import partial
def my_connect(signal, slot, key):
    # connect signal to slot
    signal.connect(slot)
    # connect signal to statistics function using key as key
    signal.connect(partial(getStats, key))

def getStats(key):
    statistics[key] += 1

Disadvantage is that the key string has to be chosen manually. This might become tedious. You might want to use replace using regular expressions in order to duplicate the name of the slot as string in order to automatize the whole task.

Community
  • 1
  • 1
NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • 1
    I [answered](http://stackoverflow.com/a/22625200/984421) a similar question on this subject, and discovered that `QSignalSpy` is no use either. All it does is record the arguments that were sent, rather than where they were sent to. There is also a big problem with adding an extra slot to record the emits: what if some part of the code calls `btn.clicked.disconnect()`? – ekhumoro Nov 10 '16 at 21:53