QAction shortcut doesnt always work - c++

I have a Qaction on a menu item for deleting selected items in one of my views. Here is how i create the action:
deleteAct = new QAction( tr("Delete Selected"), this);
deleteAct->setShortcut(QKeySequence::Delete);
connect(deleteAct, SIGNAL(triggered()), this, SLOT(deleteSelected()));
I setup a keyboard shortcut (Delete Key) which should trigger the delectAct action. It works most of the time but at some points it stops working... Does anyone know why the shortcut would stop working?
Note: the action still works if i trigger it from the menu item. Its just the shortcut that doesn't...

You need to add the action to a widget, since it's the widget that will be listening for key events.
Assuming "this" is a mainwindow, simply do
addAction(deleteAct);
Note that you can add the same action to multiple widgets (that's the whole point of the separated action concept). So it's fine to add it to the mainwindow and to a menu.

Try changing the shortcut context of the action, for example:
deleteAct->setShortcutContext(Qt::ApplicationShortcut);

The shortcut works depending on the focus of the application views.
I wanted to have shortcuts working on buttons.
In my application I changed the shortcut context of the action,
added the action to the widget
and finally to the subviews of the application.
Then the necessary signals and slots of widget an action must be connected.
const QAbstractButton*button = dynamic_cast<QAbstractButton*>(widget);
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
widget->addAction(action);
ui->textBrowser->addAction(action);
ui->treeSource->addAction(action);
if (button)
{
if (button->isCheckable())
{
action->setCheckable(true);
if (button->isChecked()) action->setChecked(true);
connect(action, SIGNAL(triggered(bool)), button, SLOT(setChecked(bool)));
connect(button, SIGNAL(clicked(bool)), action, SLOT(setChecked(bool)));
}
else
{
connect(action, SIGNAL(triggered()), button, SLOT(click()));
}
}

Without seeing the complete code, I'd hazard a guess that somewhere it gets enabled/disabled. Make sure that the shortcut is getting hit in the constructor and not 'disabled' somewhere else because of a setting perhaps.

You can use http://doc.qt.io/qt-5/qaction.html#shortcutVisibleInContextMenu-prop property since QT 5.10 for this:
deleteAct->setShortcutVisibleInContextMenu(true);

Related

Two or more shortcuts for one push button

I need to have several shortcuts for one push button. For example Ctrl+W and Enter and Return (Enter and Return are different in Qt), any of them would cause a click on the button. How to do this? If the button was QAction, I would call setShortcuts() ( See Two shortcuts for one action which is NOT a duplicate. It is different, relates to QAction not QPushButton. ) but QPushButton has only setShortcut() (singular), which seems to not allow this. What solution or hack wold you suggest?
OK, I have got a solution which is not that hacky. I can create a QPushButton and a QAction, then set multiple shortcuts for QAction using QAction::setShortcuts() and connect this action to QPushButton::animateClick(). At first this solution did not work because I called connect(action, &QAction::triggered, button, &QPushButton::animateClick);. The problem was with invisible default arguments. QAction::triggered sends true/false indicating whether the action is checked. But QPushButton::animatedClick expects number of milliseconds to remain visually 'pressed'. Therefore it remained 'pressed' only for 0 or 1 millisecond, which is not enough to notice it (the default value of the argument is 100 milliseconds). This can be solved using lambda, hence:
// 'this' refers to a parent widget
auto action = new QAction(this);
action->setShortcuts({ tr("Ctrl+W"), tr("Return"), tr("Enter") });
this->addAction(action);
auto button = new QPushButton(tr("Hey, click me!"));
connect(action, &QAction::triggered, [button](){ button->animateClick(); });
And that's it.

Change the Cut, Copy, Paste shortcut to the custom slots in Qt 5

Currently, I am working on an editor program. I want to assign three shortcut keys (QKeySequence::Cut), (QKeySequence::Copy) and (QKeySequence::Paste) to my customized functions. However, it does not work as my expectation.
For testing, I open the "Application Example" from QtCreator. Then, I try to disable all the shortcut keys as following:
//cutAct->setShortcuts(QKeySequence::Cut);
connect(cutAct, SIGNAL(triggered()), textEdit, SLOT(cut()));
copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this);
//copyAct->setShortcuts(QKeySequence::Copy);
connect(copyAct, SIGNAL(triggered()), textEdit, SLOT(copy()));
pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this);
//pasteAct->setShortcuts(QKeySequence::Paste);
Surprisingly, the shortcut keys still working as before.
Another test is that:
connect all the actions to customized slots.
assign all the key sequences to the actions which have already connected to my customized slots.
Then, my result is
Click Cut, Copy, Paste on toolbar go to my customized slots.
The shortcut key works independently with my customized slots.
Any advice are welcome.
Thank you very much.
I have found the way to override the default shortcut, thanks to the code of Sigil.
I use the following code:
Delacre a new action in header:
QShortcut &m_Paste1;
Then, in the constructor of class:
m_Paste1(*(new QShortcut(QKeySequence(QKeySequence::Paste), this, 0, 0, Qt::WidgetShortcut))),
Finally, connect it to your own slot
connect(&m_Paste1, SIGNAL(activated()), this, SLOT(paste()));

How to disable minimizing by taskbar icon click

I've stumbled across very strange behaviour during work on my program.
I've written custom changeEvent class, which allows me to hide program to SysTray on minimizing.
But when i double click on taskbar app icon, the function goes crazy. It creates 2 to 4 systray icons and on requesting window show again, it just shows main window borders without any content inside.
Here's my changeEvent code:
void MainWindow::changeEvent(QEvent *e) {
QMainWindow::changeEvent(e);
if(e->type()==QEvent::WindowStateChange)
if(isMinimized()) {
trayIcon=new QSystemTrayIcon(QIcon(":/icon/itime.ico"));
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_show(QSystemTrayIcon::ActivationReason)));
QAction *showAction=new QAction("Pokaż",trayIcon);
connect(showAction,SIGNAL(triggered()),this,SLOT(on_show()));
QMenu *trayIconMenu=new QMenu;
trayIconMenu->addAction(showAction);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->show();
this->hide();
}
}
on_show(QSystemTrayIcon::ActivatioReason) SLOT:
void MainWindow::on_show(QSystemTrayIcon::ActivationReason reason) {
if(reason) {
if(reason!=QSystemTrayIcon::DoubleClick)
return;
}
if(this->isMinimized()) {
this->raise();
this->showNormal();
this->setWindowState(Qt::WindowActive);
trayIcon->hide();
}
}
on_show() SLOT is just the same besides that first if.
Soo, I would like to know whether there is any way to disable minimizing of window by taskbar icon click.
If there's none, then maybe you have any ideas what can go wrong in here when doubleclicking on icon in taskbar?
Thanks for help!
I've managed to work around that problem by overloading closeEvent function and leaving alone changeEvent function.
So, I'm using boolean flag to distinct between closing of program by menu item and by clicking "X" button and the rest stays just the same, as posted in my earlier post with one change.
I've moved this whole block of code to window constructor in order to prevent multiple creation of trayIcon, as pointed out by Nicolas.
trayIcon=new QSystemTrayIcon(QIcon(":/icon/itime.ico"));
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(on_show(QSystemTrayIcon::ActivationReason)));
QAction *showAction=new QAction("Pokaż",trayIcon);
connect(showAction,SIGNAL(triggered()),this,SLOT(on_show()));
QMenu *trayIconMenu=new QMenu;
trayIconMenu->addAction(showAction);
trayIcon->setContextMenu(trayIconMenu);
Thanks for your help!

How do I assign a shortcut to a QPushButton?

The documentation on assigning a shortcut to a QPushButton is as follows:
A shortcut key can be specified by preceding the preferred character with an ampersand in the text. For example:
QPushButton *button = new QPushButton("&Download", this);
In this example the shortcut is Alt+D.
What do I do if I don't want an Alt+[A-Z] shortcut? For example, in my case I want my button to be fired when the TAB button is pressed. How can I achieve this effect?
You can use setShortcut method, eg:
pushButton->setShortcut(QKeySequence(Qt::Key_Tab));
It will fire then slots assigned to the clicked() signal
You can use a QShortcut. Another tip: Qt signal / slots mechanism allows you to connect a signal to a signal.
You can overload QWidget::keyPressEvent and trigger your button click directly or through previously specially connected signal
void MainWindow::keyPressEvent(QKeyEvent * pEvent)
{
if (Qt::Key_Tab == pEvent->key())
{
ui->button->click();
}
QMainWindow::keyPressEvent(pEvent);
}
You can define the key, the target object and it's relevant slot in the constructor of QShortcut :
QShortcut * shortcut = new QShortcut(QKeySequence(Qt::Key_Tab),button,SLOT(click()));
shortcut->setAutoRepeat(false);

How do I properly set up generic QT actions for a menu constructed at run time?

I am populating a sytem tray icon menu (QMenu) from entries in an xml file which is read when my application starts up.
I am unsure of how to properly set up the SLOT end of the action:
QList<CMenuItem> menuItems = m_layout->getMenuItems();
QListIterator<CMenuItem> iter(menuItems);
while (iter.hasNext())
{
CMenuItem menuItem = iter.next();
QAction *action = new QAction(menuItem.qsTitle, this);
connect(action, SIGNAL(triggered()), this, SLOT(launchMenuItem()));
trayIconMenu->addAction(action);
}
How does my "launchMenuItem()" SLOT know which menu item was triggered? I can't make a SLOT for each menu item as I don't know how many items will exist until run time.
I can think of some ugly ways to do this, but I am looking for the RIGHT way.
What I usually do is to use QAction::setData(const QVariant&) to store whatever action ID I need. Then on slot side I retrieve ID with QAction::data() and behave accordingly.
Note that QVariant obviously accepts much more than basic int (which is what I use to identify actions), you can pass any QVariant-compatible info.
edit : oh! btw, this is somehow ugly because I make use of QObject::sender() to cast triggered action back. Sorry for that, but it works anyway.