如何解决QWebEngineView触摸滚动
我有一个从旧版Qt 4.7.4移植到Qt5的应用程序,据我了解,QWebView变成了QWebEngineView,并且在我使用FlickCharm的QWebView中,它在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://stackoverflow.com/a/42817245
任何人都知道如何在QWebEngineView上进行触摸滚动吗?
谢谢
编辑:由于RenderWidgetHostViewQtDelegateWidget是QWebEngineView的子级,因此我尝试从webEngineView-> children()访问它(如果可能的话,至少作为QWidget),但未成功,因为其唯一的子级是其QVBoxLayout(为空) )和FlickCharm。
解决方法
我终于在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,&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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。