PDA

View Full Version : How to find the control that triggered a QAction



drmacro
22nd July 2017, 15:43
I have a bunch of sliders. When I create the sliders I give them each a name with .setObjectName and add a set of actions with .addActions.

When I right click on a slider it does as expected and calls the code specified by the definition of the action. In this case it is the same code for each action and that code dispatches to the appropriate code for the action.

How do I find the slider that actually triggered the action? (i.e. I need to read the value of the slider) (when I call .sender().objectName() it returns an empty string)

d_stranz
22nd July 2017, 23:09
If your slot is connected to the QAction's triggered() signal, then sender() is the QAction instance, not the widget to which you added it. I don't know if there is any way to recover the pointer to the widget.

drmacro
23rd July 2017, 17:24
What I want to do is pop a list when the user right clicks on the slider offering some optional things to do. All the sliders will do the same thing, but just act on the slider that was right clicked.

I got, what I assume is a kludge way of doing it, working:

In the init for the dialog:



self.slider_entered = ''
self.sldr_actions_list = []
self.sldr_action_names = ['Set Min', 'Set 0db', 'Propagate level']
for action_name in self.sldr_action_names:

newaction = QAction(action_name, None)
newaction.triggered.connect(eval('self.slider_acti on_{}'.format(action_name.replace(' ', '_').lower())))
self.sldr_actions_list.append(newaction)



When the slider is added:


sldr = MySlider()
sldr.setContextMenuPolicy(Qt.ActionsContextMenu)
sldr.addActions(self.sldr_actions_list)


MySlider inherits from QSLider and has:



def enterEvent(self, m_ev):
self.window().slider_entered = self.objectName()


and the code for the actions in the dialog, set min in this case:



def slider_action_set_min(self):
act_sndr = self.sender()
sldr = self.window().findChild(QtWidgets.QSlider, name=self.slider_entered)
print('Set slider to min. Current value: {}'.format(sldr.value()))
self.slider_set(self.slider_entered, 0)



What I want to do is pop a list when the user right clicks on the slider offering some optional things to do. All the sliders will do the same thing, but just act on the slider that was right clicked.

I got, what I assume is a kludge way of doing it, working:

In the init for the dialog:



self.slider_entered = ''
self.sldr_actions_list = []
self.sldr_action_names = ['Set Min', 'Set 0db', 'Propagate level']
for action_name in self.sldr_action_names:

newaction = QAction(action_name, None)
newaction.triggered.connect(eval('self.slider_acti on_{}'.format(action_name.replace(' ', '_').lower())))
self.sldr_actions_list.append(newaction)



When the slider is added:


sldr = MySlider()
sldr.setContextMenuPolicy(Qt.ActionsContextMenu)
sldr.addActions(self.sldr_actions_list)


MySlider inherits from QSLider and has:



def enterEvent(self, m_ev):
self.window().slider_entered = self.objectName()


and the code for the actions in the dialog, set min in this case:



def slider_action_set_min(self):
act_sndr = self.sender()
sldr = self.window().findChild(QtWidgets.QSlider, name=self.slider_entered)
print('Set slider to min. Current value: {}'.format(sldr.value()))
self.slider_set(self.slider_entered, 0)



Added after 1 30 minutes:

I think I found the right way (or at least a better way) :rolleyes:

When I create the slider:



sldr.setContextMenuPolicy(Qt.CustomContextMenu)
sldr.customContextMenuRequested.connect(self.sldr_ action_click)



then the self.sender() in self.sldr_action_click is the slider.

d_stranz
23rd July 2017, 18:12
I think I found the right way (or at least a better way)

Yep, that's it.

From what I understand of your previous (kludge) code, it appeared to have a pretty big memory leak since it looks like the QAction instances are created every time the slider is entered, but they're never deleted. I'm not a Python expert, so my reading of your code might be wrong.

drmacro
23rd July 2017, 18:27
From what I understand of your previous (kludge) code, it appeared to have a pretty big memory leak since it looks like the QAction instances are created every time the slider is entered, but they're never deleted. I'm not a Python expert, so my reading of your code might be wrong.

I thought only the string self.slider_entered was set every time the widget was entered...

But, I'm not a python expert either (maybe semi-seasoned hack...on a good day :o ). I could have watched for memory growth to see but Ive changed the code over to the better way and not going back now... :rolleyes: