PDA

View Full Version : NEED HELP: QSystemTrayIcon QMenu doesn't dissapear



codeslicer
10th February 2008, 02:53
Hello,
I am making an application which will use the system tray. At first, when the application starts, a splash screen appears, then the tray icon shows without the main QWidget dialog showing. Everything is fine... until when the icon is right-clicked and the context menu shows. The problem is, the menu doesn't dissapear when it loses focus, unless the open dialog receives the focus. Here is main.cpp:


#include <QApplication>
#include <QtGui>
#include "app.h"
//
QSplashScreen *splash = 0;
//
int main(int argc, char ** argv)
{
QApplication app( argc, argv );
QPixmap pixmap(":/app/splash.png");
splash = new QSplashScreen (pixmap, Qt::X11BypassWindowManagerHint | Qt::FramelessWindowHint | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
splash->show();
splash->showMessage(QObject::tr("Loading:") + " " + QObject::tr("Setting application variables"), Qt::AlignRight | Qt::AlignTop, Qt::black);
qApp->processEvents();
splash->showMessage(QObject::tr("Loading:") + " " + QObject::tr("Checking for system tray"), Qt::AlignRight | Qt::AlignTop, Qt::black);
while(!QSystemTrayIcon::isSystemTrayAvailable()) { //Check presence of system tray
if(QMessageBox::critical(0, QObject::tr("app"), QObject::tr("Failed to add icon to the tray. Either your operating system doesn't have a system tray, or it has not been loaded yet. Currently, a system tray is required to run this program. Would you like to retry?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
return 1;
}
}
qApp->processEvents();
splash->showMessage(QObject::tr("Loading:") + " " + QObject::tr("Preloading main window"), Qt::AlignRight | Qt::AlignTop, Qt::black);
app win;
win.show();
qApp->processEvents();
splash->close();
delete splash;
return app.exec();
}

Here is app.cpp:


#include <QtCore>
#include <QtGui>
#include "app.h"
//
app::app(QWidget * parent, Qt::WFlags f)
: QWidget(parent, f)
{
setupUi(this);
createActions();
createTrayIcon();
trayIcon->show();
connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason )), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReas on)));
}

void app::showMessage(const QString & title, const QString & message, QSystemTrayIcon::MessageIcon icon, int millisecondsTimeoutHint) {
if(QSystemTrayIcon::supportsMessages()) { //Use the bubble only if the system supports it
trayIcon->showMessage(title, message, icon, millisecondsTimeoutHint);
} //This function is a failsafe of the default systray showMessage();
else {
QMessageBox::information(this, title, message); //Otherwise, use a good old message box
}
}
void app::closeEvent(QCloseEvent *event) { //Prevent the user from entirely exiting the program when he just closes the dialog
QSettings TMIP(this);
event->ignore();
}

void app::setDialogVisible() {
isVisible()?hide():show(); //Quick way of showing/hiding dialog
}

void app::iconActivated(QSystemTrayIcon::ActivationReas on reason) {
switch (reason) {
case QSystemTrayIcon::Trigger: {
setDialogVisible();
break;
}
case QSystemTrayIcon::DoubleClick:{
break;
}
case QSystemTrayIcon::MiddleClick: {
break;
}
default: {
;
}
}
}

void app::createTrayIcon() {
trayIconMenu = new QMenu(this);
trayIconMenu->addAction(showDialogAction);
trayIconMenu->addAction(maximizeAction);
trayIconMenu->addAction(restoreAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
trayIcon = new QSystemTrayIcon(this);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->setIcon(QIcon(":app/app.png"));
}

void app::createActions() { //Create the tray icon's context menu
showDialogAction = new QAction(tr("Show/hide window..."), this);
connect(showDialogAction, SIGNAL(triggered()), this, SLOT(setDialogVisible()));
maximizeAction = new QAction(tr("Ma&ximize"), this);
connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
restoreAction = new QAction(tr("&Restore"), this);
connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
quitAction = new QAction(tr("&Quit"), this);
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

Finally, here is app.h:


#ifndef APP_H
#define APP_H
//
#include "ui_app.h"
#include <QSystemTrayIcon>
#include <QWidget>
//
class QSettings;
class QAction;
class QMenu;
class app : public QWidget, public Ui::app
{
Q_OBJECT
public:
app( QWidget * parent = 0, Qt::WFlags f = 0 );
void showMessage(const QString & title, const QString & message, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int millisecondsTimeoutHint = 10000);
protected:
void closeEvent(QCloseEvent *event);
private slots:
void setDialogVisible();
void iconActivated(QSystemTrayIcon::ActivationReason reason);
private:
void createTrayIcon();
void createActions();

QAction *showDialogAction;
QAction *maximizeAction;
QAction *restoreAction;
QAction *quitAction;

QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
};
#endif


I am using Ubuntu 7.10 with Qt 4.3.3. I based this off the trayicon example in the Qt Docs. The Qt example, when compiled, works perfectly as it should. On the Windows platform, the context menu also works as it should.

If I could get any help, I would be really grateful. So thanks in advance :) ~codeslicer

marcel
10th February 2008, 03:03
Does this happen on all platforms?

BTW, using labels and goto's is considered bad practice/coding/design. You can easily do that with a boolean function and a while loop.

codeslicer
10th February 2008, 03:14
Oh right, I forgot.

I am using Ubuntu 7.10 with Qt 4.3.3. I based this off the trayicon example in the Qt Docs. The Qt example, when compiled, works perfectly as it should. On the Windows platform, the context menu also works as it should.

I'll replace the goto stuff with a while() loop, but why is goto bad?

marcel
10th February 2008, 03:23
A label is where a "goto" goes. In your example, retryTrayIcon is a label.
They are bad because they make the code unreadable, are very likely to cause errors and also make the code harder to maintain.

The only difference between your app and the Qt Systray example is that you start up with your application hidden. Try, just for testing, to show it, in main.cpp. See if you're experiencing the same behavior.

codeslicer
10th February 2008, 03:57
Hmm, weird. In my original source code, adding or subtracting the win.show() didn't make a difference. But I made a seperate project removing extra commands and it worked. I'll look around, and if I can't find it, I'll upload a zipped copy of my source code. Thanks though :confused:

codeslicer
10th February 2008, 04:17
I got it! It was QDevelop's fault. Apparently, when I ran the executable by using the debug button, the menu wouldn't lose focus. However, when I opened that binary, everything worked!!!

This is truly strange ;) Is it because QDevelop or the debugger is changing the ownership of the menu?