Unsolved Signal/slot vs direct call, and related question
-
Two questions: one stylistic, one implementation.
GUI application, main window with several widget-windows on it, one of which is a
QGraphicsScene
(sub-classed). Objects there can be copy/pasted etc.- Style: "To signal/slot or not to signal/slot, that is the question..."
Inherited code which used
QGraphicsScene::keyPressEvent()
to capture and act on the Copy etc. key presses. Now that these actions have been added to the main window's menu with shortcuts, that stops working (and I need to deal with menu actions anyway).As I move to the action handler in the main window, I simply call directly the desired exported method from the graphics scene sub-class. Is there any good reason why I should instead raise a signal for these actions, and make the methods slots? The main window would still need to see those methods exported so that it can
connect()
to them, at which point am I just as good with a direct call?- Implementation
When the code was in
QGraphicsScene::keyPressEvent()
we knew that the key press was directed at theQGraphicsScene
. Now the actions are on main menu we do not, it could be for other windows. What is the "rule" I need to test for (presumably in main window action handler) before I pass on to deal with inQGraphicsScene
window? It's not enough to say "is there an item selected on the scene", is it? I presume I'm supposed to test for something like where the focus is, is that it?? Or is it "window is activated" (I don't think so)? Or what? -
@JonB said in Signal/slot vs direct call, and related question:
Now that these actions have been added to the main window's menu with shortcuts, that stops working (and I need to deal with menu actions anyway).
Your
keyPressEvents
are shortcuts?!
Why dont you useQShortcut
?! You can set aShortcutContext (click)
to trigger your actions even when your scene doesn't have focus. Then you redirect your shortcut to your scene.@JonB said in Signal/slot vs direct call, and related question:
What is the "rule" I need to test for (presumably in main window action handler) before I pass on to deal with in QGraphicsScene window? It's not enough to say "is there an item selected on the scene", is it? I presume I'm supposed to test for something like where the focus is, is that it?? Or is it "window is activated" (I don't think so)? Or what?
QShortcut
handles that for you, if you useWindowShortcut
orApplicationShortcut
.
If your window or widget, where yourscene
is in, is a child ofMainWindow
yourscene
doesnt even need focus (AppShortcut: your shortcut works everywhere, you just need one active window) -
@Pl45m4
Sorry, I don't understand any of this, and don't think it relates to what I am asking.I know how shortcuts work and how to use them. I'm (now) using shortcuts, as I explained.
Inherited code which used QGraphicsScene::keyPressEvent() to capture and act on the Copy etc. key presses. Now that these actions have been added to the main window's menu with shortcuts, that stops working (and I need to deal with menu actions anyway).
You suggested:
to trigger your actions even when your scene doesn't have focus.
That's 100% precisely what I don't want to happen. The whole point is asking how, when an action on a main window menu is triggered by click or shortcut (doesn't matter which), how you decide which widget is supposed to respond to it. I do not want to direct a Copy command to the scene if it does not have focus, do I? That is what I am asking about.
-
@JonB said in Signal/slot vs direct call, and related question:
how you decide which widget is supposed to respond to it.
Aren't your
QActions
in your menu connected to some slots (at destination)?It seems, that I really dont understand your problem :-)
@JonB said in Signal/slot vs direct call, and related question:
I do not want to direct a Copy command to the scene if it does not have focus, do I? That is what I am asking about.
Ah, check. You want
Qt::WidgetShortcut
behavior, but still trigger yourQActions
from your mainWindow's menuBar (or wherever they are) to copy your GraphicItem?! -
Hi,
How are you creating your actions ?
-
@Pl45m4 said in Signal/slot vs direct call, and related question:
Ah, check. You want Qt::WidgetShortcut behavior, but still trigger your QActions from your mainWindow's menuBar (or wherever they are) to copy your GraphicItem?!
This sounds like it. Yes I think to all. Let me go read about
Qt::WidgetShortcut
...! :)@SGaist
Menu items/actions/shortcuts are created in Designer, with whatever default. Each item has an action triggered slot in the MainWindow class. I have, say, a Copy menu item/shortcut. The gfx scene does its own copy stuff. I want to know how I am supposed to know, when the action slot is hit, that it should be directed to the gfx widget.Since asking this earlier, I now have in Main Window slot something like
def copy_action(self): if QApplication.focusWidget() is scene_view: scene.do_copy_action()
and that works.
See also my post today at https://forum.qt.io/topic/80019/find-which-widget-had-focus-when-menu-item-is-clicked/8.
-
Do you have several different widgets which are providing copy behaviour ?
-
@JonB said in Signal/slot vs direct call, and related question:
The gfx scene does its own copy stuff. I want to know how I am supposed to know, when the action slot is hit, that it should be directed to the gfx widget.
Do you also have multiple scenes or graphicsViews?
Otherwise why dont you connect your copy-action with a slot in your custom scene, determine which item shoud be copied (if this is relevant?!) and then let the scene do its copy work? :) -
@SGaist said in Signal/slot vs direct call, and related question:
Do you have several different widgets which are providing copy behaviour ?
As of today, no. But as of tomorrow, quite possibly. There are a couple of other "panes" in the main window. They do not currently copy. But most importantly, if they have "focus" the I do not want the Copy/Paste menu actions/shortcuts to go to the gfx widget.
@Pl45m4
Only one scene/view. As of today.The scene does do the copy work. The code does not call slots in other modules (nor do I think Designer offers that). For consistency, all action trigger slots are in main window class. I expected to implement a "dispatcher" which figured which window had the focus and call its method as required. As I said, FWIW I haven't looked at
Qt::WidgetShortcut
, yet. -
You can associate an action with several widgets. Did you check if sender gives you the information you seek once you add the action to all the widgets you want to use it on ?
-
@SGaist said in Signal/slot vs direct call, and related question:
once you add the action to all the widgets you want to use it on
The code is not (presently) written that way. All menu items/toolbar items/shortcuts have actions & slots in the main window class. I guess all shortcuts are the default
Qt::WindowShortcut
. Most do not care what the focused widget is, e.g. New/Open/Save/Exit etc. In the case of Copy/Cut/Paste, however, it does matter whether, say, the graphics widget has the focus.I expected to handle that in the main window action slot by checking which widget has focus. It sounds like maybe if I look into using
Qt::WidgetShortcut
(or maybeQt::WidgetWithChildrenShortcut
?) on Copy/Cut/Paste for the gfx widget (and any others which might want these in the future), the menu items and shortcut keys will only activate when the desired window is focused, and my main window will not have to decide who to "dispatch" to. I need to have a look at how this behaves tomorrow.... -
@Pl45m4 , @SGaist
Now I am trying to make this work withQt::WidgetShortcut
, which does seem like it should be the right approach. However, it does not work correctly at all! Please don't abandon me! Read on...- I have a
QMainWindow
. I design it, and add its toolbar/menu items/shortcuts in Designer. - It has 4 widgets inside it. One of them is the
QGraphicsScene/View
. That has code for, say, Cut. The others do not (at present) have anything for Cut. - In the case of a menu item/toolbar/shortcut key Cut I want that to go to the gfx view if it has the focus, else it should be ignored.
This really should not be an unusual situation. Some menu items function regardless of which widget has focus (e.g. Save), some depend on which widget has focus (e.g. Cut).
I start from the relevant code as generated (
mainwindow.py
), which includes:self.action_cut = QtWidgets.QAction(MainWindow) self.action_cut.setShortcutContext(QtCore.Qt.WindowShortcut) self.menuEdit.addAction(self.action_cut) self.toolBar.addAction(self.action_cut) self.action_cut.setShortcut(QtWidgets.QApplication.translate("MainWindow", "Ctrl+X", None, -1))
To make this work, I have found I can go:
self.action_cut.triggered.connect(self.cut) def cut(self): if QApplication.focusWidget() is self.graphicsView_model: self.model_scene.cutItems()
At this point:
- If I click the toolbar/menu item, regardless of where focus is my
cut()
is hit. Its code determines whether the gfx widget has focus or not, and correctly works accordingly. - If I click Ctrl+X, if the current focus widget absorbs that (e.g. a
QLineEdit
in some other widget). If not (e.g. on a plainQWidget
) it goes via mycut()
, and again that checks focus and works correctly.
Now I try changing as best I can to make the Cut only apply to my gfx widget. I change/add things like:
self.action_cut.setParent(self.graphicsView_model) # OR self.action_cut = QtWidgets.QAction(self.graphicsView_model) self.action_cut.setShortcutContext(QtCore.Qt.WidgetShortcut) # OR self.action_cut.setShortcutContext(QtCore.Qt.WidgetWithChildrenShortcut)
At this point:
- If I click toolbar/menu it still calls my
cut()
regardless of where focus is. It has not made it so this is only called whenself.graphicsView_model
has focus. So I will still need to testif QApplication.focusWidget() is self.graphicsView_model
. - Ctrl+X no longer does anything, regardless of focus.
Both of these are no good/not expected.
I came across thread starting at https://lists.qt-project.org/pipermail/qt-interest-old/2011-February/031257.html. I think that guy reports my findings trying to use
Qt::WidgetShortcut
. Summary:So if I install an action on a QWidget I would assume that the actions
shortcut is only active if the QWidget has focus, right? But this seems
to be broken somehow.
.
My educated guess would be that this "shortcut context" thing might only work between "dialog and main windows", but not between common QWidgets?In a word: if you expect
Qt::WidgetShortcut
to work for me, please tell me how?!My case should not be that unusual: some menu items/shortcuts apply regardless of focused window, some do not. If you do not want me to have to use my
if QApplication.focusWidget() is self.graphicsView_model
-type-dispatching, please tell me how?! I'm exhausted typing this all up....P.S.
And this is only a P.S., I really don't think this is to do with the problem:
@SGaist said in Signal/slot vs direct call, and related question:You can associate an action with several widgets. Did you check if sender gives you the information you seek once you add the action to all the widgets you want to use it on ?
See the accepted solutuon at https://stackoverflow.com/a/6003452/489865. Note how the approach is still to look at
QWidget::hasFocus()
to decide which the user was in when trying to invoke the action. If I'm going to do that, my current code will suffice. - I have a