Discussion:
QLineEdit vs. menu keyboard shortcuts
Nathan Weston
2011-06-28 15:50:40 UTC
Permalink
QLineEdit has some keyboard shortcuts (e.g. Ctrl+Z for Undo) that clash
with the shortcuts for QActions in my application menus. When a
QLineEdit has keyboard focus, it intercepts these shortcuts and my
QActions are never triggered.

I'd like to give application-level shortcuts precedence over QLineEdit's
shortcuts, but I can't seem to find a clean and general way to do this.

Alternatively, is there a way to customize the keyboard shortcuts in
QLineEdit? If I could disable some of the problematic shortcuts that
would be a reasonable workaround.

- Nathan
Baz Walter
2011-06-28 17:48:16 UTC
Permalink
Post by Nathan Weston
QLineEdit has some keyboard shortcuts (e.g. Ctrl+Z for Undo) that clash
with the shortcuts for QActions in my application menus. When a
QLineEdit has keyboard focus, it intercepts these shortcuts and my
QActions are never triggered.
I'd like to give application-level shortcuts precedence over QLineEdit's
shortcuts, but I can't seem to find a clean and general way to do this.
Alternatively, is there a way to customize the keyboard shortcuts in
QLineEdit? If I could disable some of the problematic shortcuts that
would be a reasonable workaround.
the default key bindings for QLineEdit are hard-coded, but the actual
key sequences used are platform-dependent (and the same goes for most
(all?) other widgets which have them).

but what is your reason for wanting to change the default behaviour?

as a user, i would expect all the 'normal' shortcuts to work when typing
in a line edit. if Ctrl+Z undid something in some other widget that i
wasn't looking at, it could become very confusing. (IIRC this was how
things used to work with qt3 - and good riddance to that!).
Nathan Weston
2011-06-28 17:56:35 UTC
Permalink
Post by Baz Walter
Post by Nathan Weston
QLineEdit has some keyboard shortcuts (e.g. Ctrl+Z for Undo) that clash
with the shortcuts for QActions in my application menus. When a
QLineEdit has keyboard focus, it intercepts these shortcuts and my
QActions are never triggered.
I'd like to give application-level shortcuts precedence over QLineEdit's
shortcuts, but I can't seem to find a clean and general way to do this.
Alternatively, is there a way to customize the keyboard shortcuts in
QLineEdit? If I could disable some of the problematic shortcuts that
would be a reasonable workaround.
the default key bindings for QLineEdit are hard-coded, but the actual
key sequences used are platform-dependent (and the same goes for most
(all?) other widgets which have them).
but what is your reason for wanting to change the default behaviour?
as a user, i would expect all the 'normal' shortcuts to work when typing
in a line edit. if Ctrl+Z undid something in some other widget that i
wasn't looking at, it could become very confusing. (IIRC this was how
things used to work with qt3 - and good riddance to that!).
I have a subclass of QLineEdit for entering numbers. The user can either
type in a number, or drag the mouse to increase/decrease the value, like
a slider (similar widgets are often found in After Effects and other
video editing software).

In the latter mode, the widget is temporarily set as non-editable, so
its built-in Undo behavior doesn't work at all (but it still eats the
keyboard event!).
--
. . . . . . . . . . . . . . . . . . . . . . . . .
Nathan Weston ***@genarts.com
GenArts, Inc. Tel: 617-492-2888
955 Mass. Ave Fax: 617-492-2852
Cambridge, MA 02139 USA www.genarts.com
Hans-Peter Jansen
2011-06-28 18:17:18 UTC
Permalink
Post by Nathan Weston
Post by Baz Walter
Post by Nathan Weston
QLineEdit has some keyboard shortcuts (e.g. Ctrl+Z for Undo) that
clash with the shortcuts for QActions in my application menus.
When a QLineEdit has keyboard focus, it intercepts these shortcuts
and my QActions are never triggered.
I'd like to give application-level shortcuts precedence over
QLineEdit's shortcuts, but I can't seem to find a clean and
general way to do this.
Alternatively, is there a way to customize the keyboard shortcuts
in QLineEdit? If I could disable some of the problematic shortcuts
that would be a reasonable workaround.
the default key bindings for QLineEdit are hard-coded, but the
actual key sequences used are platform-dependent (and the same goes
for most (all?) other widgets which have them).
but what is your reason for wanting to change the default
behaviour?
as a user, i would expect all the 'normal' shortcuts to work when
typing in a line edit. if Ctrl+Z undid something in some other
widget that i wasn't looking at, it could become very confusing.
(IIRC this was how things used to work with qt3 - and good riddance
to that!).
I have a subclass of QLineEdit for entering numbers. The user can
either type in a number, or drag the mouse to increase/decrease the
value, like a slider (similar widgets are often found in After
Effects and other video editing software).
In the latter mode, the widget is temporarily set as non-editable, so
its built-in Undo behavior doesn't work at all (but it still eats the
keyboard event!).
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?

Pete
Baz Walter
2011-06-28 18:25:54 UTC
Permalink
Post by Hans-Peter Jansen
Post by Nathan Weston
In the latter mode, the widget is temporarily set as non-editable, so
its built-in Undo behavior doesn't work at all (but it still eats the
keyboard event!).
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?
it sounds like he might want to drag with the mouse and use keyboard
shortcuts at the same time - otherwise, why worry about keyboard events?

(then again, i might just have completely misunderstood :)
Baz Walter
2011-06-28 18:35:54 UTC
Permalink
Post by Baz Walter
Post by Hans-Peter Jansen
Post by Nathan Weston
In the latter mode, the widget is temporarily set as non-editable, so
its built-in Undo behavior doesn't work at all (but it still eats the
keyboard event!).
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?
it sounds like he might want to drag with the mouse and use keyboard
shortcuts at the same time - otherwise, why worry about keyboard events?
(then again, i might just have completely misunderstood :)
How about setting focus policy to no focus. You can still use drag event but
widget will never be focused therefore doesn't interfere with shortcuts.
(re-posting this to the list)
_______________________________________________
PyQt mailing list ***@riverbankcomputing.com
http://www.riverbankcomputing.com/m
Nathan Weston
2011-06-29 13:50:58 UTC
Permalink
Post by Hans-Peter Jansen
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?
I can certainly do that, but it doesn't cause my QActions to trigger. I
could intercept specific shortcuts and manually trigger the QActions,
but then my QLineEdit subclass has to know about all the menu items,
which is pretty ugly.

The interaction between QAction shortcuts and widget-specific shortcuts
is a little strange. I've written a little test program: it's a
QMainWindow with some menu items and a QLineEdit subclass as the central
widget.

The first menu item has Ctrl+R as its shortcut, which doesn't clash with
anything in QLineEdit. If I type Ctrl+R, the action intercepts the
keypress event *before* QLineEdit gets it -- I never see a keyPressEvent.

The menu item shortcut has Ctrl+Z as a shortcut. If I type Ctrl+Z, the
QLineEdit gets a keyPressEvent, which causes an undo of the text. If I
ignore() the event, it disables the undo behavior, but my QAction still
doesn't fire.

I've attached my program. If you press Ctrl+Z it will print 'Foo
keyPress 16777249' (for the Ctrl) and 'Foo keyPress 90' (for the Z). If
you press Ctrl+R it just prints 'action' from the slot connected to my
QAction.

Does anyone understand what's going on under the hood here?
--
. . . . . . . . . . . . . . . . . . . . . . . . .
Nathan Weston ***@genarts.com
GenArts, Inc. Tel: 617-492-2888
955 Mass. Ave Fax: 617-492-2852
Cambridge, MA 02139 USA www.genarts.com
Andreas Pakulat
2011-06-29 14:34:06 UTC
Permalink
Post by Nathan Weston
Post by Hans-Peter Jansen
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?
I can certainly do that, but it doesn't cause my QActions to
trigger. I could intercept specific shortcuts and manually trigger
the QActions, but then my QLineEdit subclass has to know about all
the menu items, which is pretty ugly.
The interaction between QAction shortcuts and widget-specific
it's a QMainWindow with some menu items and a QLineEdit subclass as
the central widget.
The first menu item has Ctrl+R as its shortcut, which doesn't clash
with anything in QLineEdit. If I type Ctrl+R, the action intercepts
the keypress event *before* QLineEdit gets it -- I never see a
keyPressEvent.
The menu item shortcut has Ctrl+Z as a shortcut. If I type Ctrl+Z,
the QLineEdit gets a keyPressEvent, which causes an undo of the
text. If I ignore() the event, it disables the undo behavior, but my
QAction still doesn't fire.
I've attached my program. If you press Ctrl+Z it will print 'Foo
keyPress 16777249' (for the Ctrl) and 'Foo keyPress 90' (for the Z).
If you press Ctrl+R it just prints 'action' from the slot connected
to my QAction.
Does anyone understand what's going on under the hood here?
--
. . . . . . . . . . . . . . . . . . . . . . . . .
GenArts, Inc. Tel: 617-492-2888
955 Mass. Ave Fax: 617-492-2852
Cambridge, MA 02139 USA www.genarts.com
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
print 'Foo keyPress', event.key(); sys.stdout.flush()
QLineEdit.keyPressEvent(self, event)
app = QApplication([])
window = QMainWindow()
f = Foo()
window.setCentralWidget(f)
window.show()
print 'action'; sys.stdout.flush()
action1 = QAction('Action 1', f, triggered=do_action)
action1.setShortcut(Qt.CTRL + Qt.Key_Z)
action1.setShortcutContext(Qt.WidgetShortcut)
For actions that should work all over the mainwindow, you should use
Qt.WidgetWithChildren here.

Andreas
Nathan Weston
2011-06-29 14:39:15 UTC
Permalink
Post by Andreas Pakulat
Post by Nathan Weston
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
print 'Foo keyPress', event.key(); sys.stdout.flush()
QLineEdit.keyPressEvent(self, event)
app = QApplication([])
window = QMainWindow()
f = Foo()
window.setCentralWidget(f)
window.show()
print 'action'; sys.stdout.flush()
action1 = QAction('Action 1', f, triggered=do_action)
action1.setShortcut(Qt.CTRL + Qt.Key_Z)
action1.setShortcutContext(Qt.WidgetShortcut)
For actions that should work all over the mainwindow, you should use
Qt.WidgetWithChildren here.
Oops, that line was an artifact of an earlier experiment. I actually
tried every possible value for shortcutContext, none of them seem to
make a difference.
Baz Walter
2011-06-29 17:07:19 UTC
Permalink
Post by Nathan Weston
Post by Hans-Peter Jansen
If you're subclassing QLineEdit anyway, what does stop you from
overriding keyPressEvent to catch and accept() any unwanted key
presses?
I can certainly do that, but it doesn't cause my QActions to trigger. I
could intercept specific shortcuts and manually trigger the QActions,
but then my QLineEdit subclass has to know about all the menu items,
which is pretty ugly.
The interaction between QAction shortcuts and widget-specific shortcuts
is a little strange. I've written a little test program: it's a
QMainWindow with some menu items and a QLineEdit subclass as the central
widget.
The first menu item has Ctrl+R as its shortcut, which doesn't clash with
anything in QLineEdit. If I type Ctrl+R, the action intercepts the
keypress event *before* QLineEdit gets it -- I never see a keyPressEvent.
The menu item shortcut has Ctrl+Z as a shortcut. If I type Ctrl+Z, the
QLineEdit gets a keyPressEvent, which causes an undo of the text. If I
ignore() the event, it disables the undo behavior, but my QAction still
doesn't fire.
I've attached my program. If you press Ctrl+Z it will print 'Foo
keyPress 16777249' (for the Ctrl) and 'Foo keyPress 90' (for the Z). If
you press Ctrl+R it just prints 'action' from the slot connected to my
QAction.
Does anyone understand what's going on under the hood here?
as was suggested earlier in this thread, if the line-edit doesn't have
the keyboard focus, it can't trigger its own shortcuts. if it *does*
have the focus, but the shortcut sequence is not one it handles, the
keypress event will be re-propagated (as happens with 'Ctrl+R' in your
example).

the simplest way to control the focus is to use clearFocus() and setFocus().
Baz Walter
2011-06-29 17:32:39 UTC
Permalink
Post by Baz Walter
as was suggested earlier in this thread, if the line-edit doesn't have
the keyboard focus, it can't trigger its own shortcuts. if it *does*
have the focus, but the shortcut sequence is not one it handles, the
keypress event will be re-propagated (as happens with 'Ctrl+R' in your
example).
the simplest way to control the focus is to use clearFocus() and setFocus().
please reply to the list so that everyone can read your comments.
Unfortunately, I need the line-edit to have keyboard focus (and respond
to some keyboard shortcuts), without bashing my global menu shortcuts.
It seems like there *should* be a clean way to do this by mucking around
with the keyPressEvent, but so far nobody seems to know of one.
did you actually try what was suggested?

going back to your earlier example of dragging in the line-edit to
change its value: all you need to do is clearFocus() when the drag
starts and setFocus() when the drag ends. that way, whilst the drag is
in progress, the line-edit's shortcuts won't work, but your global
shortcuts will.

if that's not what you want, please try to make it clear what you do
want (i.e. with a working example).

HTH
Nathan Weston
2011-06-29 17:57:18 UTC
Permalink
Post by Baz Walter
Post by Baz Walter
as was suggested earlier in this thread, if the line-edit doesn't have
the keyboard focus, it can't trigger its own shortcuts. if it *does*
have the focus, but the shortcut sequence is not one it handles, the
keypress event will be re-propagated (as happens with 'Ctrl+R' in your
example).
the simplest way to control the focus is to use clearFocus() and setFocus().
Unfortunately, I need the line-edit to have keyboard focus (and respond
to some keyboard shortcuts), without bashing my global menu shortcuts.
It seems like there *should* be a clean way to do this by mucking around
with the keyPressEvent, but so far nobody seems to know of one.
did you actually try what was suggested?
going back to your earlier example of dragging in the line-edit to
change its value: all you need to do is clearFocus() when the drag
starts and setFocus() when the drag ends. that way, whilst the drag is
in progress, the line-edit's shortcuts won't work, but your global
shortcuts will.
if that's not what you want, please try to make it clear what you do
want (i.e. with a working example).
Short answer: focus tricks won't work for me. I need the widget to be
able to accept keyboard focus and respond to some keyboard shortcuts.

Long answer:
I guess this will require a complete specification of how my widget works.

The widget appears to the user somewhat like a label displaying a
number. If the user clicks and drags, the value will increase or
decrease as the mouse is moved. By holding down modifier keys the user
can adjust the speed with which the value changes.

If the user clicks (but doesn't drag), the number is highlighted and a
text editing cursor appears. The widget at this point behaves exactly
like a QLineEdit (with a validator to force numeric values). When the
user presses Enter or the widget loses focus, it reverts to its default
appearance.

If the widget has keyboard focus, but isn't in edit mode, the Up/Down
arrow keys will "nudge" the value a small amount in either direction.

I am implementing this as a subclass of QLineEdit, overriding mouse and
keyboard events and throwing in some CSS to make it look nice. When the
widget is in "edit mode" it's set to editable, otherwise it's set to
non-editable.

Now, when the widget is in its non-editable state, and the user hits
Ctrl-Z, I want it to trigger the Undo action on the Edit menu.
Unfortunately, QLineEdit intercepts the Ctrl-Z keystroke and does
nothing (because it's not editable).

I can't call clearFocus() at the end of the drag, because this would
break the Up/Down arrow shortcuts.

- Nathan
Baz Walter
2011-06-29 22:16:23 UTC
Permalink
Post by Nathan Weston
Post by Baz Walter
going back to your earlier example of dragging in the line-edit to
change its value: all you need to do is clearFocus() when the drag
starts and setFocus() when the drag ends. that way, whilst the drag is
in progress, the line-edit's shortcuts won't work, but your global
shortcuts will.
if that's not what you want, please try to make it clear what you do
want (i.e. with a working example).
[snip]
Post by Nathan Weston
Now, when the widget is in its non-editable state, and the user hits
Ctrl-Z, I want it to trigger the Undo action on the Edit menu.
Unfortunately, QLineEdit intercepts the Ctrl-Z keystroke and does
nothing (because it's not editable).
the example you posted earlier works (i.e. Ctrl+Z prints 'action') if
the Foo widget has been set as read-only.

(nb: the setShortcutContext line also needs to be commented out)
Post by Nathan Weston
I can't call clearFocus() at the end of the drag, because this would
break the Up/Down arrow shortcuts.
call clearFocus() at the *start* of the drag, setFocus() at the *end*.
Nathan Weston
2011-06-30 14:44:16 UTC
Permalink
Post by Baz Walter
Post by Nathan Weston
Post by Baz Walter
going back to your earlier example of dragging in the line-edit to
change its value: all you need to do is clearFocus() when the drag
starts and setFocus() when the drag ends. that way, whilst the drag is
in progress, the line-edit's shortcuts won't work, but your global
shortcuts will.
if that's not what you want, please try to make it clear what you do
want (i.e. with a working example).
[snip]
Post by Nathan Weston
Now, when the widget is in its non-editable state, and the user hits
Ctrl-Z, I want it to trigger the Undo action on the Edit menu.
Unfortunately, QLineEdit intercepts the Ctrl-Z keystroke and does
nothing (because it's not editable).
the example you posted earlier works (i.e. Ctrl+Z prints 'action') if
the Foo widget has been set as read-only.
(nb: the setShortcutContext line also needs to be commented out)
Interesting... it works as you say on my Linux machine at home, but not
on my Windows machine at work. The Windows machine has Qt 4.6.2, I don't
know about the Linux machine off the top of my head. What platform/Qt
version are you testing on?
Post by Baz Walter
Post by Nathan Weston
I can't call clearFocus() at the end of the drag, because this would
break the Up/Down arrow shortcuts.
call clearFocus() at the *start* of the drag, setFocus() at the *end*.
I don't see how that would help... after the drag, the line-edit will
have focus again, and will eat the Ctrl-Z shortcut.
--
. . . . . . . . . . . . . . . . . . . . . . . . .
Nathan Weston ***@genarts.com
GenArts, Inc. Tel: 617-492-2888
955 Mass. Ave Fax: 617-492-2852
Cambridge, MA 02139 USA www.genarts.com
Nathan Weston
2011-06-30 15:56:28 UTC
Permalink
Post by Nathan Weston
Post by Baz Walter
Post by Nathan Weston
Post by Baz Walter
going back to your earlier example of dragging in the line-edit to
change its value: all you need to do is clearFocus() when the drag
starts and setFocus() when the drag ends. that way, whilst the drag is
in progress, the line-edit's shortcuts won't work, but your global
shortcuts will.
if that's not what you want, please try to make it clear what you do
want (i.e. with a working example).
[snip]
Post by Nathan Weston
Now, when the widget is in its non-editable state, and the user hits
Ctrl-Z, I want it to trigger the Undo action on the Edit menu.
Unfortunately, QLineEdit intercepts the Ctrl-Z keystroke and does
nothing (because it's not editable).
the example you posted earlier works (i.e. Ctrl+Z prints 'action') if
the Foo widget has been set as read-only.
(nb: the setShortcutContext line also needs to be commented out)
Interesting... it works as you say on my Linux machine at home, but not
on my Windows machine at work. The Windows machine has Qt 4.6.2, I don't
know about the Linux machine off the top of my head. What platform/Qt
version are you testing on?
I updated to the latest Qt/PyQt and it's working now. My original
application is working correctly as well.
--
. . . . . . . . . . . . . . . . . . . . . . . . .
Nathan Weston ***@genarts.com
GenArts, Inc. Tel: 617-492-2888
955 Mass. Ave Fax: 617-492-2852
Cambridge, MA 02139 USA www.genarts.com
Baz Walter
2011-06-30 21:54:49 UTC
Permalink
Post by Nathan Weston
I updated to the latest Qt/PyQt and it's working now. My original
application is working correctly as well.
glad you got it working.

one final thought: rather stupidly, i completely forgot about
QEvent.ShortcutOverride, which may well be exactly what you were
originally looking for.

it could be used something like this:

def event(self, event):
if (not self._editable and
event.type() == QEvent.ShortcutOverride):
return False
return QLineEdit.event(self, event)

better late than never, i suppose :/
Yaşar Arabacı
2011-06-30 22:41:54 UTC
Permalink
Wow, I can't describe epicness of this :) Didn't know such thing existed :)
Post by Baz Walter
Post by Nathan Weston
I updated to the latest Qt/PyQt and it's working now. My original
application is working correctly as well.
glad you got it working.
one final thought: rather stupidly, i completely forgot about
QEvent.ShortcutOverride, which may well be exactly what you were originally
looking for.
if (not self._editable and
return False
return QLineEdit.event(self, event)
better late than never, i suppose :/
_______________________________________________
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
Loading...