OnAppear not working properly?

Asked by born

In sikuli 0.10.1 is not working as it should?
Example:

def test ():
      print "Good"
click (img0)
OnAppear (img1, test ())

On the screen after clicking on the image "img0" a completely different image, not img1. Nevertheless OnAppear causes handler test ().

Is this correct?

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
born
Solved:
Last query:
Last reply:

This question was reopened

  • by born
Revision history for this message
RaiMan (raimund-hocke) said :
#1

To use the observer feature, you have to use observe(), to start the observation of the specified region based upon your onFunctions. I have marked the comments with !!! where you have to correct your code.

def test (event): # !!! the handler should have this parameter, it contains a reference to the observing region object
      print "Good"
click (img0)
onAppear (img1, test) # this implements an observation event, the handler has to be the function name, not the function call
observe() # this starts the observation, script waits

If you are using Windows: the observer feature has a bug ( bug 604514 ), so does not work properly and as expected.

In your case "Good" is printed, because in your onAppear(img1, test()) your function test() is called in this moment, returns None which becomes the callback for the onAppear() (would do nothing, if observe would work ;-)

How it should work:
onAppear (img1, test) # this implements an observation event, in case img1 appears during observation or is there already, the handler test is called
observe() # this starts the observation, script waits for 3 seconds (AutoWaitTimeout), use the timeout parm to have a longer observation time

More details:
http://sikuli.org/trac/wiki/reference-0.10#ObservingVisualEventsinaRegion

Revision history for this message
RaiMan (raimund-hocke) said :
#2

missed the !!!

onAppear (img1, test) # !!! this implements an observation event, the handler has to be the function name, not the function call

Revision history for this message
born (born127) said :
#3

Thank you for such a quick response RaiMan!

I write code for regression testing in the windows-environment. If there is an issue that has not yet fixed, I can otherwise carry out its task?

The challenge is what to check when you click the mouse button, to discover whether the right window and did not raise any errors.

Maybe there are other ways to check this?

Revision history for this message
RaiMan (raimund-hocke) said :
#4

I understand:
- you click something and some window with some content comes up
- you want to check wether it is the right window

assumptions:
- the upcoming window, that we want to check, has a visible object (img1) that cannot be seen somewhere else on the screen, only in the window to check.
- only as example: the window contains a button (img2) that can be clicked to proceed

click(img0) # this should bring up the next window
if exists(img1, 10): # check for img1 to come up, wait max 10 seconds
   popup("success")
else:
   popup("sorry")
   exit() # end script, since normally the workflow is broken
click(img2) # window is there, we can try to click

Since the normal operation of the observer feature just pauses the script at that point and waits for the events to come up, as long until in one of the handlers the observation is stopped or a given timeout is reached, it is more or less a more readable loop construction that checks for the existence/absence of some images. Normally this can be done with one or more exists().

real benefits of the observer feature:
- more readable when 3 or more events have to be checked in parallel
- can be run in the background while the script continues some processing
- onChange() as a compound event is only available with observe() (could be simulated by capturing the region and periodically checking if it is still the same)

So my recommendation:
use exits() to get on the road.

a simulation of observ():

exists(img, 0) # makes only one try to find, without ,0 it would wait 3 seconds (default)

timeout = 10 # max 10 loops
start = 0
case = None
while start < timeout: # the first event ends the loop
   if exists(img1, 0): # onAppear(img1)
      case = 1
      break
   if exists(img2, 0): # onAppear(img2)
      case = 2
      break
   if not exists(img3, 0): # onVanish(img3)
      case = 3
      break
   wait(1) # we wait 1 second
   start += 1 # next try

if case:
   pass # we have to check which one fired
else:
   pass # we had a timeout (in this case after about 20 seconds)

Revision history for this message
born (born127) said :
#5

Thank you I will experiment further!

Revision history for this message
born (born127) said :
#6

Close the question.

Revision history for this message
alex (alex-life2539) said :
#7

I am trying to work with a similar code above in ubuntu:

def ClosePopup (event):
 click(img01)
region(region01).nearby().onAppear(img02, ClosePopup)
observe(FOREVER)

I need the script to close a specific window when a specific image pops up(only pops up for one second). The image never changes position and since it will run 'forever' I was hoping this would use the least amount of resource. I also do not know how to use the 'event' variable so i left it as is.

Revision history for this message
RaiMan (raimund-hocke) said :
#8

problems in your script and questions:

1. An observer per definition is bound to a region: in this case region(region01).nearby(). since you bind onAppear() to this region, the observer has to be bound to the same region, so you need a reference to this region:
reg = region(region01).nearby()
reg.onAppear(img02, ClosePopup)

?? what is region01? if it is already a region, you can write: region01.nearby()
?? nearby() returns a region, that is 50 pixels larger on every side than the given one. Is this your intention?

2. observe() without a bound region acts on default SCREEN (which is Screen(0)). so in your case you need:
reg.observe(FOREVER) (in your script nothing happens, since your observe() (= SCREEN.observe()) has nothing to do)

3. especially when using FOREVER, you need to stop the observer, because in your case the click might fire, when the event happens, but the observer would go on (your script will not continue including never ending). If this is your intention: ok, if not:
def ClosePopup (event):
 click(img01)
 event.region.stopObserver()

and here you have the "event" parameter: among other things, it knows the region, it belongs to, so with this construct you can stop observation.

This is the theory, sorry. I did not succeed to get an example running (on windows it is buggy anyway) on my Mac (first time I did that with 10.2, I guess I have to report at least 2 bugs))

try this instead:

def ClosePopup (event = None):
 click(img01)
 if event: event.region.stopObserver()

reg = region(region01).nearby()

# emulation of observe()
start = time.time()
max = 100 # max wait time or whatever FOREVER means for you
while True:
  if reg.exists(img02, 0):
    myH()
    break
  if time.time() - start > max: exit(1) # if nothing happens, we give up
# end emulation
print "window closed?" # here we go, when success

This works, if reg is small enough (with the whole screen, you may miss the popup if its only there for 1 second).

I left the handler ClosePopup and made it generally usable, so you only need to replace the emulation code.

This is tested with an applescript that produces a popup for 1 second. the region in my case is (600 x 600) and each exists costs less than 0.5 seconds. So make your region reg as small as possible.

Have fun with Sikuli.