QSystemTrayIcon activated signal: DoubleClick without Trigger - c++

I want to show context menu on left click and run app on double click.
For this i have next code:
...
connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(slotActivated(QSystemTrayIcon::ActivationReason)));
...
void MyTray::slotActivated(ActivationReason reason)
{
if(reason==QSystemTrayIcon::DoubleClick)
startApp();
else
if(reason==QSystemTrayIcon::Trigger
|| reason==QSystemTrayIcon::MiddleClick)
contextMenu()->popup(QCursor::pos());
}
It works, but for double click case i got two slot calls - one for Trigger and only then for DoubleClick. As result context menu shown and hidding in a moment.
Is there is a way to avoid this?

Rather than using slotActivated, you need to handle the mouse events.
Whilst these aren't directly available in QSystemTrayIcon, it does allow you to install an event filter and handle the mouse events from there.

Related

Call button click function from grandchild

I'm creating my first C++ wxWidgets application. I'm trying to create some kind of split button where the options are displayed in a grid. I have a custom button class which, when right-clicked on, opens a custom wxPopupTransientWindow that contains other buttons.
When I click on the buttons in the popup, I want to simulate a left click on the main button. I'm trying to achieve this through events, but I'm kinda confused.
void expandButton::mouseReleased(wxMouseEvent& evt)
{
if (pressed) {
pressed = false;
paintNow();
wxWindow* mBtn = this->GetGrandParent();
mBtn->SetLabel(this->GetLabel());
mBtn->Refresh();
wxCommandEvent event(wxEVT_BUTTON);
event.SetId(GetId());
event.SetEventObject(mBtn);
mBtn-> //make it process the event somehow?
wxPopupTransientWindow* popup = wxDynamicCast(this->GetParent(), wxPopupTransientWindow);
popup->Dismiss();
}
}
What is the best way to do this?
You should do mBtn->ProcessWindowEvent() which is a shorter synonym for mBtn->GetEventHandler()->ProcessEvent() already mentioned in the comments.
Note that, generally speaking, you're not supposed to create wxEVT_BUTTON events from your own code. In this particular case and with current (and all past) version(s) of wxWidgets it will work, but a cleaner, and guaranteed to also work with the future versions, solution would be define your own custom event and generate it instead.

Qt event when widget goes out of sight

Is there a way in Qt to handle situation when any widget of Window goes out of sight. I.e if a widget was in tab control and user have changed active tab, or if user just scrolls and widget goes offscreen, and also when it goes back on screen.
Is that possible to add some code to this two events?
Best if this can be done globally...
Is there a way in Qt to handle situation when any widget of Window goes out of sight. I.e if a widget was in tab control and user have changed active tab, or if user just scrolls and widget goes offscreen, and also when it goes back on screen.
The way the question asked makes one think that the widget show-hide-expose state changes need to be handled:
bool MyWidget::event(QEvent* pEvent)
{
if (pEvent->type() == QEvent::Show)
{
// event "shown"
}
else if (pEvent->type() == QEvent::Hide)
{
// event "hidden"
}
else if (pEvent->type() == QEvent::Expose)
{
// event "exposure changed"
// deal with QExposeEvent and evaluate the exposed region
// QExposeEvent* pExposeEvent = reinterpret_cast<QExposeEvent*>(pEvent);
}
return QWidget::event(pEvent);
}
Best if this can be done globally...
Event filter at the top level widget may solve that. Or you can override event() function for the top level widget but finding what exact widget was affected is another thing.
Refer to QExposeEvent description.

Qt menu bar events

I've added menus and menu items in Qt creator using the "Design" option. I then rt-clicked the associated action below and clicked on "Go to slot". This takes me to the code that will be executed when I click on that menu item. Perfect - almost. I'd like to distinguish between clicking and shift-clicking on the menu item. It looks like I can determine whether the event was modified with the shift button by doing something like this:
if (event->modifiers() & Qt::ShiftModifier) {
...
}
The problem is that no event is passed in for a menu click action.
Can I do what I'm trying to do somehow? Do I need to figure out how to pass an event in - or is there some other way to test that the shift key is pressed?
Thanks!
In the slot which is being called you can use QGuiApplication::keyboardModifiers() to get the current keyboard modifiers:
void MainWindow::on_action_triggered() {
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) {
// Shift key is down.
}
}

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.

QAction shortcut doesnt always work

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);