Jump to content
Faalamva

[SOLVED] [IE.au3] How to "refresh" elements coordinates after the first use of _IECreate ?

Recommended Posts

Faalamva

Hi,

I'm using the IE.au3 library to parse elements in a webpage and get their (x,y) coordinates.

Main commands I'm using are :         

$oIE = _IECreate($myWebPage)

$oElements = _IETagNameGetCollection($oIE, "label")

$windowleft = $oIE.document.parentwindow.screenLeft
$windowtop = $oIE.document.parentwindow.screenTop

$oElementPosX = $windowleft + _IEfindPosX($oElement)
$oElementPosY = $windowtop + _IEfindPosY($oElement)

Now things become a bit tricky when i simulate a scroll in my webpage :

$oIE.document.parentwindow.scroll(0, $myScrollY)

Because once this is done, the coordinates of the elements are still what they were before the scroll.

I can manage this problem by keeping track of the number of pixels I have scrolled, and compute the new "real" ($oElementPosX, $oElementPosY).

But I'm pretty sure there's a more efficient / more elegant way to do it.

What's more in some situations, when I click some controls in the webpage, the webpage adds new elements and shifts the controls below by a random number of pixel, so my workaround can't be used...

So here's my question : Is there a way to "refresh" the calculation of label coordinates ($oElementPosX, $oElementPosY) after a scroll ?

Thank you !

EDIT : I forgot to post the _IEfindPosX and _IEfindPosY functions (found somewhere on this forum) :

Func _IEfindPosX($o_object)
    Local $curleft = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curleft += $parent.offsetLeft
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objx = $o_object.x
        If IsObj($objx) Then $curleft += $objx
    EndIf
    Return $curleft
EndFunc

Func _IEfindPosY($o_object)
    Local $curtop = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curtop += $parent.offsetTop
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objy = $o_object.y
        If IsObj($objy) Then $curtop += $objy
    EndIf
    Return $curtop
EndFunc

 

Edited by Faalamva

Share this post


Link to post
Share on other sites
Faalamva
26 minutes ago, l3ill said:

Cant you just rerun the function you used to find them the first time ?

Thank you for your answer, unfortunately, I've already tried and it doesn't work.

Here is a full example to illustrate my problem. Just copy/paste and run it and you'll understand what I'm trying to achieve.

 

#include <IE.au3>

; ----------------------------------------------------------------------
; Main
; ----------------------------------------------------------------------

$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("","",@SW_MAXIMIZE)

$windowleft = $oIE.document.parentwindow.screenLeft
$windowtop = $oIE.document.parentwindow.screenTop
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        $oElementPosX = $windowleft + _IEfindPosX($oElement)
        $oElementPosY = $windowtop + _IEfindPosY($oElement)
        MsgBox(0, "", "Mouse will be moved to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    EndIf
Next

MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)

; Trying to "refresh the elements positions" --> it doesn't work
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        $oElementPosX = $windowleft + _IEfindPosX($oElement)
        $oElementPosY = $windowtop + _IEfindPosY($oElement)
        MsgBox(0, "", "Mouse will be moved again to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    EndIf
Next

MsgBox(0, "", "Positions of webpage elements haven't been refreshed, the mouse was moved to the former EXERCISE position...")

; ----------------------------------------------------------------------
; Functions
; ----------------------------------------------------------------------

Func _IEfindPosX($o_object)
    Local $curleft = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curleft += $parent.offsetLeft
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objx = $o_object.x
        If IsObj($objx) Then $curleft += $objx
    EndIf
    Return $curleft
EndFunc

Func _IEfindPosY($o_object)
    Local $curtop = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curtop += $parent.offsetTop
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objy = $o_object.y
        If IsObj($objy) Then $curtop += $objy
    EndIf
    Return $curtop
EndFunc

 

Share this post


Link to post
Share on other sites
l3ill

Sorry, no answers just some info; I added some error checking and it would seem that your If statement is not working correctly.

Spoiler
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

Local $windowleft = $oIE.document.parentwindow.screenLeft
Local $windowtop = $oIE.document.parentwindow.screenTop
Local $oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        MsgBox(0, "Success", "EXERCISE found in 'InnerText'")
        Local $oElementPosX = $windowleft + _IEfindPosX($oElement)
        Local $oElementPosY = $windowtop + _IEfindPosY($oElement)
        ConsoleWrite("$oElementPosX = " & $oElementPosX & @CRLF)
        ConsoleWrite("$oElementPosY = " & $oElementPosY & @CRLF)
        MsgBox(0, "", "Mouse will be moved to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    Else
        MsgBox(0, "error", "Something went wrong here...")
    EndIf
Next

MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)

; Trying to "refresh the elements positions" --> it doesn't work
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        MsgBox(0, "Success", "EXERCISE found in 'InnerText'")
        Local $oElementPosX = $windowleft + _IEfindPosX($oElement)
        Local $oElementPosY = $windowtop + _IEfindPosY($oElement)
        ConsoleWrite("$oElementPosX = " & $oElementPosX & @CRLF)
        ConsoleWrite("$oElementPosY = " & $oElementPosY & @CRLF)
        MsgBox(0, "", "Mouse will be moved again to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    Else
        MsgBox(0, "error", "Something went wrong here...")
    EndIf
Next
MsgBox(0, "", "Positions of webpage elements haven't been refreshed, the mouse was moved to the former EXERCISE position...")

You should take a closer look at how your Functions are being called. It also good practice to use Local or Global when defining variables.

 

Share this post


Link to post
Share on other sites
Faalamva

Your example won't work, it will display

"Something went wrong here..."

everytime the element checked isn't "EXERCISE".

Please remember that this is just an example I wrote in a few minutes to illustrate the case, it may not be state-of-the-art of course.

But it's working as a standalone program, just copy/paste and run it to see by yourself.

Let's stick to the topic please :)

Edited by Faalamva

Share this post


Link to post
Share on other sites
l3ill

Understood..

A simple test reveals that your website does not have the .innerText element you are trying to use:

From the Help File:

#include <IE.au3>
#include <MsgBoxConstants.au3>

;~ Local $oIE = _IE_Example("basic")
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")

Local $oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    If $oElement.id Then MsgBox($MB_SYSTEMMODAL, "Element Info", "Tagname: " & $oElement.tagname & @CRLF & "id: " & $oElement.id & @CRLF & "innerText: " & $oElement.innerText)
Next

_IEQuit($oIE)

Without the error checking your script is finding mouse coordinates one time but the rest of the code is skipping through (aka: not working)

If you have access to the code from your page I would suggest giving the 'EXERCISE' header (or whatever) its own .id and then write your code to pick up on that element.


<h4 id="myHeader">Exercise</h4>

My $0.02 ...

Good luck o:)

 

Share this post


Link to post
Share on other sites
Faalamva
#include <IE.au3>
#include <MsgBoxConstants.au3>

;~ Local $oIE = _IE_Example("basic")
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")

Local $oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    ConsoleWrite("Tagname: " & $oElement.tagname & @CRLF & " id: " & $oElement.id & @CRLF & " innerText: " & $oElement.innerText & @CRLF)
Next

_IEQuit($oIE)

Result in console :

Quote

...

Tagname: H4
 id:
 innerText: EXERCISE

...

We're still drifting away from topic... :(

Edited by Faalamva

Share this post


Link to post
Share on other sites
l3ill

No, your right. Never mind all that.

It is more difficult than I had hoped. Your coordinate variables are staying in memory for some reason and zeroing them out didn't work.

Sorry couldn't help.

...all the smart people have gone to bed...:P

might have to wait until tomorrow :'(

Share this post


Link to post
Share on other sites
Chimp

... try this:

#include <IE.au3>
; ----------------------------------------------------------------------
; Main
; ----------------------------------------------------------------------
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

$oElement = _IETagNameGetCollection($oIE, 'H4', 0)
MouseMove($oElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $oElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

MsgBox(0, "", "Let's scroll the webpage 200 pixels down", 2)
$oIE.document.parentwindow.scroll(0, 200)
MouseMove($oElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $oElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

MsgBox(0, "", "caught!", 2)
$oElement.style.setAttribute('border', '5px solid red') ; draw a red border (just for fun)

 

Edited by Chimp
  • Like 1

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites
Faalamva

Very interesting Chimp, it seems we're heading in the right direction :lol: !

EDIT : I managed to adapt your code to get exactly what I need (i.e. using displayed labels instead of "H4") :

#include <IE.au3>

$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

Local $myElement
$oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then $myElement = $oElement
Next

MsgBox(0, "", "Let's locate EXERCISE")
MouseMove($myElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $myElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)
MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)
MsgBox(0, "", "Let's locate EXERCISE again")
MouseMove($myElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $myElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

EDIT 2 : Tested "for real" in dynamic webpages. Works perfectly, and much simpler/shorter than the original code.

Case solved, thank you ! :)

Edited by Faalamva

Share this post


Link to post
Share on other sites
Chimp
2 hours ago, Faalamva said:

......

Case solved, thank you ! :)

You are welcome... ;)


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • MakzNovice
      By MakzNovice
      Hello Experts,
      I am working on modifying table data of a browser currently in IE (soon in FF)
      My sequence of operations:
      1. Activate Browser
      2. Get Browser table
      3. Modify data  in table
      4. Suppress any warning/error message from webpage
      5. Activate the Webpage again 
      6. Send {F11} key sequence twice to achieve some update without Updating form ( {F5})
       
      My problem is at Step 5, as it activates the wrong window ( last used application rather than my browser window)
      My code snippet for it as follows
      $bFoundWindow = False Local $aList = WinList("[REGEXPTITLE:(?i)(.*Internet Explorer.*)]") Local $hWND = 0 For $i = 1 To $aList[0][0] If False = $bFoundWindow And $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 1) Then WinActivate($aList[$i][1]) ; 1. Activate Browser window WinSetState ( $aList[$i][1], "", @SW_MAXIMIZE) $hWND = $aList[$i][1] $objEditIE = _IEAttach ($aList[$i][1], "hwnd") $oTitles = _IETagNameGetCollection($objEditIE, "TITLE") For $oTitle In $oTitles $sTitle = $oTitle.innerText If $sTitle = $searchString Then MsgBox(0,"APPLICATION Found", "Got Edit List Window", 1) $bFoundWindow = True ExitLoop EndIf Next EndIf Next If False = $bFoundWindow Then MsgBox(0,"Error","Please launch Edit window for updating values in Browser prior to script execution",10) Exit EndIf ; MY CODE HERE TO MODIFY TABLE ; 2. Get Browser table ; 3. Modify data  in table ; Check if message from webpage pop-up window exists if so click ok on it Local $nCounter = 0 Local $nMaxCounter = 5 while 1 If WinExists("Message from webpage","") Then ControlClick("Message from webpage","","Button1","primary",1) ;4. Suppress any warning/error message from webpage Else $nCounter = $nCounter + 1 Sleep(100) ;MsgBox(0,"Counter", $nCounter, 1) If $nCounter = $nMaxCounter Then ExitLoop EndIf WEnd ;5. Activate the Webpage again  WinActivate($hWND) ; have already tried WinActivate($aList[$i][1]) but no success ;6. Send {F11} key sequence twice to achieve some update without Updating form ( {F5}) Send("{F11}") WinActivate($hWND) ;WinActivate($aList[$i][1]) Sleep(100) Send("{F11}") Any support will be highly appreciated
    • MakzNovice
      By MakzNovice
      Hello Experts,
      I am working on custom application details of which I am unable to share.
      But here is statement of my problem, I have two IE windows one window with Title "Parent " and other with "TableEdit", but for some reason when I get WinList they are shown as 2 processes each. ( see attached image)
      Since my most important motive is to modify table data in 'TableEdit' I try to access the table in it
      My code snippet is 
      ***********************************************************************************************
      $searchString = "TableEdit"
      Local $aList = WinList("[REGEXPTITLE:(?i)(.*Internet Explorer.*)]")
      _ArrayDisplay($aList)
      For $i = 1 To $aList[0][0]
          If $aList[$i][0] <> "" And BitAND(WinGetState($aList[$i][1]), 2) Then
              ;MsgBox($MB_SYSTEMMODAL, "", "Title: " & $aList[$i][0] & @CRLF & "Handle: " & $aList[$i][1])
              If 0 <> StringInStr($aList[$i][0],"TableEdit") Then
                  $objEditIE = _IEAttach ($aList[$i][1])
                  ExitLoop
              EndIf
          EndIf
      Next
      WinActivate($objEditIE)
      $oPageContentListFrame = _IEFrameGetObjByName($objEditIE, "iframe_1")
      $iNumFrames = @extended
      MsgBox(0,"Got pagecontent",@error) ; returns 3, indicating invalid data type
      MsgBox(0,"Number of Frame",$iNumFrames) ; returns 1, expected value is 1 
      ***********************************************************************************************
      and If I do code as below the return value is different
      $searchString = "TableEdit"
       $objEditIE = _IEAttach ($searchString, "title")
      WinActivate($objEditIE)
      $oPageContentListFrame = _IEFrameGetObjByName($objEditIE, "iframe_1")
      $iNumFrames = @extended
      MsgBox(0,"Got pagecontent",@error) ; returns 0
      MsgBox(0,"Number of Frame",$iNumFrames) ; returns 0. expected value is 1
      ***********************************************************************************************
      What is wrong with my code? 
      Why do I see two process each for IE for each window?
       
      WinListImage.bmp
    • SteveStrop
      By SteveStrop
      Hi 
       
      I'm trying to:
      1) Open a hidden browser session
      2) Do some stuff in the background
      3)  Make the hidden window visible
       
      This is my code:
       
      Opt("WinTitleMatchMode", 2) ;1=start, 2=subStr, 3=exact, 4=advanced, -1 to -4=Nocase $oIE = _IECreate("https://www.google.co.uk/",0,0) $oSearchBox = _IEGetObjById($oIE, "lst-ib") $oSearchBox.innertext = "AutoIT" $oForm = _IEFormGetObjByName($oIE,"f") _IEFormSubmit($oForm) WinSetState("Google","",@SW_SHOW)  
      It dosen't work
      The last line does make the window visible but it is an empty greyed out box that disappears as soon as I click on it.
      I have a sort of workaround that hides the browser window as soon as I have created it which works fine:
      $oIE = _IECreate("https://www.google.co.uk/") WinSetState("Google","",@SW_HIDE) . . . WinSetState("Google","",@SW_SHOW) But this looks a bit pants as the newly created window flashes on then off of the screen.
      Am I using the wrong method to make the browser window visible?
      Thanks
       
       
    • Tippex
      By Tippex
      I have a problem trying to use _IEAttach to recover control after a Windows Explorer reset (e.g. on Windows 7), since all the 
      InternetExplorer.Application objects appear to be destroyed by this event. An example of this is when a PC has some kind of fault causing a pop-up error message "Windows Explorer has stopped working". I can simulate this event by using Windows Task Manager to end the Explorer.exe process then to file, new task (run...) Explorer.exe
      After this event, _IEAttach gives an @error of: 
      7 ($_IEStatus_NoMatch) - No Match
      However, using WinList() followed by WinGetText() I can recover the URL for an IE session that has lost its 
      InternetExplorer.Application object which could be used to _IECreate a new session (the $iTryAttach fails) and WinKill() the original session but the result is a if a refresh had been done (any form entries are lost) . Unfortunately form entries do not appear as text or hidden text to Windows so I'm looking for the best way to read the contents of an Internet Explorer screen (even if just text without structure). 
      When there is no InternetExplorer.Application object (because of some Windows fault) but still with an Internet Explorer session running, I tried to read its contents by a "Select All" & "Copy to Clipboard" but its form entries are blanked and combo boxes choices are all displayed with no way of finding out which ones were selected.
      Local $ClipBoardSave = _ClipBoard_GetData() ;not ClipGet() which is text only ClipPut("") ;Clear User's Clipboard Local $sText = "" Local $hWnd = WinActivate("Window Title", "") If IsHWnd($hWnd) Then Local $bStatusCtrlSend = ControlSend("Window Title", "", "", "^a^c") If $bStatusCtrlSend Then Local $bStatusCtrlClick = ControlClick("Window Title", "", "") If $bStatusCtrlClick Then $sText = ClipGet() _ClipBoard_SetData($ClipBoardSave) ;not ClipPut($ClipBoardSave) which is text only  
      Is  there a solution to this please?
    • AnonymousX
      By AnonymousX
      Hello,
      I need to pull data from company intranet website. I created a script that I can give a list of project numbers and it will open up the the related webpage for each project, save the html comments for that project, then move on to the next. 
      However my problem comes in that each time I open up a project it locks it for other users, and if you just exit the page it keeps it locked, you have to actually press the "close" button on the page. So I'm not sure how to deal with this as I end up just locking every project in my name when I run my program as I don't understand the nature of how the website is built. I don't understand how to close with just using my automation code without manually having to press the stupid button. 
      My Function:
      Func Getscript($ProjectAddress) ;getting the page source code and storing it into text file for easy reading it $file = FileOpen(@ScriptDir & "\source.txt", 10) $IE = _IECreate($ProjectAddress & ".html", 0, 0) $source = _IEDocReadHTML($IE) FileWrite($file, $source) $target_source = _StringBetween($source, "<BODY>", "</BODY>") ; only take content between the specified tags _IEQuit($IE) FileClose($file) return $target_source[0] EndFunc ;==>Getscript  
      Source Code I got from website that I think is relevant:
      function closeForm(){ if(topButtonEnabled("closeButton")){ parent.mainFrame.closeForm(); } } <button id="closeButton" class="saveCloseButton" style="LEFT: 77px;" onclick=closeForm()>&nbsp;Close&nbsp;</button>  
      Any Ideas of how to tell website to either activate the closeform function or just give it the command to close?
       
      Thanks
×