I want to write a function that will work with keybinding for the application I am developing on the Qt platform, but I could not find any example that will work for me, like the picture I added from the discord application, can you help me?
Discord keybinding
You question is slightly fuzzy, there are a few aspects associated with key bindings.
At the start of the application, you can assign default shortcut keys to actions and menus, see the documentation on QAction, QShortcut, QMenu.
If you need a dialog which allows changing a key binding, you can easily create a dialog yourself. See the documentation on QKeySequenceEdit which helps you entering a new shortcut key sequence for an action.
Last but not least, you need to bind your modified key sequences to your actions. You can do this by deriving a class from QAction. Find these actions by searching all objects with mainWindow->findChildren<YourActionClass*>()
and modify the keyboard shortcut with the results from your dialog.
This derived class could also store the default binding, the icon (your users might like to modify icons perhaps) etc.
All this is quite straight forward.
If you want user to hit a key combination for a selection then just create a class inheriting QLinEdit (even QLabel would work) and override keyPressEvent,
void QLineEdit::keyPressEvent(QKeyEvent *event);
and then use QKeyEvents function to get key and modifiers (shift, ctrl etc.). Just read the Qt Docs about it. Depending on the key and modifiers, write the modifier name + key's text (e.g. Ctrl + N).
To hold actions (QAction), just use std::map<QString,QAction*> or QMap<QString,QAction*> and register/add your QAction objects in the map and assuming your class' name is MyClass and it has getKeyString() , to return key combination as QString, then you will just do,
QString str = MyClassObj.getKeyString();
QKeySequence ks(str);
actionMap.at("NewFile")->setShortcut(ks);
Related
In order to create a QComboBox that can filter its values list when typing in it, I attached a slot to the QComboBox's editTextChanged-event, to open its list view popup when the user starts typing. This is done like so:
void SearchableComboBox::slotEditing(QString in_text)
{
this->showPopup();
}
Unfortunately, this immediatly steals the focus from the QLineEdit and I can't type anymore.
Calling lineEdit()->setFocus() makes no difference, and I don't want to grabKeyboard() since this creates a whole other world of pain.
Any recommendations?
This isn't really a combobox then, more of a completion listview for a lineedit. I implemented exactly that in ruqola (KDE client for rocket chat), you can see the source code at https://lxr.kde.org/source/network/ruqola/src/widgets/common/completionlistview.cpp. Notice the little dance with the focus proxy thing:
setFocusPolicy(Qt::NoFocus);
textWidget->setFocusPolicy(origPolicy);
setFocusProxy(textWidget);
and the long method slotCompletionAvailable() for positioning the completion popup at the right place...
Use the Focus Proxy method for this purpose. See https://doc.qt.io/qt-5/qwidget.html#setFocusProxy
With this the pop-up would relay its inputs to the lineedit.
In your case you could try something like
this->setFocusProxy( this->lineEdit() );
But maybe you should read how to use a QCompleter. This would provide Autocompletion while typing and is maybe also useful for you.
I'm coding a simple text editor with only few basic features.
At the moment it has a QMainWindow with QTabWidget set as it's centralWidget.
What I'm implementing now are some shortcuts; ctrl+s to save, ctrl+o to open, and ctrl+t/ctrl+w to create a new tab/close the current tab.
I know how to implement all the features, but the question is where to implement the features?
Should all the shortcuts be members of QMainWindow and let it take care of everything, or should I try separating the shortcuts into their correspoding classes?
For example, creating a new tab (ctrl+t) would be part of QTabWidget.
Now what about ctrl+s (save, duh), should it be part of QTextEdit since it's the text I'm saving, or..?
Basically my program contains three classes; QMainWindow, which contains QTabWidget, and each tab is a QTextEdit.
Your setup sounds a lot like many of the applications I've built.
I generally handle shortcuts via the QAction::setShortcut() method, so it's really more about where does it make sense to store the QAction objects. This usually ends up being my MainWindow class as a lot of the actions are all used in the MainWindw's menus. When these actions are triggered, the result is usually that the TabWidget is notified which in turn notifies all the necessary tabs and can handle things like a "Close All" action triggering only one save prompt.
However, if it doesn't make sense to store those QActions on the MainWindow object, then I don't, as in the case of the context menu I usually have available on my individual tabs.
Hope that helps.
What is the difference about them?
In Qt, if I have a hotkey for QPushButton, I can make it by "Alt + ?", but if it's for qaction, I can press "?" only
In Windows, an accelerator key is application global; e.g. Alt+F4.
A shortcut key is part of the name of a menu item or button, where it can be underlined, and is available (without modifiers) when that menu item or button is directly available.
From Microsoft:
A hot key is a key combination that the user can press to perform an action quickly. For example, a user can create a hot key that activates a given window and brings it to the top of the z-order.
which seems to indicate that hot keys are system global.
To sum up:
shortcut key = no modifiers, local in menu or (for button) in window
accelerator key = typically with modifier, application global
hot key = apparently system global
I don't know about specific meanings in Qt; for that see the Qt documentation.
Alf's answer is correct for Windows applicability. Your terms you mention (hotkey/shortcut/accelerator) don't sound familiar from a pure Qt point of view.
In Qt you can elect to handle key sequences yourself or you can use Qt's own simplification method. Either way you must remember that Qt itself targets many platforms on which a key combination may or may not make sense. The classic Alt + F4 makes sense on a keyboard, but on a mobile device you don't have an Alt modifier or an F4 key. What you really want is a way of specifying a generic close the application shortcut. This problem is multiplied because the symbol may be available but the key sequence to reach it might be different on other keyboard layouts. This section of the documentation provides a good example.
Qt handles this with class QKeySequence. The very clever Qt developers have provided an easy way of defining common user actions and those actions will use key combinations that are default to the target platform. It does this using enum QKeySequence::StandardKey and in the close the application example, you could use this like so:
QAction exitAction;
exitAction.setShortcut(QKeySequence(QKeySequence::Quit));
This is all explained in the documentation. There are a two other modifiers (shortcutContext() and softKeyRole()) which can be applied to QActions which effect their application in more advanced ways.
You are also free to assign your own shortcuts using something like:
QAction helpAction(tr("&?"));
helpAction.setShortcut(QKeySequence(tr("ALT+?")));
The first line applies the (translated) text "?" to the action which will appear as its text on a menu or button. Note that the question mark symbol might not be the right symbol in all languages so the translate method allows a translator to assign a more appropriate symbol if required. The ampersand symbol means the character immediately after will be the short-cut key when the menu is active.
The second line assigns the (translated) shortcut of Alt + ? and in this example the Shift modifier will be handled by the platform if required. Again, the tr() method allows the translator to specify a more appropriate shortcut if available.
In response to teukkam's comment:
If you mean you simply want your button to be triggerable by a keystroke whether its modified by Alt or not then you could do something like:
QPushButton* yourButton; // assign this pointer yourself
yourButton->setText(tr("&Process"));
yourButton->setShortcut(tr("p"));
In this example, the ampersand in setText() does the same as the previous example, and the translate function is used in the same way.
The setShortcut() method just uses the letter "p" so should work now with or without the Alt modifier. A quick skim of the documentation suggests this will work with or without the Shift modifier as the letters in a key sequence are apparently case-insensitive.
Also, P would be a bad choice as its often assumed to be the print command.
A final note if you're defining hard coded short cuts, make sure they work on all your target platforms!
In Windows:
HotKey
Keyboard key or combination of keys that execute a command in a given context.
Shortcut
Multi-key HotKey with no menu navigation restrictions nor gui elements required.
AccessKey
Single key HotKey which command is to activate a visible command control
(requires gui element) that is captioned/labeled with the corresponding hotkey letter underscored.
Accelerator Keys
Multi-key HotKey which command is to activate a command control (requires gui element) regardless of its visibility.
So I have an action I want to expose in multiple menus (one of the main menus, and some context menus). I'd like the menu item text to differ slightly from menu to menu (to make the mnemonic unique, and to be more or less verbose as necessary in each context).
In MFC (which I have the pleasure of migrating away from at the moment) this was easy, as each menu's items were defined separately, and could map to the same ID, which would be linked to the handler. In Qt though, the QAction encapsulates the behaviour as well as the text/icon/etc. So I don't suppose there's straightforward support for it to return a different text dependent on where it's being used.
My thought about how to handle this is, for each location, to create a "proxy" QAction, which has the text specific to that context and simply has its triggered() signal connected to the original QAction's one. But I thought I should check first about whether there's an easier way to approach this.
I don't know about MFC, but in Qt - QAction is just an interface. One QAction object can have only one text to display. But the real action QAction does, you will implement in what Qt calls SLOT. Then you can have as much interfaces(or QActions objects) pointing to the same slot - just connect all QAction objects, that you want to do the same thing, to the same slot.
Hope this helps.
Your suggested solution is the simplest, I think. You can change the text of an action dynamically, when a menu is activated, but this looks more complicated to me.
I am attempting to re-implement the Copy behavior for a QTextEdit object. The custom context menu I create works as expected when the 'Copy' button is clicked, but Ctrl + C isn't being handled correctly. Since the context menu doesn't have any issues, I'll omit that portion of the code.
// Create a text edit box for text editing
QTextEdit text_edit_box = new QTextEdit(getBaseWidget());
text_edit_copy_action = new QAction(QString("Copy"), getBaseWidget());
text_edit_copy_action->setShortcut(QKeySequence::Copy);
// Add custom copy action to the text edit box to ensure Ctrl+C uses our copy
// implementation
text_edit_box->addAction(text_edit_copy_action);
When I set the shortcut to be an unused key combination (e.g., Ctrl + Q) it works fine. It seems Ctrl + C is being handled differently since it's "built in".
Copy is not virtual so this might be problematic. Copying is handled via the private text control API, and is not easily accessible. The best approach is probably to install an event handler for the text edit and intercept the copy key event before it's delivered to the text control processEvent handler - which should allow your own action to correctly trigger.
It might be simpler to derive from QTextEdit and reimplement QTextEdit::copy(), depending on what the new behaviour is.
I would recommend creating an event filter and installing that on the base widget (or even the QApplication instance). You can use the event filter to look at key events and hopefully see the Ctrl+C event prior to it being handled elsewhere.
When you encounter the Ctrl + C event that you want to handle, make sure to accept that event to prevent it from being propogated any further.