1

I have a QMenu that in a QSystemTrayIcon. Both are members of a QMainWindow object.

I wan the QMenu of the QSystemTrayIcon to act exactly alike when right clicking (ie, reason QSystemTrayIcon::Context) and when single left clicking (ie, reason QSystemTrayIcon::Trigger).

The right clicking behavior by default acts like I want it to. However I can't figure out how to make the left click act exactly like right click. My efforts so far lead me to:

 void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
 {
     if(reason==QSystemTrayIcon::Trigger)  trayIcon->contextMenu()->popup(QCursor::pos());
 }

However, the menu doesn't disappear when it loses focus whereas bringing up the contextmenu with right click does make it disappear when focus is lost.

Is there away to make Trigger act like Context? Maybe a way to throw a mock signal or something?

moesef
  • 4,641
  • 16
  • 51
  • 68

2 Answers2

1

Well I needed to do the same thing and couldn't figure out how to do it cleanly with pure Qt code, so here's a little Windows-only hack that works:

void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason)
    {
    case QSystemTrayIcon::Trigger:
    case QSystemTrayIcon::DoubleClick:
    case QSystemTrayIcon::MiddleClick:
        {
            POINT p;
            GetCursorPos(&p);
            HWND hwnd = WindowFromPoint(p);
            ScreenToClient(hwnd, &p);
            PostMessageA(hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELONG(p.x, p.y));
            PostMessageA(hwnd, WM_RBUTTONUP, 0, MAKELONG(p.x, p.y));
        }
        break;
    case QSystemTrayIcon::Context:
        show();
        setWindowState(windowState() & ~Qt::WindowMinimized | Qt::WindowActive);
        mTrayIcon->contextMenu()->popup(QCursor::pos());
        break;
    default:
        break;
    }
}
Jedao
  • 155
  • 2
  • 3
0

So, if i understood right.

You are letting Qt handle the right button ( you don't check Context in your slot ) and then menu disappears when loses focus.

But youre handling left button clicks and you are not able to get the same behavour. Right?

I can think of, at least, two ways to do this through an eventFilter:

This would be a way to make a fake event.

bool MainWindow::eventFilter(QObject *obj, QEvent *event){
if (event->type() == QEvent::MouseButtonPress) {
  QMouseEvent *mEvent = static_cast<QMouseEvent *>(event);
  if(mEvent->button() == Qt::LeftButton)
  {
    QMouseEvent my_event = new QMouseEvent ( mEvent->type(), 
        mEvent->pos(), Qt::Rightbutton , 
    mEvent->buttons(), mEvent->modifiers() );
     QCoreApplication::postEvent ( trayIcon, my_event );
    return true;
  }
} 
return QObject::eventFilter(obj, event);
}

Install with

trayIcon->installEventFilter(this);

from Main Window

But, i think it's a bit tricky.

If you're making an eventFilter, you could watch for focusOut event on menu.

bool MainWindow::eventFilter(QObject *obj, QEvent *event){

  QMouseEvent *mEvent = dynamic_cast<QMouseEvent *>(event);
  if(mEvent)
  {
  if(mEvent->type() == QEvent::Leave || mEvent->type() == QEvent::WindowDeactivate)
  {
    trayIcon->contextMenu()->close();
    return true;
  }
} 
return QObject::eventFilter(obj, event);
}

Note that i havent tried. But should be worth a try.

Some handy links:

How to detect that my application lost focus in Qt?

installEventFilter

postEvent

Community
  • 1
  • 1
trompa
  • 1,967
  • 1
  • 18
  • 26
  • your understanding is correct. And while reading through your example, it looks like it should work, for some reason, eventFilter isn't being triggered in my code. – moesef May 08 '13 at 22:04
  • For second method install in menu – trompa May 09 '13 at 05:30
  • And prolly, also in 2nd methos, its a QEvent::MouseMove. I will change code a bit – trompa May 09 '13 at 08:34
  • I actually havent tried the second method yet. I liked the first one because it makes the left mouse click act exactly like a right click (which is what I want) without going through and assigning each behavior to the left mouse itself. I'll give the second method a go and see what happens. – moesef May 09 '13 at 17:48
  • Note that i didnt tried the code. Maybe you have to do some tweak to make it work. This was just a proof of concept – trompa May 09 '13 at 18:26
  • And, btw, it should enter in eventFilter, even if then you check the wrong event – trompa May 09 '13 at 18:34
  • yea. I'll keep working on it. thanks for the help getting started. – moesef May 09 '13 at 18:38