QT 实现一个任务栏托盘图标程序 weathertrayicon

  1.  int main(intargc,char*argv[])
  2. {
  3.     QApplication app(argc, argv);
  4.     app.setApplicationName(app.translate("main",
  5.                                          "Weather Tray Icon"));
  6.     app.setOrganizationName("Qtrac Ltd.");
  7.     app.setOrganizationDomain("qtrac.eu");
  8. #ifdef Q_WS_MAC
  9.     app.setCursorFlashTime(0);
  10. #endif
  11.     app.setQuitOnLastWindowClosed(false);
  12.     if (int error = enableNetworkProxying())
  13.         return error;
  14.  
  15.     WeatherTrayIcon weatherTrayIcon;
  16.     weatherTrayIcon.show();
  17.     return app.exec();
  18. }
第11行代码很重要,设置这个应用程序在最后一个窗口关闭后也不退出,这样任务栏托盘图标程序才会继续保持运行状态
  1. int enableNetworkProxying()
  2. {
  3.     AQP::OptionParser parser(qApp->arguments(), qApp->translate(
  4.             "main",
  5.             "usage: {program} [options]\n\n"
  6.             "To use a proxy server set the host and port,\n"
  7.             "and if required the username, password, and proxy "
  8.             "type.\n\nVersion 1.0.0 Copyright (c) 2010 Qtrac Ltd. "
  9.             "All rights reserved.\n"));
  10.     AQP::StringOptionPtr typeOpt = parser.addStringOption(
  11.             "t", "type");
  12.     typeOpt->setHelp(qApp->translate("main", "proxy type"));
  13.     typeOpt->setDefaultValue("socks5");
  14.     typeOpt->setAcceptableValues(QStringList() << "socks5" << "http");
  15.     AQP::StringOptionPtr hostOpt = parser.addStringOption(
  16.             "H", "host");
  17.     hostOpt->setHelp(qApp->translate("main",
  18.             "hostname, e.g., www.example.com"));
  19.     AQP::IntegerOptionPtr portOpt = parser.addIntegerOption(
  20.             "p", "port");
  21.     portOpt->setHelp(qApp->translate("main",
  22.             "port number, e.g., 1080"));
  23.     AQP::StringOptionPtr userOpt = parser.addStringOption(
  24.             "u", "username");
  25.     userOpt->setHelp(qApp->translate("main", "username"));
  26.     AQP::StringOptionPtr passwordOpt = parser.addStringOption(
  27.             "P", "password");
  28.     passwordOpt->setHelp(qApp->translate("main", "password"));
  29.     if (!parser.parse())
  30.         return 2;
  31.  
  32.     if (parser.hasValue("host")) {
  33.         QNetworkProxy proxy;
  34.         proxy.setType(parser.string("type") == "socks5"
  35.                 ? QNetworkProxy::Socks5Proxy
  36.                 : QNetworkProxy::HttpProxy);
  37.         proxy.setHostName(parser.string("host"));
  38.         if (parser.hasValue("port"))
  39.             proxy.setPort(parser.integer("port"));
  40.         if (parser.hasValue("username"))
  41.             proxy.setUser(parser.string("username"));
  42.         if (parser.hasValue("password"))
  43.             proxy.setPassword(parser.string("password"));
  44.         QNetworkProxy::setApplicationProxy(proxy);
  45.     }
  46.     return 0;
  47. }
第32行代码起,为程序访问网络提供通过代理访问的功能.包括代理类型,主机名,端口号,用户名,密码
本程序定义的代理在整个程序起作用.还可以为每一个socket设置代理QAbstractSocket::setProxy
下面我们来看看最最重要的WeatherTrayIcon类
 
  1. class WeatherTrayIcon : public QSystemTrayIcon
  2. {
  3.     Q_OBJECT
  4.  
  5. public:
  6.     explicit WeatherTrayIcon();
  7.  
  8. private slots:
  9.     void requestXml();
  10.     void readXml(QNetworkReply *reply);
  11.     void readIcon(QNetworkReply *reply);
  12.     void setAirport(QAction *action);
  13.  
  14. private:
  15.     void createContextMenu();
  16.     void populateToolTip(QDomDocument *document);
  17.     QString toolTipField(const QString &name,
  18.             const QString &htmlColor, const QString &value,
  19.             bool appendBr=true);
  20.     QString textForTag(const QString &tag, QDomDocument *document);
  21.  
  22.     QMenu menu;
  23.     QNetworkAccessManager *networkXmlAccess;
  24.     QNetworkAccessManager *networkIconAccess;
  25.     QString airport;
  26.     QCache<QUrl, QIcon> iconCache;
  27.     int retryDelaySec;
  28. };
首先这个类是以Qt的标准类QSystemTrayIcon为基类.此基类又直接从QObject派生的.
其次,说明一下私有成员都是干什么的.
第25行的airport为当前选定的机场
第26行的iconCache 记录特定的URL和与其相关的反应天气状况的图标文件
最后,说明一下该类涉及到的方法,先从构造函数开始吧WeatherTrayIcon();
  1. WeatherTrayIcon::WeatherTrayIcon()
  2.     : QSystemTrayIcon(), retryDelaySec(1)
  3. {
  4.     setIcon(QIcon(":/rss.png"));
  5.     createContextMenu();
  6.  
  7.     networkXmlAccess = new QNetworkAccessManager(this);
  8.     networkIconAccess = new QNetworkAccessManager(this);
  9.     connect(networkXmlAccess, SIGNAL(finished(QNetworkReply*)),
  10.             this, SLOT(readXml(QNetworkReply*)));
  11.     connect(networkIconAccess, SIGNAL(finished(QNetworkReply*)),
  12.             this, SLOT(readIcon(QNetworkReply*)));
  13.  
  14.     QTimer::singleShot(0, this, SLOT(requestXml()));
  15. }
设置下载第一个图标过程中的等待图标.
创建上下文菜单
初始化两个访问管理实例,分别下载天气信息和图标
只关心下载完成,并响应处理
然后调用requestXml()函数
在说明requestXml()函数作用前,先看看createContextMenu()创建上下文菜单函数
  1. void WeatherTrayIcon::createContextMenu()
  2. {
  3.     QStringList airports;
  4.     airports << "Austin-Bergstrom International Airport (KAUS)"
  5.              << "Chicago/Ohare (KORD)"
  6.              << "Dallas / Fort Worth International Airport (KDFW)"
  7.              << "Detroit City Airport (KDET)"
  8.              << "Houston Intercontinental Airport (KIAH)"
  9.              << "Indianapolis International Airport (KIND)"
  10.              << "Jacksonville International Airport (KJAX)"
  11.              << "Los Angeles Intl Airport (KLAX)"
  12.              << "New York/John F. Kennedy Intl Airport (KJFK)"
  13.              << "Philadelphia International Airport (KPHL)"
  14.              << "Phoenix/Sky Harbor (KPHX)"
  15.              << "Port Columbus International Airport (KCMH)"
  16.              << "San Antonio International Airport (KSAT)"
  17.              << "San Diego/Brown Fld (KSDM)"
  18.              << "San Francisco Intl Airport (KSFO)"
  19.              << "San Jose International Airport (KSJC)";
  20.     QSettings settings;
  21.     airport = settings.value("airport", QVariant(airports.at(0)))
  22.                              .toString();
  23.  
  24.     QActionGroup *group = new QActionGroup(this);
  25.     foreach (const QString &anAirport, airports) {
  26.         QAction *action = menu.addAction(anAirport);
  27.         group->addAction(action);
  28.         action->setCheckable(true);
  29.         action->setChecked(anAirport == airport);
  30.         action->setData(anAirport);
  31.     }
  32.     connect(group, SIGNAL(triggered(QAction*)),
  33.             this, SLOT(setAirport(QAction*)));
  34.     menu.addSeparator();
  35.     menu.addAction(QIcon(":/exit.png"), tr("E&xit"), qApp,
  36.                    SLOT(quit()));
  37.  
  38.     AQP::accelerateMenu(&menu);
  39.     setContextMenu(&menu);
  40. }
从注册表中读取最后一次设置的机场名,如果是第一次运行程序,默认为第一个机场名
foreach访问字符串列表中的每一个字符串,创建action加在action组中,统一处理action响应
设置此菜单为QSystemTrayIcon的菜单
 
  1. void WeatherTrayIcon::requestXml()
  2. {
  3.     QString airportId = airport.right(6);
  4.     if (airportId.startsWith("(") && airportId.endsWith(")")) {
  5.         QString url = QString("http://www.weather.gov/xml/"
  6.                 "current_obs/%1.xml").arg(airportId.mid(1, 4));
  7.         networkXmlAccess->get(QNetworkRequest(QUrl(url)));
  8.     }

  9.     setToolTip(tr("Failed to connect to network.\n"
  10.             "A proxy can be set on the command line:\n"
  11.             "weathertrayicon --help"));
  12. }
networkXmlAccess以QNetworkRequest作为参数进行get操作,当请求得到响应后会自动调用之前连接的槽来处理响应
  1. void WeatherTrayIcon::readXml(QNetworkReply *reply)
  2. {
  3.     if (reply->error() != QNetworkReply::NoError) {
  4.         setToolTip(tr("Failed to retrieve weather data:\n%1")
  5.                    .arg(reply->errorString()));
  6.         QTimer::singleShot(retryDelaySec * 1000,
  7.                            this, SLOT(requestXml()));
  8.         retryDelaySec <<= 1;
  9.         if (retryDelaySec > 60 * 60)
  10.             retryDelaySec = 1;
  11.         return;
  12.     }
  13.     retryDelaySec = 1;
  14.     QDomDocument document;
  15.     if (document.setContent(reply))
  16.         populateToolTip(&document);
  17.     QTimer::singleShot(60 * 60 * 1000, this, SLOT(requestXml()));
  18. }
 请求得到的响应有错误的话会进行延时重传,成功的话会在一个小时后重新请求
  1. void WeatherTrayIcon::readIcon(QNetworkReply *reply)
  2. {
  3.     QUrl redirect = reply->attribute(
  4.             QNetworkRequest::RedirectionTargetAttribute).toUrl();
  5.     if (redirect.isValid())
  6.         networkIconAccess->get(QNetworkRequest(redirect));
  7.     else {
  8.         QByteArray ba(reply->readAll());
  9.         QPixmap pixmap;
  10.         if (pixmap.loadFromData(ba)) {
  11.             QIcon *icon = new QIcon(pixmap);
  12.             setIcon(*icon);
  13.             iconCache.insert(reply->request().url(), icon);
  14.         }
  15.     }
  16. }
请求图标的响应可能是一个重定向的网址,如果有效用此重定向的网址再请求一次图标下载
否则读取reply中的数据放到字节数组里,用QPixmap加载进来,生成一个QIcon,设置程序Icon,存储到iconCache里
 
就写到这里,参考<<Qt 高级编程>>,仅供本人加深理解之用

另:本人提供有偿技术服务.如有需要请登陆   http://shop71746057.taobao.com/ 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值