1
votes

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?

2

2 Answers

1
votes

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;
    }
}
0
votes

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