Trouble using onChange in a for loop

Asked by Mangin Matthias on 2020-04-16

Hello,

I am using Sikulix-IDE-2.0.4
My screen size is 1920*1080

I am trying to run a for loop that click on a region, wait until the screen changes, then click on a region, and so on :
I have tried to use onChange to check that the screen changes, but havent figured out how to do it properly.
I have tried 2 approaches :

1) onChange outside for loop :

    time_to_change_map = 10.0
    time_to_load_map = 2.0
    Settings.ObserveScanRate = 1.0 / time_to_load_map

    def map_change_handler(event):
        event.stopObserver()
        wait(1)

    def change_map(regions, custom_time_to_change_map=time_to_change_map):
        # regions = list of the regions where to click
        onChange(1000000, map_change_handler)
        for r in regions:
            click(r)
            # Wait until we change of map and it loads
            observe(custom_time_to_change_map + time_to_load_map)

It seems that once the event has once be triggered in the first iteration of the loop,
it is always considered as changed, so it doesn't wait to change map.
Is there a way to reset the event in the handler ?

2) onChange inside the for loop

    time_to_change_map = 10.0
    time_to_load_map = 2.0
    Settings.ObserveScanRate = 1.0 / time_to_load_map

    def map_change_handler(event):
        event.stopObserver()
        wait(1)

    def change_map(regions, custom_time_to_change_map=time_to_change_map):
        # regions = list of the regions where to click
        for r in regions:
            click(r)
            # Wait until we change of map and it loads
            onChange(1000000, map_change_handler)
            observe(custom_time_to_change_map + time_to_load_map)

Here it seems to create a new event each time, so at the iteration N of the loop, the handler is called N times, which is dirty and makes N times wait(1). I know i can put the wait(1) outside of the handler, but anyway I don't want the handler to be called N times, and I don't want to fill the memory with events.
Is there a way to remove the events once consumed by the handler ? I tried with region.getEvents() but it isn't working.

Best Regards

Question information

Language:
English Edit question
Status:
Solved
For:
Sikuli Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
2020-04-16
Last query:
2020-04-16
Last reply:
2020-04-16
Best RaiMan (raimund-hocke) said : #1

The first approach is correct, since the change event does not vary in the loop.

When observe() is started, a screenshot is taken and then every 1/ObserveScanRate seconds a new screenshot is taken and compared with the one taken before.
If changes are detected, the handler is visited.
If you do not stop the observer, it will go on checking for changes until the given oberserve time elapses.

With your given script, you can only guess, that the handler is visited, if the next click happens within less than 12 seconds.

I suggest, to restrict the observed region to the area of the observed map. This avoids false positives (changes that might happen elsewhere on the screen).

You are setting the observe scan rate to 0.5 (checking every 2 seconds for changes) - hope it is your intention.

This is my testscript:

def handler(evt):
    clen = len(evt.getChanges())
    print "changed", clen
    cr = evt.getChanges()[0]
    for n in range(1, clen):
        cr = cr.union(evt.getChanges()[n])
    cr.highlight(2)
    evt.stopObserver()

reg = SCREEN
# reg = Region(25,111,548,285) # uncomment to have a restricted area
reg.highlight(2)
reg.onChange(10000, handler)
for n in range(3):
    print n
    reg.observe(5)

comment on
reg.onChange(10000, handler)

if the observed region is not the whole screen, then this works with the defaults:
reg.onChange(handler)

A higher pixel value is only needed if you want to ignore smaller changes. In case of whole screen, this filters changes happening outside the region of interest. But as mentioned: it is always better to restrict the observed region.

In my example I trigger the changes by switching windows on the screen.

Mangin Matthias (deax-stormz) said : #2

Thanks alot for your answer,
Indeed I wasn't stoping the right observer, so the behaviour was unexpected.
Now it properly works
Thanks for the suggestions about restricting the area, but almost the whole screen is changing so i'm checking the screen region.

Mangin Matthias (deax-stormz) said : #3

Thanks RaiMan, that solved my question.