日期:2014-05-17  浏览次数:21526 次

Qt下载必应的每日图片,Windows API设置桌面背景

自制小程序功能

    下载当日必应的每日图片,浏览已下载的图片,设置桌面背景。


QtNetwork和QtWebKit

    Qt中可用于网络编程的类大多在QtNetwork和QtWebKit中。QtWebKit里面的类用于呈现和编辑web页面的内容,所以像QWebView、QWebInspector都继承自QWidget。而QtNetwork中有用于ftp、socket编程的类,比如QLocalServer、QLocalSocket、QFtp等。


利用QWebView获取web页面源码

    QWebView可以通过load函数来加载一个url指定的web页面内容,load函数会发送loadStarted、loadProgress、loadFinished信号,在加载完毕后,也就是连接loadFinished信号和某个槽,通过该槽函数来执行对页面源码解析,提取出目标信息加以处理。

    获取源码可以利用的QWebFrame的toHtml函数。

QWebView *webView = new QWebView;
webView->load(QUrl("http://cn.bing.com"));
webView->show();

    在loadFinished信号发送出后执行:

qDebug()<< webView->page()->currentFrame()->toHtml();

不过这个小程序并不是去获取页面的源代码,而是通过css选择器来选择需要的元素。QWebElement有提供相应的DOM操作,不过与JS比起来还是很弱的。

connect(bing_, SIGNAL(loadFinished(bool)), this, SLOT(onload(bool)));
void BingDesktopFollower::onload(bool success)
{
    qDebug() << "onload: success = " << success;
    if(success)
    {
        QRegExp rxp("background-image\\s*:\\s*url\\s*[(](.+)[)]", Qt::CaseInsensitive);
        int pos = 0;
        rxp.setMinimal(true);
//        bing_->show();
        QWebElement bgDiv = bing_->page()->currentFrame()->findFirstElement("div#bgDiv"); //用CSS选择器获取指定DOM元素(解析HTML)
        QString style = bgDiv.attribute("style"); //获取属性节点
        if(style.contains(rxp)) //利用正则匹配出图片地址,之所以判断图片地址是否存在是因为 QWebView 的 loadFinished 会触发多次,如果页面有多个 frame
        {
            pos = rxp.indexIn(style);
            qDebug() << "extracted image path: " << rxp.cap(1);
            downloadPicture(QUrl(rxp.cap(1)));
        }
        if(-1 == pos)
        {
            emit message(RESOURCE_LOCATE_ERROR);
        }
    }
    else
    {
        if(retry_counter_ >= 3)
        {
            emit message(PAGELOAD_ERROR);
            retry_counter_ = 0;
            return;
        }
        fetch();
        retry_counter_++;
    }
}


下载指定URL的图片

    利用QNetworkAccessManager的get函数来获取指定URL资源的字节流。通过类型转换来获取需要的资源。

//...假设已经做初始化了
QNetworkAccessManager *nam_;

//连接QNetworkAccessManager的finished信号和某个槽
connect(nam_, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

nam_->get(QN