QSystemTrayIcon hide() crash on mac while I use QTimer to change the icon of QSystemTrayIcon
-
I want the systemTrayIcon to change the icon every 500ms , so I use QTimer and in timeout() signal's slot function , I change the icon of
systemTrayIcon like this@
void MainWidget::flashing()
{
fIndex++;
if(fIndex == fMaxFlashingNumber){ //fMaxFlashingNumber is 20
fSystemTrayTimer->stop(); //fSystemTrayTimer is QTimer
fSystemTrayIcon->setIcon(fIcon); //fIcon is defined before
}else {
if(fIndex %2 ==0){
fSystemTrayIcon->setIcon(fIcon);
}else {
fSystemTrayIcon->setIcon(QIcon("images/butterfly.png"));
}
}
}
@when the systemTrayIcon is triggered , I want to hide the systemTrayIcon , I call
@
fSystemTrayTimer->stop() ;
fSystemTrayIcon->hide();
@it will crash on mac , it works well on windows , I don't know why . If I don't use QTimer , it won't crash .
and also another problem , when I call@fSystemTrayIcon->setIcon(QIcon()); @
to set the icon empty , it will
showing nothing on windows, while it still show the original icon on mac , why it can't work , strange problem .[EDIT: code formatting, Volker]
-
here is the crash information:
Interval Since Last Report: 7802367 sec
Crashes Since Last Report: 83
Per-App Interval Since Last Report: 944 sec
Per-App Crashes Since Last Report: 16
Anonymous UUID: A2CE6324-1143-4A63-9F98-BB0933D1C757Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x000000000000002b
Crashed Thread: 0 Dispatch queue: com.apple.main-threadApplication Specific Information:
objc_msgSend() selector name: itemThread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x99596ed7 objc_msgSend + 23
1 QtGui 0x00b86f16 -[QNSImageView mousePressed:button:] + 198
2 QtGui 0x00b86531 -[QNSImageView mouseDown:] + 49
3 com.apple.AppKit 0x92936c68 -[NSWindow sendEvent:] + 5549
4 com.apple.AppKit 0x92d74169 -[NSStatusBarWindow sendEvent:] + 82
5 com.apple.AppKit 0x92eaa0ca carbonAppWindowMouseHandler + 261
6 com.apple.AppKit 0x92eab4a0 carbonAppWindowHandler + 131
7 com.apple.HIToolbox 0x9727ac2f DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1567
8 com.apple.HIToolbox 0x97279ef6 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 411
9 com.apple.HIToolbox 0x9729c7f3 SendEventToEventTarget + 52
10 com.apple.HIToolbox 0x972ae34f ToolboxEventDispatcherHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) + 1257
11 com.apple.HIToolbox 0x9727b080 DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 2672
12 com.apple.HIToolbox 0x97279ef6 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 411
13 com.apple.HIToolbox 0x9729c7f3 SendEventToEventTarget + 52
14 QtGui 0x00b3c854 QEventDispatcherMac::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 596
15 QtCore 0x009092a1 QEventLoop::processEvents(QFlagsQEventLoop::ProcessEventsFlag) + 65
16 QtCore 0x009094dd QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) + 189
17 QtCore 0x0090b80e QCoreApplication::exec() + 174
18 com.yourcompany.demo 0x00005149 main + 75 (main.cpp:7)
19 com.yourcompany.demo 0x00004b19 _start + 208
20 com.yourcompany.demo 0x00004a48 start + 40 -
this is also tested in qtdemo's systray example , see the code I modified with timer
window.h**
****************************************************************************/
@
#ifndef WINDOW_H
#define WINDOW_H#include <QSystemTrayIcon>
#include <QDialog>QT_BEGIN_NAMESPACE
class QAction;
class QCheckBox;
class QComboBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QMenu;
class QPushButton;
class QSpinBox;
class QTextEdit;
QT_END_NAMESPACE//! [0]
class Window : public QDialog
{
Q_OBJECTpublic:
Window();void setVisible(bool visible);
protected:
void closeEvent(QCloseEvent *event);private slots:
void setIcon(int index);
void iconActivated(QSystemTrayIcon::ActivationReason reason);
void showMessage();
void messageClicked();void startFlashing();
void stopFlashing();
protected:
virtual void timerEvent(QTimerEvent *ev);private:
int fTimerID;
int fIndex;
private:
void createIconGroupBox();
void createMessageGroupBox();
void createActions();
void createTrayIcon();QGroupBox *iconGroupBox; QLabel *iconLabel; QComboBox *iconComboBox; QCheckBox *showIconCheckBox; QGroupBox *messageGroupBox; QLabel *typeLabel; QLabel *durationLabel; QLabel *durationWarningLabel; QLabel *titleLabel; QLabel *bodyLabel; QComboBox *typeComboBox; QSpinBox *durationSpinBox; QLineEdit *titleEdit; QTextEdit *bodyEdit; QPushButton *showMessageButton; QAction *minimizeAction; QAction *maximizeAction; QAction *restoreAction; QAction *quitAction; QSystemTrayIcon *trayIcon; QMenu *trayIconMenu;
};
//! [0]#endif
@ -
window.cpp
**
****************************************************************************/
@
#include <QtGui>#include "window.h"
//! [0]
Window::Window()
{
createIconGroupBox();
createMessageGroupBox();iconLabel->setMinimumWidth(durationLabel->sizeHint().width()); createActions(); createTrayIcon(); connect(showMessageButton, SIGNAL(clicked()), this, SLOT(showMessage())); connect(showIconCheckBox, SIGNAL(toggled(bool)), trayIcon, SLOT(setVisible(bool))); connect(iconComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setIcon(int))); connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(iconGroupBox); mainLayout->addWidget(messageGroupBox); setLayout(mainLayout); iconComboBox->setCurrentIndex(1); trayIcon->show(); setWindowTitle(tr("Systray")); resize(400, 300);
}
//! [0]//! [1]
void Window::setVisible(bool visible)
{
minimizeAction->setEnabled(visible);
maximizeAction->setEnabled(!isMaximized());
restoreAction->setEnabled(isMaximized() || !visible);
QDialog::setVisible(visible);
}
//! [1]//! [2]
void Window::closeEvent(QCloseEvent *event)
{
if (trayIcon->isVisible()) {
QMessageBox::information(this, tr("Systray"),
tr("The program will keep running in the "
"system tray. To terminate the program, "
"choose <b>Quit</b> in the context menu "
"of the system tray entry."));
hide();
event->ignore();
}
}
//! [2]void Window::startFlashing()
{
trayIcon->show();
fTimerID = startTimer(500);}
void Window::stopFlashing()
{
killTimer(fTimerID);
trayIcon->hide();
}
void Window::timerEvent(QTimerEvent *ev)
{
fIndex++;
if(fIndex%2 ==0){
trayIcon->setIcon(iconComboBox->itemIcon(0));
}else
trayIcon->setIcon(iconComboBox->itemIcon(1));
}//! [3]
void Window::setIcon(int index)
{
QIcon icon = iconComboBox->itemIcon(index);
trayIcon->setIcon(icon);
setWindowIcon(icon);trayIcon->setToolTip(iconComboBox->itemText(index));
}
//! [3]//! [4]
void Window::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
switch (reason) {
case QSystemTrayIcon::Trigger:
stopFlashing();
break;
case QSystemTrayIcon::DoubleClick:
iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1)
% iconComboBox->count());
break;
case QSystemTrayIcon::MiddleClick:
showMessage();
break;
default:
;
}
}
//! [4]//! [5]
void Window::showMessage()
{
QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon(
typeComboBox->itemData(typeComboBox->currentIndex()).toInt());
trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon,
durationSpinBox->value() * 1000);
//trayIcon->hide();
startFlashing();
}
//! [5]@
-
//! [6]
@
void Window::messageClicked()
{
QMessageBox::information(0, tr("Systray"),
tr("Sorry, I already gave what help I could.n"
"Maybe you should try asking a human?"));
}
//! [6]void Window::createIconGroupBox()
{
iconGroupBox = new QGroupBox(tr("Tray Icon"));iconLabel = new QLabel("Icon:"); iconComboBox = new QComboBox; iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad")); iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart")); iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash")); showIconCheckBox = new QCheckBox(tr("Show icon")); showIconCheckBox->setChecked(true); QHBoxLayout *iconLayout = new QHBoxLayout; iconLayout->addWidget(iconLabel); iconLayout->addWidget(iconComboBox); iconLayout->addStretch(); iconLayout->addWidget(showIconCheckBox); iconGroupBox->setLayout(iconLayout);
}
void Window::createMessageGroupBox()
{
messageGroupBox = new QGroupBox(tr("Balloon Message"));typeLabel = new QLabel(tr("Type:")); typeComboBox = new QComboBox; typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxInformation), tr("Information"), QSystemTrayIcon::Information); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxWarning), tr("Warning"), QSystemTrayIcon::Warning); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxCritical), tr("Critical"), QSystemTrayIcon::Critical); typeComboBox->setCurrentIndex(1); durationLabel = new QLabel(tr("Duration:")); durationSpinBox = new QSpinBox; durationSpinBox->setRange(5, 60); durationSpinBox->setSuffix(" s"); durationSpinBox->setValue(15); durationWarningLabel = new QLabel(tr("(some systems might ignore this " "hint)")); durationWarningLabel->setIndent(10); titleLabel = new QLabel(tr("Title:")); titleEdit = new QLineEdit(tr("Cannot connect to network")); bodyLabel = new QLabel(tr("Body:")); bodyEdit = new QTextEdit; bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a " "clue.nClick this balloon for details.")); showMessageButton = new QPushButton(tr("Show Message")); showMessageButton->setDefault(true); QGridLayout *messageLayout = new QGridLayout; messageLayout->addWidget(typeLabel, 0, 0); messageLayout->addWidget(typeComboBox, 0, 1, 1, 2); messageLayout->addWidget(durationLabel, 1, 0); messageLayout->addWidget(durationSpinBox, 1, 1); messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3); messageLayout->addWidget(titleLabel, 2, 0); messageLayout->addWidget(titleEdit, 2, 1, 1, 4); messageLayout->addWidget(bodyLabel, 3, 0); messageLayout->addWidget(bodyEdit, 3, 1, 2, 4); messageLayout->addWidget(showMessageButton, 5, 4); messageLayout->setColumnStretch(3, 1); messageLayout->setRowStretch(4, 1); messageGroupBox->setLayout(messageLayout);
}
void Window::createActions()
{
minimizeAction = new QAction(tr("Mi&nimize"), this);
connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));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()));
}
void Window::createTrayIcon()
{
trayIconMenu = new QMenu(this);
trayIconMenu->addAction(minimizeAction);
trayIconMenu->addAction(maximizeAction);
trayIconMenu->addAction(restoreAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu);
}
@
is this a qt bug ? or something I did wrong somewhere -
[quote author="brucewuu" date="1309868142"]@//! [6]
void Window::messageClicked()
{
QMessageBox::information(0, tr("Systray"),
tr("Sorry, I already gave what help I could.n"
"Maybe you should try asking a human?"));
}//! [6]
void Window::createIconGroupBox()
{
iconGroupBox = new QGroupBox(tr("Tray Icon"));iconLabel = new QLabel("Icon:"); iconComboBox = new QComboBox; iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad")); iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart")); iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash")); showIconCheckBox = new QCheckBox(tr("Show icon")); showIconCheckBox->setChecked(true); QHBoxLayout *iconLayout = new QHBoxLayout; iconLayout->addWidget(iconLabel); iconLayout->addWidget(iconComboBox); iconLayout->addStretch(); iconLayout->addWidget(showIconCheckBox); iconGroupBox->setLayout(iconLayout);
}
void Window::createMessageGroupBox()
{
messageGroupBox = new QGroupBox(tr("Balloon Message"));typeLabel = new QLabel(tr("Type:")); typeComboBox = new QComboBox; typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxInformation), tr("Information"), QSystemTrayIcon::Information); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxWarning), tr("Warning"), QSystemTrayIcon::Warning); typeComboBox->addItem(style()->standardIcon( QStyle::SP_MessageBoxCritical), tr("Critical"), QSystemTrayIcon::Critical); typeComboBox->setCurrentIndex(1); durationLabel = new QLabel(tr("Duration:")); durationSpinBox = new QSpinBox; durationSpinBox->setRange(5, 60); durationSpinBox->setSuffix(" s"); durationSpinBox->setValue(15); durationWarningLabel = new QLabel(tr("(some systems might ignore this " "hint)")); durationWarningLabel->setIndent(10); titleLabel = new QLabel(tr("Title:")); titleEdit = new QLineEdit(tr("Cannot connect to network")); bodyLabel = new QLabel(tr("Body:")); bodyEdit = new QTextEdit; bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a " "clue.nClick this balloon for details.")); showMessageButton = new QPushButton(tr("Show Message")); showMessageButton->setDefault(true); QGridLayout *messageLayout = new QGridLayout; messageLayout->addWidget(typeLabel, 0, 0); messageLayout->addWidget(typeComboBox, 0, 1, 1, 2); messageLayout->addWidget(durationLabel, 1, 0); messageLayout->addWidget(durationSpinBox, 1, 1); messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3); messageLayout->addWidget(titleLabel, 2, 0); messageLayout->addWidget(titleEdit, 2, 1, 1, 4); messageLayout->addWidget(bodyLabel, 3, 0); messageLayout->addWidget(bodyEdit, 3, 1, 2, 4); messageLayout->addWidget(showMessageButton, 5, 4); messageLayout->setColumnStretch(3, 1); messageLayout->setRowStretch(4, 1); messageGroupBox->setLayout(messageLayout);
}
void Window::createActions()
{
minimizeAction = new QAction(tr("Mi&nimize"), this);
connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));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()));
}
void Window::createTrayIcon()
{
trayIconMenu = new QMenu(this);
trayIconMenu->addAction(minimizeAction);
trayIconMenu->addAction(maximizeAction);
trayIconMenu->addAction(restoreAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu);
}
@
is this a qt bug ? or something I did wrong somewhere[/quote] -
If you start and end your code section in your post with an 'at' sign ('@') it will look much nicer. That is what the others are asking for.
I have just added in the post above these two signs in the begin at the end. And voila it looks much better.
Sorry, had to do two posts ;-)
-
there is a wiki page explaining how the editor works :
"Using the editor :":http://developer.qt.nokia.com/wiki/ForumHelp#9bd9c32b79efb1b2d5b039e4d48300a9 -
It may be caused by some internal objects that are no longer available after you hide the icon. I can reproduce the crash on my Mac box.
As a workaround you can replace the call to hide with a single shot timer in your slot like this
@
fSystemTrayTimer->stop() ;
//fSystemTrayIcon->hide();
QTimer::singleShot(0, fSystemTrayIcon, SLOT(hide()));
@This way the call to hide is delivered after you have left the slot.
EDIT:
I've added this as a doc not to [[Doc:QSystemTrayIcon]] too. -
hi Volker , I also meet the same problem as the following link
http://svn.netlabs.org/qt4/ticket/201
do you have some solution for that ?thanks ~~