基于QtWebkit的嵌入式bs架构设计
                                        Write by: tadaya
概述:本文旨在介绍如何使用QtWebkit来实现嵌入式客户端(browser),而不关注webkit引擎的原理和任何效率问题。重点关注如何使用遥控器去操作网页中的元素(例如焦点移动,打开新的链接),这种应用在目前的iptv上应用非常广泛,通过实现自己的browser,可以加载不同的风格的界面(即网页),结合使用qt其他控件和QtWebkit(框架)实现功能与界面完美结合的产品。
关键字:焦点, QtWebkit,元素
一.嵌入式BS架构的优势。
嵌入式bs架构的设计与pc上的bs架构的区别:
1.pc上无须自行设计浏览器,嵌入式需要对浏览器进行特殊处理。(如按键等)
2.嵌入式需要加上对遥控器的支持。(如tv遥控器)
3.pc上支持的网页元素比嵌入式要多。
4.嵌入式需要做多套网页以适应不同屏幕的分辨率。
5.嵌入式需要考虑page cache和flash权衡的问题。
bs架构比cs架构的优势:
1.设计简单。大部分界面和部分功能都在后台服务器实现。
2.界面炫丽。使用网页可以达到很炫的效果,显示格式也非常好控制。
3.修改方便。基本上只需修改网页就可以了。
4.可扩展性强。一个设计好的browser可以使用不同风格的网页,如:加载youku看电影,加载土豆看电影(不过这比较困难,焦点通过遥控器的移动在网页中链接,输入框,button之间是一个非常困难的过程,嵌入式flash player很少)。
二.QtWebkit的优势以及使用
QtWebkit只是一个浏览器框架,其核心引擎时webkit,QtWebkit简单的归纳为webkit的显示界面,即表现层和逻辑层的关系。QtWebkit的优势在于:
1. 可移植性强。Linux,windows,embedded linux。
2. 对javascript支持比较好。
3. 对css支持比较全面。
4. 封装比较好,简单易用。
需要用到QtWebkit时,需要在编译QT源码的时候,在./configure 加上 –webkit,在编译自己的应用程序时,需要在.pro文件加上QT+=webkit,或者直接改Makefile加上-lQWebkit,简单的browser程序如下:
    int main(int argc, char* argv[])
{
    QApplication app(argc,argv);
    QWebview *view = new QWebview ();
    view->setGeometry(0,0,1024,1000);
    view->load(QUrl("www.baidu"));
    view->show();
    ();
}
3.通过键盘(遥控器)控制网页元素
通过使用QWebview,QWebFrame ,QWebPage类就基本上可以实现浏览器的所有功能,而我们重点关注是QWebElement这个类,该类封装了网页中element,即每个<a></a>就是一个QWebElement对象,不仅仅局限于<a/>,<b/>,<head/>等等都是一个QWebElement,而我们要通过遥控控制焦点的移动就需要调用 element.focus()(注:qt 4.6以后才有这个方法)。
举例说明:
需求:通过上下左右键来移动baidu中链接(即<a>元素),并改变相应链接的颜。
实现分析:利用QWebview加载baidu,然后将<a>标签全部提取出来,放在QWebElement list中,(注:需要加载网页成功后才开始提取,否则会出现提取不到。即当emit  signal loadFinished(bool)后才开始提取)。重写QWebview的keyPressEvent 函数,QWebview默认的上下左右键是当网页显示不下时滚动的处理,这点可通过源码以及默认的处理看出来,但可以通过tab键实现焦点移动,当收到上下左右键时可通过把按键事件改为Qt::Key_Tab键事件来实现焦点移动(示例程序不是通过这种方法)。
改变相应链接的颜有很多方法,暂列举2种:
1. 当焦点挪动时恢复原聚焦的元素的style,给现聚焦的元素加上新的style。
2. 自写一个通明控件,当焦点聚焦时将改空间放在元素对应的位置。
代码:
#include "browser.h"
#include <stdio.h>
browser::browser(QWidget * parent/* = 0 */):QWebView(parent)
{
    focusIndex = 0;
    frame=this->page()->currentFrame();
    frame->setScrollBarPolicy(Qt::Horizontal ,Qt::ScrollBarAlwaysOff);
    frame->setScrollBarPolicy(Qt::Vertical ,Qt::ScrollBarAlwaysOff);
    connect(this,SIGNAL(loadFinished(bool)),this,SLOT(loadPageFinish(bool)));
/* set webview no transparent */
    QPalette palette(QColor(255,0,0));
    this->setPalette(palette);
    this->setAttribute(Qt::WA_OpaquePaintEvent, false);
}电影网页设计代码
browser::~browser()
{
}
QString ed = "";
void browser::loadPageFinish(bool finish)
{
    if (finish)
    {
        focusIndex = 0;
        QWebFrame  *frame=this->page()->currentFrame();
        QWebElement  document=frame->documentElement();
        //printf("%s%s\n",ed.toLocal8Bit().data(),document.tagName().toLocal8Bit().data());
        //examineChildElements(document);
        elementList.clear();
        elementList = document.findAll("a").toList();
        if (elementList.size() > focusIndex)
        {
            QWebElement element;
            element = elementList.at(focusIndex);
            if (element.hasAttribute("style"))
            {
                preFocusStyle = element.attribute("style","");
            }
            element.setFocus();
            element.setAttribute("style", "background-color: #ff0000");
        }
    }
   
    /* set page transparent,so we can see view's background*/
    QPalette palette = this->palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    this->page()->setPalette(palette);
}
void browser::examineChildElements(const QWebElement &parentElement)
{
    ed += "  ";
    QWebElement element = parentElement.firstChild();
    while (!element.isNull())
    {
        printf("%s%s\n",ed.toLocal8Bit().data(),element.tagName().toLocal8Bit().data());
        if (element.hasFocus())
        {
            qDebug()<<element.tagName()<<"==============>";
        }
        if (PlainText() == QString("hao123"))
        {
            element.setAttribute("style", "background-color: #ff0000");
            element.setFocus();
        };
        examineChildElements(element);
        if (ed.length()> 2)
        {
            ed.remove(0,2);
        }
        element = Sibling();
    }
}
void browser::keyPressEvent(QKeyEvent * ev)
{
    switch (ev->key())
    {
        case Qt::Key_Right:
        case Qt::Key_Left:
        {
            if (elementList.size() > focusIndex)