QtWebView - 如何启用页面滚动和页面中元素的滚动(例如Google Maps)

Bob*_*Bob 5 c++ user-interface qt webkit qtwebkit

我遇到了一个与我公司为我们的产品线开发/维护的白名单Web浏览器有关的问题.浏览器在Qt 4.8.6之上运行,使用qtwebkit(迁移到5.X将是理想的,但我们使用的嵌入式Linux操作系统太旧了,无法根据我们的测试支持更新版本,并升级到更新版本操作系统对我们/我们的客户来说太昂贵了).浏览器的主要界面是一个6x8触摸屏,安装在飞机驾驶舱内.

对于具有可滚动/嵌入地图(例如Google地图)之类的网站,浏览器的用户希望能够在选择地图之外的内容时拖动整个页面,并仅拖动地图(不包括整个页面)滚动)当选择地图时(Ala大多数流行的移动浏览器).

到目前为止,我可以做其中一个,但不能两个:

  • 当我将鼠标处理程序挂钩到QWebView或QGraphicsWebView时,我可以将光标变成一只手,并且非常容易支持拖动整个网页.但是,当用户拖过地图时,这会抑制页面处理鼠标事件的能力(即,当用户拖动地图时,它会拖动整个页面而不移动地图).

  • 当我没有添加钩子来处理鼠标事件时,像地图这样的东西可以通过抓取/拖动它们来滚动,但当然用户失去了拖动整个页面的能力.

现在,浏览器使用后者,禁用滚动条和方向箭头覆盖以允许用户滚动整个页面(因为显示大小有限,当滚动条的大小足够大时,滚动条会占用太多空间用户与他们互动)...但这并不理想.

我的问题:是否有任何简单的方法可以使页面和页面中的元素无缝滚动?

谢谢!抢

Atl*_*e45 2

在我看来,您需要检查您是否在这样的地图上,并在这种情况下忽略(传递)该事件。我认为你应该能够做这样的事情:

bool GraphicsWebView::isOverMap(QPoint pos) {
    QWebPage* webPage = this->page();
    if (webPage) {
        QWebFrame* webFrame = webPage->frameAt(pos);
        if (webFrame) {
            QString selectorQuery = "#map-canvas"; // Based on https://developers.google.com/maps/tutorials/fundamentals/adding-a-google-map
            QList<QWebElement> list = webFrame->findAllElements(selectorQuery).toList(); // Find all the maps!

            foreach(QWebElement element, list) {
                if (element.geometry().contains(pos)) {
                    return true; // Cursor is over a map
                }
            }
        }
    }
    return false; // No match
}
Run Code Online (Sandbox Code Playgroud)

显然,这是一个非常具体的函数,但可能有一种方法可以提出更好的选择器查询,该查询将适用于所有这些类型的QWebElement.

假设您通过子类化QGraphicsWebView和重新实现来挂钩鼠标事件void mouseMoveEvent(QGraphicsSceneMouseEvent * event),我建议您执行以下操作:

bool GraphicsWebView::isOverMap(QPoint pos) {
    QWebPage* webPage = this->page();
    if (webPage) {
        QWebFrame* webFrame = webPage->frameAt(pos);
        if (webFrame) {
            QString selectorQuery = "#map-canvas"; // Based on https://developers.google.com/maps/tutorials/fundamentals/adding-a-google-map
            QList<QWebElement> list = webFrame->findAllElements(selectorQuery).toList(); // Find all the maps!

            foreach(QWebElement element, list) {
                if (element.geometry().contains(pos)) {
                    return true; // Cursor is over a map
                }
            }
        }
    }
    return false; // No match
}
Run Code Online (Sandbox Code Playgroud)

文档的这一部分解释了如何处理最顶层项目的事件。我特别建议你阅读第三段。

希望有帮助!

编辑:做了更多研究,看起来类似的东西可能更通用: graphicsView.focusItem()->flags().testFlag(QGraphicsItem::ItemIsMovable);

作为替代品,它至少值得研究isOverMap()

编辑:明白了,这是你可以尝试的事情。从子类化开始QGraphicsSceneMouseEvent,添加一个名为 的信号,void destroyedWithoutAccept()如果事件尚未被接受,则在析构函数中发出该信号。

然后修改 mouseMoveEvent 如下所示:

void GraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* event) {
    MyEvent myEvent = new MyEvent(event); // Copy event
    event.accept(); // accept original event
    connect(myEvent, SIGNAL(destroyedWithoutAccept),
            this, SLOT(handleMoveView)); // Callback if unused

    QGraphicsWebView::mouseMoveEvent(myEvent); // Pass it to Base class
}
Run Code Online (Sandbox Code Playgroud)

如果可行的话,如果使用deleteLater 来销毁它,可能会带来一点延迟。但在这种情况下,也要重新实现它。