Modify

Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#64 closed Feature Request (Rejected)

Enhance special description for recognizing controls

Reported by: junkew@… Owned by:
Milestone: Component: AutoIt
Version: Severity:
Keywords: Cc:

Description

Actually 2 request(s) to combine and not yet sure whats most logical place to do (part can be done in a UDF)

"[CLASS:Edit; INSTANCE:1]" is a real powerfull way of recognizing controls.
I would like to see this enhanced with more possibilities like

  • using any property that is available in Window Info tool
  • using more advanced logic like "[CLASS:*Edit*; INSTANCE:1]" regular expression syntax "[VIRTUALAREA: (Square|Circle) x1,x2,y1,y2 (RelativeWindow|RelativeClient|Desktop)]" If its not a control but a certain area which is hard to recognize (would be nice if you can select the area of interest with window info tool which you then in your script can use just as if its a control but actually is not) "[CLASS:Edit; INSTANCE:1; TABS: n]" where TABS means send n TABS to activate next control (also for lauzy unrecognizable controls due to not beeing native windows controls) n can be negative. "[BITMAP: name" search the window with bitblt or similar function till matching area is found and then use this area to act on just like its a control, name is filename/location of bitmap to use (which was previously saved with capturing tool)).
  • Have a translation table for logical and technical naming Logical name: Notepad text area Technical name: "[CLASS:Edit; INSTANCE:1]"

Then use in ControlSend("Untitled - Notepad", "", "Notepad text area", "This is some text")
Where then logical name is translated to technical name

  • Translation table should have ability of grouping/hierarchy of logical names. For example

Logical Technical
01.Calculator screen "[CLASS:SciCalc; INSTANCE:1]"
+---> 01.result "[CLASS:Edit; INSTANCE:1]"
+---> 02.btnOne "[CLASS:Button; ID:125]"
02.Paint "[CLASS:MSPaintApp; INSTANCE:1]"
+---> 01.Paintarea "[CLASS:Afx:1000000:8; INSTANCE:1]"
+---> 02.Paintarea duplicate "[CLASS:Afx:1000000:8; INSTANCE:1]"
03.Calculator screen 2 "[CLASS:SciCalc; INSTANCE:1]"
+---> 01.result "[CLASS:Edit; INSTANCE:1]"

Duplicates on technical level should be allowed as the main purpose is to have logical names that can be used in the scripting itself.
Actually I put something like above now in an array at start of my script and have a lookup UDF but this is a tedious job (but is better maintainable instead of having all the technical names scattered in my script)

  • Integrate this in Window Info tool
  • Have in window info tool a way to predefine for each Class which properties should be combined to create special description.

So if I select notepad text window which is of Class Edit that I immediately can copy "[CLASS:Edit; INSTANCE:1]" instead of typing it in myself in my script.

I think above will be a major enhancement and gives even more possibilities for AutoIt to be used in testautomation situations and will reduce maintenance on scripting

Attachments (0)

Change History (10)

comment:1 follow-up: Changed 11 years ago by Valik

Only 3 of the suggestions make sense. The regex class name has already been suggested, though it may only be on the forum. Finding a control by it's size/position makes some sense. Having Au3Info show properly formatted strings also makes sense.

The other ideas are bad, however.

You can't find a control by tabbing without determining where focus is in the first place. And even then, only the user knows how far they need to tab from that point to get where they want to go. In theory, tabbing sounds great until you realize that if the current focus is off by even one control then it's a completely flawed mechanism.

Finding a control by bitmap is only slightly more useful than hard-coding an HWND. The control, depending on type, is going to look different depending on a large number of factors. A control may have a focus rectangle. A control may look different in a different theme. A control may have different text.

Lastly, a lookup table is rejected right off the bat because it would require a new flag to enable. The current syntax is different enough from anything else that user's will ever need to search for that the context is automatically determined. Never mind the fact that the lookup table provides a vastly complicated interface that's not really going to clear matters up.

comment:2 in reply to: ↑ 1 ; follow-up: Changed 11 years ago by anonymous

Replying to Valik:

You can't find a control by tabbing without determining where focus is in the first place. And even then, only the user knows how far they need to tab from that point to get where they want to go. In theory, tabbing sounds great until you realize that if the current focus is off by even one control then it's a completely flawed mechanism.

The user is in my opinion the programmer that creates the script and understands the application with expected behavior. If its not conforming to the behavior its a finding of the script that then should be analysed.
"[CLASS:Edit; INSTANCE:1; TABS: n]" means first find "[CLASS:Edit; INSTANCE:1" and after that do n tabs forward/backward just to make less dependency on changing userinterface. Actually what I want goes even much further. If you are able to make things more relative instead of hard coded maintenance decreases in your scripting.
But this is also in combination with a lookup table.
Lets say you have a screen with 4 Editcontrols where you can enter: Name, Street, ZIP Code, City and they are like "[CLASS:Edit; INSTANCE:1" thru "[CLASS:Edit; INSTANCE:4]" wouldn't it be great when I have the lookuptable
Name --> "[CLASS:Edit; INSTANCE:1"
Street --> Name:INSTANCE+1
ZIP Code --> Street:INSTANCE+1
CITY --> ZIP code:INSTANCE+1

Now if somebody decides to add control for housenumber I only have to change
Housenumber --> Street:INSTANCE+1
ZIP Code --> Housenumber:INSTANCE+1

Although I have to think about a more logical/readable syntax this saves me a lot of changing especially if there are 30+ Editboxes on a screen and someone adds 1 in the beginning of the screen.

Finding a control by bitmap is only slightly more useful than hard-coding an HWND. The control, depending on type, is going to look different depending on a large number of factors. A control may have a focus rectangle. A control may look different in a different theme. A control may have different text.

Although I agree with the statements made its much better than not beeing able to do anything with the non recognizable control. It doesn't have to be perfect and ability to handle different themes is not required. In >80% of cases you know for unrecognisable controls a lot of information.
Main feature request is: have ability to find and define a certain area (rectangle or circle/oval) where you can send analog mouseactions and keyboard actions to. Finding an area could be done initally with a picture/bitmap and later on only the area is relevant to remember and send mouseactions to.

Lastly, a lookup table is rejected right off the bat because it would require a new flag to enable. The current syntax is different enough from anything else that user's will ever need to search for that the context is automatically determined. Never mind the fact that the lookup table provides a vastly complicated interface that's not really going to clear matters up.

I do not agree in this area see below for some straightforward UDF
Would be nice if I could code like
"[LOGICALNAME:01.Result" which then would lead to a lookup triggering function.

Lookup file (control.map)

	Group
	01.Calculator	    | Rekenmachine
	01.Result           | [CLASS:Edit; INSTANCE:1]
	03.btn7		    | [CLASS:Button; TEXT:7]
	Group
	01.OfficeNet Direct | OfficeNet Direct
	01.naam		    |
	02.Afkorting        | [CLASS:Edit; INSTANCE:2]
	03.Contractnummer   | [CLASS:PBEDIT80; INSTANCE:3]
	12.btnToepassen     | [CLASS:Button; TEXT:&Toepassen]
	Group
	01.OfficeNet Direct | OfficeNet Direct
	01.Treeview         | [CLASS:PBTreeView32_80; INSTANCE:1]
	Group
	01.Aanlogscherm	    | Aanloggen OfficeNet Direct
	01.Naam		    | [CLASS:Edit; INSTANCE:3]
	02.Wachtwoord       | [CLASS:Edit; INSTANCE:2]
	03.btnOK            | [CLASS:Button; TEXT:&Ok]
	04.Annuleren        | [CLASS:Button; TEXT:&Annuleren]
	05.help             | [CLASS:Button; ID: 1002]

Source code to load control map

dim $objArray[40][15]


func LoadControlMap()
	$file=fileopen(@scriptdir & "\control.map",0)

; Check if file opened for reading OK
If $file = -1 Then
    MsgBox(0, "Error", "Unable to open file.")
    Exit
EndIf

; Read in lines of text until the EOF is reached
$i=-1
While 1
	
    $line = FileReadLine($file)
    If @error = -1 Then exitLoop

	$line = stringstripws($line,3)
	
    if $line = "Group" Then
		$i=$i+1
		$line = FileReadLine($file)
		$array=stringsplit($line,"|")
		$objArray[$i][0]=stringstripws($array[1],3)
		$objArray[$i][1]=stringstripws($array[2],3)
		$j=2
	Else
		$array=stringsplit($line,"|")
		$objArray[$i][$j]=stringstripws($array[1],3)
		$objArray[$i][$j+1]=stringstripws($array[2],3)
		$j=$j+2
	endIf
		
Wend

FileClose($file)

EndFunc

UDF to translate between logical and technical name

func getControl($objWindowName, $objLogicalName)
	for $i = 0 to ubound($objArray,1)-1 step 1
		if $objArray[$i][0] = $objWindowName Then	
		  $wName = $objArray[$i][1]
		  for $j=2 to ubound($objarray,2)-1 step 1
		    if $objArray[$i][$j]=$objLogicalName Then	
		      return $objArray[$i][$j+1]
		    EndIf
		  Next
		EndIf
	next
	
	return ""

EndFunc

Sample usage

        dim $wName ; Window to act on
        dim $c     ; Control to act on
        Loadcontrolmap()
        $c=getControl("01.Calculator", "03.btn7")
  	winactivate($wName)
       	ControlFocus($wName, "", $c)
	ControlClick($wName, "", $c, "left",1,1,1)

comment:3 in reply to: ↑ 2 ; follow-up: Changed 11 years ago by anonymous

Replying to anonymous:

Replying to Valik:
The user is in my opinion the programmer that creates the script and understands the application with expected behavior. If its not conforming to the behavior its a finding of the script that then should be analysed.
"[CLASS:Edit; INSTANCE:1; TABS: n]" means first find "[CLASS:Edit; INSTANCE:1" and after that do n tabs forward/backward just to make less dependency on changing userinterface. Actually what I want goes even much further. If you are able to make things more relative instead of hard coded maintenance decreases in your scripting.
But this is also in combination with a lookup table.
Lets say you have a screen with 4 Editcontrols where you can enter: Name, Street, ZIP Code, City and they are like "[CLASS:Edit; INSTANCE:1" thru "[CLASS:Edit; INSTANCE:4]" wouldn't it be great when I have the lookuptable
Name --> "[CLASS:Edit; INSTANCE:1"
Street --> Name:INSTANCE+1
ZIP Code --> Street:INSTANCE+1
CITY --> ZIP code:INSTANCE+1

Now if somebody decides to add control for housenumber I only have to change
Housenumber --> Street:INSTANCE+1
ZIP Code --> Housenumber:INSTANCE+1

Although I have to think about a more logical/readable syntax this saves me a lot of changing especially if there are 30+ Editboxes on a screen and someone adds 1 in the beginning of the screen.

This is why you use control IDs and not instance numbers. Most GUI's have static control IDs and thus additions do not create an offset issue. Removal doesn't affect anything, either, unless, of course, it's the control you're trying to work with.

I do not agree in this area see below for some straightforward UDF
Would be nice if I could code like
"[LOGICALNAME:01.Result" which then would lead to a lookup triggering function.

Lookup file (control.map)

	Group
	01.Calculator	    | Rekenmachine
	01.Result           | [CLASS:Edit; INSTANCE:1]
	03.btn7		    | [CLASS:Button; TEXT:7]
	Group
	01.OfficeNet Direct | OfficeNet Direct
	01.naam		    |
	02.Afkorting        | [CLASS:Edit; INSTANCE:2]
	03.Contractnummer   | [CLASS:PBEDIT80; INSTANCE:3]
	12.btnToepassen     | [CLASS:Button; TEXT:&Toepassen]
	Group
	01.OfficeNet Direct | OfficeNet Direct
	01.Treeview         | [CLASS:PBTreeView32_80; INSTANCE:1]
	Group
	01.Aanlogscherm	    | Aanloggen OfficeNet Direct
	01.Naam		    | [CLASS:Edit; INSTANCE:3]
	02.Wachtwoord       | [CLASS:Edit; INSTANCE:2]
	03.btnOK            | [CLASS:Button; TEXT:&Ok]
	04.Annuleren        | [CLASS:Button; TEXT:&Annuleren]
	05.help             | [CLASS:Button; ID: 1002]

After seeing this, I fail to see how it's any superior than using variables to store your strings. I often pass variables to functions expecting strings just because the name of a variable is almost always shorter than the string itself thus it makes the code more readable(it also makes re-use easier). So, I wonder why you don't just use named variables. I fail to see why there has to be any lookup table at all.

PS: When I say "user" I mean script writer. Remember, I'm a developer, so "my users" means "script writers".

comment:4 Changed 11 years ago by Valik

I really hate how I can't stay logged in on this blasted thing.

Anyway, in case it's not obvious, the preceding comment is from me.

comment:5 in reply to: ↑ 3 Changed 11 years ago by junkew@…

Replying to anonymous:

Replying to anonymous:

Replying to Valik:

This is why you use control IDs and not instance numbers. Most GUI's have static control IDs and thus additions do not create an offset issue. Removal doesn't affect anything, either, unless, of course, it's the control you're trying to work with.

I frequently encounter GUI's that do not behave as nicely as I want and as I am not in control allways of the developers creating the GUI. I am not talking about the 80% of controls which are straigthforward. Thats the main reason why I finally have to work with commercial tools that give this ability.
Now I am looking since this week at AutoIT I am impressed with the basic functionalities but would like to see the recognition possibilities enhanced. (although I see that some of them I can bypass by creating UDF).

After seeing this, I fail to see how it's any superior than using variables to store your strings. I often pass variables to functions expecting strings just because the name of a variable is almost always shorter than the string itself thus it makes the code more readable(it also makes re-use easier). So, I wonder why you don't just use named variables. I fail to see why there has to be any lookup table at all.

Several reasons:

  1. Mainly easily split up work between scriptwriter and tester. Giving tester a less complicated interface (lookuptable maintenance is easy) helps in speeding up testautomation. Testers frequently cannot build scripts or develop programs.
  2. Based on a lookuptable it becomes easier to make a keyworddriven script
  3. Saves coding lines
  4. Use of lookupnames have no logical limitations whereas a variable in code cannot use dots, spaces, literal characters etc.
  5. Translation table is not cluttered with coding lines so more overview
  6. Translation table can be organized in a logical way of grouping which can be independently of your coding maintained
  7. Translation can be done on 1 place instead of searching thru sourcecode (imagine applications with hundreds of screens)
  8. All commercial tooling offer this kind of functionality (not a very good reason;-))
  9. Short variablenames do not enhance readability for others reading to go through the code.
  10. Without a lookuptable with an application of >10 screens with many controls on screen you quickly loose oversight. If you only have the technical name it sometimes becomes difficult when the GUI changes which control was which one on the GUI. Keeping code and GUI in sync then frequently becomes a nightmare.

http://safsdev.sourceforge.net/FRAMESDataDrivenTestAutomationFrameworks.htm
Imagine a screen with 4 edits, 3 radiobuttons, 3 buttons where one is named Add
I could make a UDF addPerson

func addPerson()
dim $edtName, $edtAdress,$edtStreet,$edtCity, $rbMale, $rbFemale, $rbUnknown,$btnDelete,$btnFind, $btnAdd

$wName="Fill in person details"

$edtName="CLASS:Edit; INSTANCE:1"
...
$btnAdd="CLASS:Button; ID:1"

ControlSend($wName, "", $edtName, "Elwin")
...
ControlClick($wName, "", $btnAdd)

endFun

If I have a lookuptable I can generalize (saving me hundreds/thousands lines of coding) above logic to something like

LookUpGroup("Add person")

For each item in Group
     $ItemValue=LookupData(Item) 'Find data to enter in datafile/excelsheet
     If classType="Edit" then 
         ControlSend($wName, "", $ItemName, $ItemValue)
     EndIf
     If classType="Button" then 
          If $ItemValue <>"" then
             ControlSend($wName, "", $ItemName, $ItemValue)
     EndIf
     ; Synchronize code
  EndIf


comment:6 Changed 11 years ago by Valik

Your example "reasons" why a lookup table is good is full of hyperbole, at best. It's a highly specialized niche interface that you've gone and convinced yourself is some sort of revolution. It's to the point that you can't/won't even think of alternatives.

It's not going to happen.

comment:7 Changed 11 years ago by Valik

  • priority changed from major to minor

comment:8 Changed 11 years ago by Valik

  • Milestone Future Release deleted
  • Resolution set to rejected
  • Status changed from new to closed

I'm closing this as rejected. I've opened 78, 79 and 80 which cover the three requests I find acceptable. You can track the tickets there.

comment:9 Changed 11 years ago by Valik

Make that #78, #79, #80 (mentioning again to get the tickets to show up as links).

comment:10 Changed 11 years ago by TicketCleanup

  • Version 3.2.10.0 deleted

Automatic ticket cleanup.

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

Action
as closed The ticket will remain with no owner.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.