Qt: Force QWebView to click on a web element, even one not visible on the window
Asked Answered
G

3

7

So let's say I'm trying to click a link in the QWebView, here is what I have:

// extending QWebView
void MyWebView::click(const QString &selectorQuery)
{
    QWebElement el = this->page()->mainFrame()->findFirstElement(selectorQuery);
    if (!el)
         return;

    el.setFocus();

    QMouseEvent pressEvent(QMouseEvent::MouseButtonPress, el.geometry().center(), 
                    Qt::MouseButton::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QCoreApplication::sendEvent(this, &pressEvent);

    QMouseEvent releaseEvent(QMouseEvent::MouseButtonRelease, 
                             el.geometry().center(), Qt::MouseButton::LeftButton,
                             Qt::LeftButton, Qt::NoModifier);
    QCoreApplication::sendEvent(this, &releaseEvent);
}

And you call it as so:

myWebView->click("a[href]");  // will click first link on page
myWebView->click("input[type=submit]"); // submits a form

THE ONLY PROBLEM IS: if the element is not visible in the window, it is impossible to click. What I mean is if you have to scroll down to see it, you can't click it. I imagine this has to do with the geometry, since the element doesn't show up on the screen it can't do the math to click it right.

Any ideas to get around this? Maybe some way to make the window behave like a billion x billion pixels but still look 200x200?

Garber answered 16/4, 2010 at 18:52 Comment(0)
C
7

I think calling el.evaluateJavaScript("click()"); should work. I say should work because in the past I've been using QWebElement::function() with "click" argument with success. This method did not become part of QWebElement API, however. I think authors came to conclusion it was superfluous in presence of QWebElement::evaluateJavaScript().

My similar question - How to follow a link in QWebKit? - still without answer :(
I came up with the same workaround like you here - Problem with evaluateJavaScript()

Casteel answered 17/4, 2010 at 1:15 Comment(0)
M
7

Hi I know this question is quite old, but I wanted to offer a different answer. You said: "...since the element doesn't show up on the screen it can't do the math to click it...". Well, "it" can not do the math, but "You" can. ;) You can get the position of the element you want to click on and calculate how many pixels (X) you need to scroll down/up in order to make it visible. Then you can auto scroll the page by X pixels and use the X value to calculate the current position of the element and click there. The same logic is used if you have to scroll left or right too. Just use Y pixels as a horizontal correction value. I've done this in another language and I know it is doable and works fine. :)

EDIT: (Feb 21 2013)

OK, I had to do this for one of my projects too. So to illustrate what I meant above, below is the Qt code. I realize it has some flaws, especially if you are dealing with small elements around the page edges, but in most cases it works just fine.

(in the code below *elemt is the element you want to click on and *web is the QWebView widget)

QRect elGeom=element->geometry();
QPoint elPoint=elGeom.center();
int elX=elPoint.x();
int elY=elPoint.y();
int webWidth=web->width();
int webHeight=web->height();
int pixelsToScrolRight=0;
int pixelsToScrolDown=0;
if (elX>webWidth) pixelsToScrolRight=elX-webWidth+elGeom.width()/2+10; //the +10 part if for the page to scroll a bit further
if (elY>webHeight) pixelsToScrolDown=elY-webHeight+elGeom.height()/2+10; //the +10 part if for the page to scroll a bit further
web->page()->mainFrame()->setScrollBarValue(Qt::Horizontal,pixelsToScrolRight);
web->page()->mainFrame()->setScrollBarValue(Qt::Vertical,pixelsToScrolDown);
QPoint pointToClick(elX-pixelsToScrolRight,elY-pixelsToScrolDown);

QMouseEvent pressEvent(QMouseEvent::MouseButtonPress,pointToClick,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QCoreApplication::sendEvent(web, &pressEvent);
QMouseEvent releaseEvent(QMouseEvent::MouseButtonRelease,pointToClick,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QCoreApplication::sendEvent(web, &releaseEvent);

This is what works for me, when the java click fails. I hope it will be useful to someone else too.

Myrt answered 4/2, 2013 at 9:5 Comment(1)
Awesome! For the ones that run their QWebPage on the background (and thus they do not have a QWebView), using webPage.currentFrame()->documentElement().geometry() for getting the web->width() and web->height() will work as well!Trawl
K
1

For those who want to click on Webview button then do these

frame1->evaluateJavaScript( "document.forms[0].submit();" ); 
Kolyma answered 26/6, 2012 at 15:47 Comment(1)
OK answer, may be some explanation?Gustav

© 2022 - 2024 — McMap. All rights reserved.