- int main(intargc,char*argv[])
-
{
-
QApplication app(argc, argv);
-
app.setApplicationName(app.translate("main",
-
"Weather Tray Icon"));
-
app.setOrganizationName("Qtrac Ltd.");
-
app.setOrganizationDomain("qtrac.eu");
-
#ifdef Q_WS_MAC
-
app.setCursorFlashTime(0);
-
#endif
-
app.setQuitOnLastWindowClosed(false);
-
if (int error = enableNetworkProxying())
-
return error;
-
-
WeatherTrayIcon weatherTrayIcon;
-
weatherTrayIcon.show();
-
return app.exec();
-
}
第11行代码很重要,设置这个应用程序在最后一个窗口关闭后也不退出,这样任务栏托盘图标程序才会继续保持运行状态
-
int enableNetworkProxying()
-
{
-
AQP::OptionParser parser(qApp->arguments(), qApp->translate(
-
"main",
-
"usage: {program} [options]\n\n"
-
"To use a proxy server set the host and port,\n"
-
"and if required the username, password, and proxy "
-
"type.\n\nVersion 1.0.0 Copyright (c) 2010 Qtrac Ltd. "
-
"All rights reserved.\n"));
-
AQP::StringOptionPtr typeOpt = parser.addStringOption(
-
"t", "type");
-
typeOpt->setHelp(qApp->translate("main", "proxy type"));
-
typeOpt->setDefaultValue("socks5");
-
typeOpt->setAcceptableValues(QStringList() << "socks5" << "http");
-
AQP::StringOptionPtr hostOpt = parser.addStringOption(
-
"H", "host");
-
hostOpt->setHelp(qApp->translate("main",
-
"hostname, e.g., www.example.com"));
-
AQP::IntegerOptionPtr portOpt = parser.addIntegerOption(
-
"p", "port");
-
portOpt->setHelp(qApp->translate("main",
-
"port number, e.g., 1080"));
-
AQP::StringOptionPtr userOpt = parser.addStringOption(
-
"u", "username");
-
userOpt->setHelp(qApp->translate("main", "username"));
-
AQP::StringOptionPtr passwordOpt = parser.addStringOption(
-
"P", "password");
-
passwordOpt->setHelp(qApp->translate("main", "password"));
-
if (!parser.parse())
-
return 2;
-
-
if (parser.hasValue("host")) {
-
QNetworkProxy proxy;
-
proxy.setType(parser.string("type") == "socks5"
-
? QNetworkProxy::Socks5Proxy
-
: QNetworkProxy::HttpProxy);
-
proxy.setHostName(parser.string("host"));
-
if (parser.hasValue("port"))
-
proxy.setPort(parser.integer("port"));
-
if (parser.hasValue("username"))
-
proxy.setUser(parser.string("username"));
-
if (parser.hasValue("password"))
-
proxy.setPassword(parser.string("password"));
-
QNetworkProxy::setApplicationProxy(proxy);
-
}
-
return 0;
-
}
第32行代码起,为程序访问网络提供通过代理访问的功能.包括代理类型,主机名,端口号,用户名,密码
本程序定义的代理在整个程序起作用.还可以为每一个socket设置代理QAbstractSocket::setProxy
下面我们来看看最最重要的WeatherTrayIcon类
-
class WeatherTrayIcon : public QSystemTrayIcon
-
{
-
Q_OBJECT
-
-
public:
-
explicit WeatherTrayIcon();
-
-
private slots:
-
void requestXml();
-
void readXml(QNetworkReply *reply);
-
void readIcon(QNetworkReply *reply);
-
void setAirport(QAction *action);
-
-
private:
-
void createContextMenu();
-
void populateToolTip(QDomDocument *document);
-
QString toolTipField(const QString &name,
-
const QString &htmlColor, const QString &value,
-
bool appendBr=true);
-
QString textForTag(const QString &tag, QDomDocument *document);
-
-
QMenu menu;
-
QNetworkAccessManager *networkXmlAccess;
-
QNetworkAccessManager *networkIconAccess;
-
QString airport;
-
QCache<QUrl, QIcon> iconCache;
-
int retryDelaySec;
-
};
首先这个类是以Qt的标准类QSystemTrayIcon为基类.此基类又直接从QObject派生的.
其次,说明一下私有成员都是干什么的.
第25行的airport为当前选定的机场
第26行的iconCache 记录特定的URL和与其相关的反应天气状况的图标文件
最后,说明一下该类涉及到的方法,先从构造函数开始吧WeatherTrayIcon();
-
WeatherTrayIcon::WeatherTrayIcon()
-
: QSystemTrayIcon(), retryDelaySec(1)
-
{
-
setIcon(QIcon(":/rss.png"));
-
createContextMenu();
-
-
networkXmlAccess = new QNetworkAccessManager(this);
-
networkIconAccess = new QNetworkAccessManager(this);
-
connect(networkXmlAccess, SIGNAL(finished(QNetworkReply*)),
-
this, SLOT(readXml(QNetworkReply*)));
-
connect(networkIconAccess, SIGNAL(finished(QNetworkReply*)),
-
this, SLOT(readIcon(QNetworkReply*)));
-
-
QTimer::singleShot(0, this, SLOT(requestXml()));
-
}
设置下载第一个图标过程中的等待图标.
创建上下文菜单
初始化两个访问管理实例,分别下载天气信息和图标
只关心下载完成,并响应处理
然后调用requestXml()函数
在说明requestXml()函数作用前,先看看createContextMenu()创建上下文菜单函数
-
void WeatherTrayIcon::createContextMenu()
-
{
-
QStringList airports;
-
airports << "Austin-Bergstrom International Airport (KAUS)"
-
<< "Chicago/Ohare (KORD)"
-
<< "Dallas / Fort Worth International Airport (KDFW)"
-
<< "Detroit City Airport (KDET)"
-
<< "Houston Intercontinental Airport (KIAH)"
-
<< "Indianapolis International Airport (KIND)"
-
<< "Jacksonville International Airport (KJAX)"
-
<< "Los Angeles Intl Airport (KLAX)"
-
<< "New York/John F. Kennedy Intl Airport (KJFK)"
-
<< "Philadelphia International Airport (KPHL)"
-
<< "Phoenix/Sky Harbor (KPHX)"
-
<< "Port Columbus International Airport (KCMH)"
-
<< "San Antonio International Airport (KSAT)"
-
<< "San Diego/Brown Fld (KSDM)"
-
<< "San Francisco Intl Airport (KSFO)"
-
<< "San Jose International Airport (KSJC)";
-
QSettings settings;
-
airport = settings.value("airport", QVariant(airports.at(0)))
-
.toString();
-
-
QActionGroup *group = new QActionGroup(this);
-
foreach (const QString &anAirport, airports) {
-
QAction *action = menu.addAction(anAirport);
-
group->addAction(action);
-
action->setCheckable(true);
-
action->setChecked(anAirport == airport);
-
action->setData(anAirport);
-
}
-
connect(group, SIGNAL(triggered(QAction*)),
-
this, SLOT(setAirport(QAction*)));
-
menu.addSeparator();
-
menu.addAction(QIcon(":/exit.png"), tr("E&xit"), qApp,
-
SLOT(quit()));
-
-
AQP::accelerateMenu(&menu);
-
setContextMenu(&menu);
-
}
从注册表中读取最后一次设置的机场名,如果是第一次运行程序,默认为第一个机场名
foreach访问字符串列表中的每一个字符串,创建action加在action组中,统一处理action响应
设置此菜单为QSystemTrayIcon的菜单
-
void WeatherTrayIcon::requestXml()
-
{
-
QString airportId = airport.right(6);
-
if (airportId.startsWith("(") && airportId.endsWith(")")) {
-
QString url = QString("http://www.weather.gov/xml/"
-
"current_obs/%1.xml").arg(airportId.mid(1, 4));
-
networkXmlAccess->get(QNetworkRequest(QUrl(url)));
-
}
-
-
setToolTip(tr("Failed to connect to network.\n"
-
"A proxy can be set on the command line:\n"
-
"weathertrayicon --help"));
-
}
networkXmlAccess以QNetworkRequest作为参数进行get操作,当请求得到响应后会自动调用之前连接的槽来处理响应
-
void WeatherTrayIcon::readXml(QNetworkReply *reply)
-
{
-
if (reply->error() != QNetworkReply::NoError) {
-
setToolTip(tr("Failed to retrieve weather data:\n%1")
-
.arg(reply->errorString()));
-
QTimer::singleShot(retryDelaySec * 1000,
-
this, SLOT(requestXml()));
-
retryDelaySec <<= 1;
-
if (retryDelaySec > 60 * 60)
-
retryDelaySec = 1;
-
return;
-
}
-
retryDelaySec = 1;
-
QDomDocument document;
-
if (document.setContent(reply))
-
populateToolTip(&document);
-
QTimer::singleShot(60 * 60 * 1000, this, SLOT(requestXml()));
-
}
请求得到的响应有错误的话会进行延时重传,成功的话会在一个小时后重新请求
-
void WeatherTrayIcon::readIcon(QNetworkReply *reply)
-
{
-
QUrl redirect = reply->attribute(
-
QNetworkRequest::RedirectionTargetAttribute).toUrl();
-
if (redirect.isValid())
-
networkIconAccess->get(QNetworkRequest(redirect));
-
else {
-
QByteArray ba(reply->readAll());
-
QPixmap pixmap;
-
if (pixmap.loadFromData(ba)) {
-
QIcon *icon = new QIcon(pixmap);
-
setIcon(*icon);
-
iconCache.insert(reply->request().url(), icon);
-
}
-
}
-
}
请求图标的响应可能是一个重定向的网址,如果有效用此重定向的网址再请求一次图标下载
否则读取reply中的数据放到字节数组里,用QPixmap加载进来,生成一个QIcon,设置程序Icon,存储到iconCache里
就写到这里,参考<<Qt 高级编程>>,仅供本人加深理解之用
另:本人提供有偿技术服务.如有需要请登陆 http://shop71746057.taobao.com/