QWebEngineView 触摸滚动
Posted
技术标签:
【中文标题】QWebEngineView 触摸滚动【英文标题】:QWebEngineView scroll with touch 【发布时间】:2020-09-30 07:20:29 【问题描述】:我有一个应用程序从旧的 Qt 4.7.4 移植到 Qt5,据我了解,QWebView 变成了 QWebEngineView,并且我使用 QWebView 使用了 FlickCharm,这是在 Qt 示例中,它仍然适用于 QScrollArea(例如QListWidget, QTableWidget, ...当然还有基本的 QScrollArea),但不再使用 QWebEngineView,这里是激活 FlickCharm 的代码,它在 Qt4 上工作:
void FlickCharm::activateOn(QWidget *widget, QWidget* p_viewport)
QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
if (scrollArea)
// Widget is a scroll area
QAbstractItemView *itemView = qobject_cast<QAbstractItemView*>(widget);
if(itemView)
itemView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
itemView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
QWidget *viewport = scrollArea->viewport();
if ( p_viewport )
viewport = p_viewport;
else
scrollArea->installEventFilter(this);
viewport->installEventFilter(this);
QHash<QWidget*, FlickData*>::iterator oldViewport;
if ( ( oldViewport = d->flickData.find(viewport) ) != d->flickData.end() )
delete oldViewport.value();
d->flickData.remove(viewport);
d->flickData[viewport] = new FlickData;
d->flickData[viewport]->widget = widget;
d->flickData[viewport]->state = FlickData::Steady;
d->flickData[viewport]->customViewPort = (viewport != scrollArea->viewport());
return;
QWebView *webView = qobject_cast<QWebView*>(widget);
if (webView)
// Widget is a web view
webView->installEventFilter(this);
QHash<QWidget*, FlickData*>::iterator oldViewport;
if ( ( oldViewport = d->flickData.find(webView) ) != d->flickData.end() )
delete oldViewport.value();
d->flickData.remove(webView);
d->flickData[webView] = new FlickData;
d->flickData[webView]->widget = webView;
d->flickData[webView]->state = FlickData::Steady;
return;
qWarning() << "FlickCharm only works on QAbstractScrollArea (and derived classes)";
qWarning() << "or QWebView (and derived classes)";
在 FlickData 类中有以下滚动功能:
bool scrollWidget(const int dx, const int dy)
QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
if (scrollArea)
const int x = scrollArea->horizontalScrollBar()->value();
const int y = scrollArea->verticalScrollBar()->value();
scrollArea->horizontalScrollBar()->setValue(x - dx);
scrollArea->verticalScrollBar()->setValue(y - dy);
return (scrollArea->horizontalScrollBar()->value() != x
|| scrollArea->verticalScrollBar()->value() != y);
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
const QPointF position = webEngineView->page()->scrollPosition();
const QPointF newPosition = position - QPointF(dx, dy);
webEngineView->page()->runjavascript(QString("window.scrollTo(%1, %2);").arg(newPosition.x()).arg(newPosition.y()));
return webEngineView->page()->scrollPosition() != position;
return false;
在 Qt5 中,我尝试像上面那样直接应用到 QWebEngineView:
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
webEngineView->installEventFilter(this);
QHash<QWidget*, FlickData*>::iterator oldViewport;
if ( ( oldViewport = d->flickData.find(webEngineView) ) != d->flickData.end() )
delete oldViewport.value();
d->flickData.remove(webEngineView);
d->flickData[webEngineView] = new FlickData;
d->flickData[webEngineView]->widget = webEngineView;
d->flickData[webEngineView]->state = FlickData::Steady;
return;
并且还尝试了我认为是视口的页面视图:
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
QWidget *viewport = webEngineView->page()->view();
webEngineView->installEventFilter(this);
viewport->installEventFilter(this);
QHash<QWidget*, FlickData*>::iterator oldViewport;
if ( ( oldViewport = d->flickData.find(viewport) ) != d->flickData.end() )
delete oldViewport.value();
d->flickData.remove(viewport);
d->flickData[viewport] = new FlickData;
d->flickData[viewport]->widget = webEngineView;
d->flickData[viewport]->state = FlickData::Steady;
return;
在 QWebEngineView::page() (即 QWebEnginePage)中,有一个 scrollPosition() 函数,但这是来自 Q_PROPERTY 但没有写访问器函数,但我发现代码和平可以使用我尝试使用的 javascript 滚动:
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
const QPointF position = webEngineView->page()->scrollPosition();
const QPointF newPosition = position - QPointF(dx, dy);
webEngineView->page()->runJavaScript(QString("window.scrollTo(%1, %2);").arg(newPosition.x()).arg(newPosition.y()));
return webEngineView->page()->scrollPosition() != position;
但是在添加了一些日志之后,我发现我从来没有为 QWebEngineView 传入 scrollWidget,并且,由于我有自己的类继承了实例化的 QApplication,我可以看到这不是直接单击的 QWebEngineView,而是 RenderWidgetHostViewQtDelegateWidget(以 QWebEngineView 作为父级),无法从任何地方访问,我看到这一点是因为我重新实现了 MyApplication::notify 以登录哪些小部件点击了:
bool MyApplication::notify(QObject* p_object, QEvent* p_event)
[...]
if ( p_event->type() == QEvent::MouseButtonPress )
QWidget* widget = dynamic_cast<QWidget*>(p_object);
if (widget != 0)
qDebug().nospace() << "Mouse pressed on [" << (widget->isEnabled() ? "enabled" :"disabled") << "] widget: "
<< p_object
<< ", parent: " << p_object->parent();
else
qDebug().nospace() << "Mouse pressed on object: " << p_object
<< ", parent: " << p_object->parent();
else if ( p_event->type() == QEvent::MouseButtonRelease )
QWidget* widget = dynamic_cast<QWidget*>(p_object);
if (widget != 0)
qDebug().nospace() << "Mouse release on [" << (widget->isEnabled() ? "enabled" :"disabled") << "] widget: "
<< p_object
<< ", parent: " << p_object->parent();
else
qDebug().nospace() << "Mouse release on object: " << p_object
<< ", parent: " << p_object->parent();
[...]
另外,当我尝试在 QWebEngineView 上滚动时,会选择文本。
这里是flickcharm的完整代码:https://doc.qt.io/archives/qt-4.8/qt-demos-embedded-anomaly-src-flickcharm-cpp.html
另外,我看到有一种解决方案可以使 WebEngineView 可滑动,但仅适用于 QtQuick QML:https://***.com/a/42817245
有人知道如何在 QWebEngineView 上进行触摸滚动吗?
谢谢
编辑:由于 RenderWidgetHostViewQtDelegateWidget 是 QWebEngineView 的子级,我尝试从 webEngineView->children() 访问它(至少作为 QWidget,如果可能的话)但没有成功,因为它唯一的子级是它的 QVBoxLayout(即为空) 和 FlickCharm。
【问题讨论】:
你忘了问问题。 谢谢,我更改了“如果有人能提供帮助,我会很高兴。”到“任何人都知道如何在 QWebEngineView 上进行触摸滚动?” 【参考方案1】:我终于设法在 FlickCharm::activateOn 中为 QWebEngineView 做我想做的事:
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
QLayout* webEngineViewLayout = webEngineView->layout();
QWidget* webEngineViewChildWidget = 0;
for (int i = 0; i < webEngineViewLayout->count(); ++i)
webEngineViewChildWidget = qobject_cast<QWidget*>(webEngineViewLayout->itemAt(i)->widget());
if (webEngineViewChildWidget != nullptr)
// There should be only one QWidget under QWebEngineView, but break just in case
break;
if (webEngineViewChildWidget != nullptr)
// Install event filter on widget found in QWebEngineView layout
webEngineViewChildWidget->installEventFilter(this);
QHash<QWidget*, FlickData*>::iterator oldViewport;
if ( ( oldViewport = d->flickData.find(webEngineViewChildWidget) ) != d->flickData.end() )
delete oldViewport.value();
d->flickData.remove(webEngineViewChildWidget);
d->flickData[webEngineViewChildWidget] = new FlickData;
d->flickData[webEngineViewChildWidget]->widget = webEngineView;
d->flickData[webEngineViewChildWidget]->state = FlickData::Steady;
else
// Web engine view has not yet a page loaded, activate "again" when a page has been loaded
connect(webEngineView, &QWebEngineView::loadFinished, this, &FlickCharm::ReactToWebEngineViewLoaded);
return;
而FlickCharm::ReactToWebEngineViewLoaded()
是:
void FlickCharm::ReactToWebEngineViewLoaded()
QWebEngineView* webEngineView = qobject_cast<QWebEngineView*>(sender());
if (webEngineView != nullptr)
// We need to pass only once there then we can disconnect now
disconnect(webEngineView, &QWebEngineView::loadFinished, this, &FlickCharm::ReactToWebEngineViewLoaded);
// Activate "again" so that view actually uses flick charm
activateOn(webEngineView);
else
LOG_ERROR("Web engine view is NULL");
assert(webEngineView != nullptr);
当然 void ReactToWebEngineViewLoaded()
在 flickcharm.h 中声明为插槽。
在FlickData::scrollWidget
中用于 QWebEngineView (这很棘手,我不喜欢 qApp->processEvents 调用,但如果我们想实际比较函数返回的值,它们是强制性的):
QWebEngineView *webEngineView = qobject_cast<QWebEngineView*>(widget);
if (webEngineView)
webEngineView->page()->runJavaScript(QString("window.scrollBy(%1, %2);").arg(-dx).arg(-dy));
return true;
【讨论】:
以上是关于QWebEngineView 触摸滚动的主要内容,如果未能解决你的问题,请参考以下文章