haulm 发表于 2008-3-9 20:28:42

基础篇 -- Qt4.2之后的托盘类实现托盘程序

用hello world简单的代码更容易看懂托盘的具体实现,未完待续,一些细节问题,比如为什么提示消息没有显示在托盘上,如何在tip消息上增加图标等。

#include <QtGui>
class myclass: public QWidget
{
public:
        myclass();
private:
        QPushButton *b1;
        QSystemTrayIcon *trayIcon;
       
};

myclass::myclass()
{       
        QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312"));
        setMinimumSize(200,100);
        setMaximumSize(200,100);
        b1=new QPushButton("hello world",this);
        b1->setGeometry(20,20,160,40);
        QIcon icon = QIcon("./images/bad.svg");
        setWindowIcon(icon);
        trayIcon = new QSystemTrayIcon(this);
        trayIcon->setIcon(icon);
        trayIcon->setToolTip("a trayicon example");
        QString titlec=tr("看吧");
        QString textc=QString::fromLocal8Bit("就这德行啊");
        trayIcon->show();
        trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
        setWindowTitle(tr("Systray"));
}

int main(int argc,char **argv)
{
        QApplication testc(argc,argv);
        myclass newc;
        newc.show();
        return testc.exec();
}

haulm 发表于 2008-3-12 19:16:49

进一步研究,加入点击托盘的响应,使提示信息显示在托盘上,未完待续托盘的右键菜单。

经验一:编译信号和槽 需要有.h .cpp这样的格式,否则不会生成相应的信号和槽;

经验二:信号和槽之间可以递参数,但是不允许函数直接给槽提供参数。

hello.h

#include <QtGui>
class myclass: public QWidget
{
Q_OBJECT
public:
myclass();
private:
QPushButton *b1;
QSystemTrayIcon *trayIcon;
char *msg;
void showMessage(char *msg);
private slots:
void showM();
void iconActivated(QSystemTrayIcon::ActivationReason reason);
};

hello.cpp

#include <QtGui>
#include "hello.h"
myclass::myclass()
{
QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312"));
setMinimumSize(200,100);
setMaximumSize(200,100);
b1=new QPushButton("hello world",this);
b1->setGeometry(20,20,160,40);
QIcon icon = QIcon("./images/bad.svg");
setWindowIcon(icon);
trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(icon);
trayIcon->setToolTip("a trayicon example");
trayIcon->show();
setWindowTitle(tr("Systray"));

connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
                     this,SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
connect(b1,SIGNAL(clicked()),this,SLOT(showM()));
}

void myclass::showM()
{
QString titlec=tr("slot需要signal相同的参数进行传递");
QString textc=QString::fromLocal8Bit("测试内容单击、双击、中键、按钮");
trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
}

void myclass::showMessage(char *msg)
{
QString titlec=tr(msg);
QString textc=QString::fromLocal8Bit("测试内容单击、双击、中键、按钮");
trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
}

void myclass::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
switch (reason) {
case QSystemTrayIcon::Trigger:
showMessage("单击");
break;
case QSystemTrayIcon::DoubleClick:
showMessage("双击啦");
break;
case QSystemTrayIcon::MiddleClick:
showMessage("你用的是三轮鼠标还是滚轮鼠标啊");
break;
default:
;
}
}

int main(int argc,char **argv)
{
QApplication testc(argc,argv);
myclass newc;
newc.show();
return testc.exec();
}

haulm 发表于 2008-3-13 17:20:01

那么最后我们把所有元素都结合在一起来实现这么一个托盘程序,比较上个例子我们增加了右键菜单并使它管理窗口的大小。

hello.h

#include <QtGui>
class myclass: public QWidget
{
        Q_OBJECT       
public:
        myclass();
private:
        QPushButton *b1;
        QSystemTrayIcon *trayIcon;
        char *msg;
        void showMessage(char *msg);
        void createActions();
        void createTrayIcon();
        QAction *minimizeAction;
      QAction *maximizeAction;
      QAction *restoreAction;
      QAction *quitAction;
        QMenu *trayIconMenu;
private slots:
        void showM();
        void iconActivated(QSystemTrayIcon::ActivationReason reason);
};



hello.cpp

#include <QtGui>
#include "hello.h"
myclass::myclass()
{       
        QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312"));
        setMinimumSize(200,100);
        b1=new QPushButton("hello world",this);
        b1->setGeometry(20,20,160,40);
        QIcon icon = QIcon("./images/bad.svg");
        setWindowIcon(icon);
        trayIcon = new QSystemTrayIcon(this);
        trayIcon->setIcon(icon);
        trayIcon->setToolTip("a trayicon example");
createActions();
createTrayIcon();
        trayIcon->show();
        setWindowTitle(tr("Systray"));
connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
connect(b1,SIGNAL(clicked()),this,SLOT(showM()));
}

void myclass::showM()
{
        QString titlec=tr("slot需要signal相同的参数进行传递");
        QString textc=QString::fromLocal8Bit("测试内容单击、双击、中键、按钮");
        trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
      }
               
void myclass::showMessage(char *msg)
{
        QString titlec=tr(msg);
        QString textc=QString::fromLocal8Bit("测试内容单击、双击、中键、按钮");
        trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
      }
               
void myclass::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
   switch (reason) {
   case QSystemTrayIcon::Trigger:
showMessage("单击");
        break;
   case QSystemTrayIcon::DoubleClick:
showMessage("双击啦");
         break;
   case QSystemTrayIcon::MiddleClick:
showMessage("你用的是三轮鼠标还是滚轮鼠标啊");
         break;
   default:
         ;
   }
}

void myclass::createActions()
{
   minimizeAction = new QAction(tr("最小化 (&I)"), this);
   connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

   maximizeAction = new QAction(tr("最大化 (&X)"), this);
   connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));

   restoreAction = new QAction(tr("还原 (&R)"), this);
   connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

   quitAction = new QAction(tr("退出 (&Q)"), this);
   connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

void myclass::createTrayIcon()
{
   trayIconMenu = new QMenu(this);
   trayIconMenu->addAction(minimizeAction);
   trayIconMenu->addAction(maximizeAction);
   trayIconMenu->addAction(restoreAction);
   trayIconMenu->addSeparator();
   trayIconMenu->addAction(quitAction);
   trayIcon->setContextMenu(trayIconMenu);
}


int main(int argc,char **argv)
{
        QApplication testc(argc,argv);
        myclass newc;
        newc.show();
        return testc.exec();
}



[ 本帖最后由 haulm 于 2008-3-13 17:23 编辑 ]

hover_sky 发表于 2009-5-15 23:59:11

如何实现点击Dialog的最小化就最小化到托盘呢?

haulm 发表于 2009-5-16 10:17:53

通过重新定义closeEvent事件 event->ignore() 可以解决这个问题
protected:
      void closeEvent(QCloseEvent *event);

void myclass::closeEvent(QCloseEvent *event)
{
    if (this->trayIcon->isVisible()) {
       hide();
      event->ignore();
    }
}

hover_sky 发表于 2009-5-16 13:11:06

谢谢haulm。

版主,您提供的代码是“点击关闭”然后最小化到托盘的吧?


我要的是“点击右上角的最小化按钮”,然后最小化到托盘。。。。

sejishikong 发表于 2009-5-16 23:14:25

QWindowStateChangeEvent

hover_sky 发表于 2009-5-17 13:06:26


void Dialog::changeEvent(QEvent * event )
{
    if(event->WindowStateChange)
    {
         switch(this->windowState()){
               case Qt::WindowMinimized:
                  //this->showNormal();
                  this->hide();
                  event->ignore();
                   // event->accept();
                   break;
               // caseQt::WindowNoState:
                        //this->show();
                      //event->ignore();
                      //break;
               // default:
                   break;
               }
    }
}
结果点击“最小化”按钮,状态栏还存在图标,但那个图标是“死的”了,点击它,还可以在桌面显示,但已经是白茫茫的一片。。。。

hover_sky 发表于 2009-5-17 13:52:19

附详细代码

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QtGui/QDialog>
#include <QSystemTrayIcon>

namespace Ui
{
    class Dialog;
}
class QPaintEvent;
class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QSystemTrayIcon *trayIcon;
    QMenu *trayIconMenu;
    QAction *minimizeAction;

    //QAction *maximizeAction;
    QAction *restoreAction;
    QAction *quitAction;
    char *msg;
    void createActions();
    void createTrayIcon();
    void showMessage(char *msg);
protected:
      void closeEvent(QCloseEvent *event);
      void changeEvent(QEvent * event );
      void paintEvent(QPaintEvent *event);

private slots:
    void on_pushButton_clicked();
    void on_pushButton2_clicked();
    void showM();
    void iconActivated(QSystemTrayIcon::ActivationReason reason);
};

#endif // DIALOG_H

hover_sky 发表于 2009-5-17 13:52:51

dialog.cpp


#include <QMessageBox>
#include <QtGui>
#include <QtCore/QTextCodec>
#include <QtGui/QCloseEvent>
#include <QMenu>
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent), ui(new Ui::Dialog)
{
    char *string = "你好,世界!";
   // QTextCodec *codec = QTextCodec::codecForName("GBK");
   // QString strText = codec->toUnicode(string);
   // QString str;
    //str = str.fromLocal8Bit(string);
    this->setWindowFlags(Qt::WindowMinimizeButtonHint);
    ui->setupUi(this);
    ui->textEdit->clear();
    ui->textEdit->setText(QObject::tr(string));
    //QObject::connect(ui->pushButton2, SIGNAL(clicked()),this, SLOT(close()));
    //QObject::connect(ui->pushButton, SIGNAL(clicked()),this, SLOT(on_pushButton_clicked()));
    QIcon icon = QIcon("./hello.svg");
    setWindowIcon(icon);
    //this->restoreAction = new QAction(tr("还原 (&R)"), this);
    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setIcon(icon);
    trayIcon->setToolTip("1st trip of QT4");
    QString titlec=QObject::tr("QT4");
    QString textc=QObject::tr("初次约会");
    trayIcon->show();
    createActions();
    createTrayIcon();
    trayIcon->show();
    trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,50);
    setWindowTitle(tr("QT4"));
    connect(trayIcon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));


   connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

}


Dialog::~Dialog()
{
    delete ui;
}

void Dialog::on_pushButton2_clicked()
{
    this->close();
}

void Dialog::on_pushButton_clicked()
{
   QMessageBox::information(this,tr("朋友"),tr("您好"));

}

void Dialog::showM()
{
      QString titlec=tr("双击打开主窗体");
      QString textc=QString::fromLocal8Bit("右键选择其他操作");
      trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);
      }

void Dialog::showMessage(char *msg)
{
      QString titlec=tr(msg);
      QString textc=QString::fromLocal8Bit("测试内容单击、双击、中键、按钮");
       trayIcon->showMessage(titlec,textc,QSystemTrayIcon::Information,5000);

}

void Dialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
   switch (reason) {
   case QSystemTrayIcon::Trigger:
             //showMessage("单击");
            // this->showM();
             //connect(this->restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
            break;
   case QSystemTrayIcon::DoubleClick:
            this->showNormal();
            //showMessage("双击啦");
         break;
   //case QSystemTrayIcon::MiddleClick:
            //showMessage("你用的是三轮鼠标还是滚轮鼠标啊");
         // this->showM();
            break;
   default:
         ;
   }
}

void Dialog::createActions()
{
   minimizeAction = new QAction(tr("最小化 (&I)"), this);
   connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));

   //maximizeAction = new QAction(tr("最大化 (&X)"), this);
   //connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));

   restoreAction = new QAction(tr("还原 (&R)"), this);
   connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));

   quitAction = new QAction(tr("退出 (&Q)"), this);
   connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

void Dialog::createTrayIcon()
{
   trayIconMenu = new QMenu(this);
   trayIconMenu->addAction(minimizeAction);
   //trayIconMenu->addAction(maximizeAction);
   trayIconMenu->addAction(restoreAction);
   trayIconMenu->addSeparator();
   trayIconMenu->addAction(quitAction);
   trayIcon->setContextMenu(trayIconMenu);
}
void Dialog::closeEvent(QCloseEvent *event)
{
    if (this->trayIcon->isVisible())
    {
      QMessageBox::information(this, tr("QT4"),
            tr("程序会一直运行在系统托盘。您可以通过右键点击程序对应的系统托盘图标,然后选择菜单中\"退出\"选项来终止程序的运行。"));
       hide();
       event->ignore();
    }
}
void Dialog::changeEvent(QEvent * event )
{
    if(event->WindowStateChange)
    {
         switch(this->windowState()){
               case Qt::WindowMinimized:
                  //this->showNormal();
                  this->hide();
                  event->ignore();
                   // event->accept();
                   break;
               // caseQt::WindowNoState:
                        //this->show();
                      //event->ignore();
                      //break;
               // default:
                   break;
               }
    }
}
void Dialog::paintEvent(QPaintEvent *event)
{
   QPainter painter;
   painter.begin(this);
   painter.setRenderHint(QPainter::Antialiasing);
   //helper->paint(&painter, event, elapsed);
   painter.end();
}

hover_sky 发表于 2009-5-17 13:53:45

ui_dialog.h


/********************************************************************************
** Form generated from reading ui file 'dialog.ui'
**
** Created: Sat May 16 22:52:04 2009
**      by: Qt User Interface Compiler version 4.5.0
**
** WARNING! All changes made in this file will be lost when recompiling ui file!
********************************************************************************/

#ifndef UI_DIALOG_H
#define UI_DIALOG_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialog>
#include <QtGui/QHBoxLayout>
#include <QtGui/QHeaderView>
#include <QtGui/QPushButton>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Dialog
{
public:
    QWidget *widget;
    QVBoxLayout *verticalLayout;
    QTextEdit *textEdit;
    QHBoxLayout *horizontalLayout;
    QPushButton *pushButton;
    QPushButton *pushButton2;

    void setupUi(QDialog *Dialog)
    {
      if (Dialog->objectName().isEmpty())
            Dialog->setObjectName(QString::fromUtf8("Dialog"));
      Dialog->resize(303, 276);
      widget = new QWidget(Dialog);
      widget->setObjectName(QString::fromUtf8("widget"));
      widget->setGeometry(QRect(20, 40, 258, 227));
      verticalLayout = new QVBoxLayout(widget);
      verticalLayout->setSpacing(6);
      verticalLayout->setMargin(11);
      verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
      verticalLayout->setContentsMargins(0, 0, 0, 0);
      textEdit = new QTextEdit(widget);
      textEdit->setObjectName(QString::fromUtf8("textEdit"));

      verticalLayout->addWidget(textEdit);

      horizontalLayout = new QHBoxLayout();
      horizontalLayout->setSpacing(6);
      horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
      pushButton = new QPushButton(widget);
      pushButton->setObjectName(QString::fromUtf8("pushButton"));

      horizontalLayout->addWidget(pushButton);

      pushButton2 = new QPushButton(widget);
      pushButton2->setObjectName(QString::fromUtf8("pushButton2"));

      horizontalLayout->addWidget(pushButton2);


      verticalLayout->addLayout(horizontalLayout);

      QWidget::setTabOrder(textEdit, pushButton);
      QWidget::setTabOrder(pushButton, pushButton2);

      retranslateUi(Dialog);

      QMetaObject::connectSlotsByName(Dialog);
    } // setupUi

    void retranslateUi(QDialog *Dialog)
    {
      Dialog->setWindowTitle(QApplication::translate("Dialog", "Dialog", 0, QApplication::UnicodeUTF8));
      textEdit->setHtml(QApplication::translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'\345\256\213\344\275\223'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">ffffffffff</p></body></html>", 0, QApplication::UnicodeUTF8));
      pushButton->setText(QApplication::translate("Dialog", "\346\202\250\345\245\275", 0, QApplication::UnicodeUTF8));
      pushButton2->setText(QApplication::translate("Dialog", "\347\246\273\345\274\200", 0, QApplication::UnicodeUTF8));
      Q_UNUSED(Dialog);
    } // retranslateUi

};

namespace Ui {
    class Dialog: public Ui_Dialog {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_DIALOG_H

hover_sky 发表于 2009-5-17 13:54:21

main.cpp


#include <QtGui/QApplication>
#include <QtCore/QTextCodec>
#include <QMessageBox>
#include "dialog.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
    Dialog w;
    w.show();
    return a.exec();
}

haulm 发表于 2009-5-17 14:57:38

我也是从例子中去学习的,很少有程序去实现最小化按钮功用定义,如果要美观可以搞个图标按钮在上面。我之所以这么说是因为你想实现的最小化到托盘的确是比较少的做法。所以看到你的提问我没有深入去研究。
WindowStateChange应该是不能用event->ignore();来中断的,event->ignore();是为了防止closeEvent程序就此关闭了。建议你去找找最小化的事件,如果系统的确没提供就用一个图标按钮来实现好了。
顺便提一下,别把UI生成的代码放上来,离开UI它不能编译,你有试过QHideEvent么?

haulm 发表于 2009-5-17 15:17:04

我在linux下运行以下代码是正常的,麻烦管理员把多余的代码回帖删掉吧
void Window::hideEvent(QHideEvent *event)
{
    if (trayIcon->isVisible()) {
      hide();
      event->ignore();
    }
}

hover_sky 发表于 2009-5-17 18:10:30

先对版主表示感谢。


没有试过QHideEvent哦

只有ui_dialog.h是UI生成的代码。发出来是供大家参考,如果有兴趣。:lol:
void Window::hideEvent(QHideEvent *event)
{
    if (trayIcon->isVisible()) {
      hide();
      event->ignore();
    }
}
在我这里也正常啊,没有问题。


请注意:这里有2个最小化,一是:点击右上角的最小化按钮;二是,点击托盘菜单中的最小化按钮。

实现第二没有问题,就是参考lz的代码。

就是实现第一个,没有成功。

[ 本帖最后由 hover_sky 于 2009-5-17 18:14 编辑 ]
页: [1] 2
查看完整版本: 基础篇 -- Qt4.2之后的托盘类实现托盘程序