How to work around an occasional image

Asked by DAVID MASTROIANNI on 2017-09-27

My code basically looks like:
wait("image1", FOREVER)
click("image1)
wait("image2", FOREVER)
click("image2")

Sometimes there is an "image1.5" or a known image at a random time.

What is the best way to work through this?

Can you show me an example of how to use an "if", "onAppear", "while exists" etc. or whatever is most appropriate?

Question information

Language:
English Edit question
Status:
Answered
For:
Sikuli Edit question
Assignee:
No assignee Edit question
Last query:
2017-10-01
Last reply:
2017-10-02
masuo (masuo-ohara) said : #1

Try this codes.

def handler1_5(event):
    click(event.getMatch())
    event.stopObserver()

r1 = Region(100,100,300,300)
r1.highlight(1)

r1.onAppear("image1_5.png", handler1_5)
r1.observe(FOREVER,True)

r1.wait("image1.png", FOREVER)
r1.click()

r1.wait("image2.png", FOREVER)
r1.click()

r1.stopObserver()
popup("Click [OK] to finish")

This code clicks an image if finds it and does nothing if image is not present:
======
def try_click(our_image):
        try:
                click(our_image)
        except FindFailed:
                pass
======

DAVID MASTROIANNI (dmastro918) said : #3

@roman, is this possible for multiple images?

DAVID MASTROIANNI (dmastro918) said : #4

[error] script [ PROGRAM.AUTOMATION ] stopped with error in line 1 at column 14
[error] SyntaxError ( 'no viable alternative at input \'"1506689574881.png"\'', )

def try_click("1506689574881.png"):
        try:
                click("1506689574881.png")
        except FindFailed:
                pass

DAVID MASTROIANNI (dmastro918) said : #5

I am trying to write code at the beginning of the script that says hey:

If image1, image2, or image3 ever show up, take action x,y,z

which will simply be if image1 shows up click image1, if image 2 shows up click image2, etc.

======

def try_click("1506689574881.png"):
        try:
                click("1506689574881.png")
        except FindFailed:
                pass
======
That's wrong.

Correct:
======

# Function definition
def try_click(our_image):
        try:
                click(our_image)
        except FindFailed:
                pass

# function call
try_click("1506689574881.png")

======

You also may add later:

=====
try_click(image2)

try_click(image3)

=====

DAVID MASTROIANNI (dmastro918) said : #7

def try_click(our_image):
        try:
                click(our_image)
        except FindFailed:
                pass
try_click(Pattern("1506689688440.png").targetOffset(44,-61))
try_click("1506689574881-2.png")
try_click("1506689746912.png")
__________________________________________
I put this code before the rest of my script, but now my script won't do anything when I click run.
Again I'm trying to achieve a code where if an image appears it will be clicked, however the image may or may not show at a point in the middle of the script.

Manfred Hampl (m-hampl) said : #8

Maybe the following approach works:

Split the logic into two parts:
1. the main logic, as already programmed by you

wait("image1", FOREVER)
click("image1")
wait("image2", FOREVER)
click("image2")

and
2. additional logic that runs when that image1.5 shows up
For this you can let an observer run in the background.

def myHandler(e):
        print "image 1.5 appeared"
onAppear("image1.5.png", myHandler)
observe(FOREVER, background = True)

(part 2 has to go before part 1)

DAVID MASTROIANNI (dmastro918) said : #9

Instead of print "image1.5 appeared"
Can I use click("image1.5")

I wish to have my program run while I'm away from the computer, right now each time the image pops up I have to manually click it, and then the automation continues

1|def myHandler(e):
2| click(Pattern("1506689688440-1.png").targetOffset(44,-61))
3|onAppear(Pattern("1506689688440-2.png").targetOffset(44,-61), myHandler)
4|observe(FOREVER, background = True)
________________________________________________________________________
[error] script [ SWFC_LOG_ALL_2+ ] stopped with error in line 4
[error] TypeError ( observe(): takes no keyword arguments )

Sorry, David, you weren't clear with requirements.
Ok, here is a version with infinite loop.

======
# Setting similarity up for my testing purposes, you may or may not use it
Settings.MinSimilarity = 0.95

# Defining function for clicking if image present
def try_click(our_image):
        try:
                click(our_image)
        except FindFailed:
                pass

# Infinite loop, makes looking for images 1, 2 and 3 infinite
while True:
    try_click(image1)
    try_click(image2)
    try_click(image3)

    # Code for stopping the script: if it finds image 4 on screen, infinite loop stops
    # and does not search for images 1, 2 and 3 anymore
    if exists(image4):
        break

======

I think you better not use onAppear / observe() for this purpose. They are expected to wait for image until it appears (that is like wait for image1 until it appears, not paying any attention if image2 and image3 are on screen now). Function try_click() does not wait, it just clicks image if it is present now and does nothing if the image is not present.

Settings.MinSimilarity = 0.95
def try_click(our_image):
        try:
                click(our_image)
        except FindFailed:
                pass
while True:
    try_click(Pattern("1506689688440-1.png").targetOffset(44,-61))
    try_click("1506689574881-3.png")
    try_click("1506771151595.png")
___________________________________________________________
I click run and nothing happens, without the above code my script runs perfectly, aside from the 3 images showing up sometimes

You have to figure where to put it in your script. As I don't see you full code, I can't. If, say, your code should work first and then just "sit and wait and click occasional images", you should put "while True: ..." part in the very end of your script.

"while True: loop" captures the execution flow, and if put before some commands execution never reach that commands.

Yes @Roman, sorry for the lack of code and confusion, and thank you for helping me thus far.

My script consists only of:

Wait(Image_A, FOREVER)
Click(Image_A)
Wait(Image_B, FOREVER)
Click(Image_B)

and continues this way all the way to Image_Z

I want to add a background statement that if image1, image2, or image3 appear they get clicked.
Note: Image1, image2, and image3 may possibly not show up at all, or may possibly show up at some point in between Image_A and Image_Z.

As of right now I watch my script run, and if image 1, 2, or 3 appear I manually click them and then allow my script to continue to run.

So I want to write something that will allow for these images to get clicked if they appear.
What exactly would that code look like?

TestMechanic (ndinev) said : #16

Hi David,

I have one idea that may be helpful. Please note I am giving you "not tested" code. Also assuming you have main imagesA-Z and sporadic images1-3. The logic will work but wont be very fast

def WaitMainImage(mainImage):
 while True: # endless loop for the main image - return only when main image is found&clicked
    if exists(mainImage): click(); return
    if exists(image1): click()
    if exists(image2): click()
    if exists(image3): click()

# here is the list of main images paths
ImagesA_Z=["imagepath_A", "imagepath_B", ................ "imagepath_B"]

# MAIN
for img in ImagesA_Z:
  WaitMainImage(img)

Hi ndinev,
Yes I do have images A through Z and Images 1, 2 and 3.
===========================================================================
def WaitMainImage(mainImage):
 while True:
    if exists(mainImage): click(); return
    if exists("image1.png": click()
    if exists("image2.png"): click()
    if exists("image3.png"): click()
wait(Image_A, FOREVER)
click(Image_A)
wait(Image_B, FOREVER)
etc.
===========================================================================
The good news is the script runs and starts waiting for image A and clicks image A, and continues
The bad news is when Image1 and Image2 showed up nothing happened.
So the question is: Why isn't the "if exists(image): click()" working?

ndinev, I'm really only concerned with the occasional unexpected images, not the main images or main sequence.
if ever appear
then click
if doesn't appear
do nothing

when I watched the Youtube tutorials
there is a game automation example
it has a working if exists
but the image is already on the screen, so its just telling the script to reference what's already there
my images are pop ups
they aren't present until they are

Manfred Hampl (m-hampl) said : #20

You modified ndinev's suggestion in a wrong way.
You just have to take it as it is and insert the image names, and this should work.

Work on this line:
ImagesA_Z=["imageA.png", "imageB.png","imageC.png", "imageD.png", ... and so on until ... "imageZ.png"]

I actually did that deliberately because (full disclosure)
After Image E is a sign in button
at which point I have my script type text including username and password.
After this sign in process point the wait/click cycle continues.
How can I work in the sign in button using ndinev's suggestion?
How can I use my type text function exactly where I need it to be?

I am going to try to use ndinev's code while making the sign in page an unexpected page (so the sign in image will not be a main image). testing now.

Yea, the specific issue for this scenario is that there will be times where multiple main (expected) images are true.
So having a code sequence of wait/click is necessary, however it still needs to use a background function for unexpected/occasional images

click; wait; click; wait; click; wait; click; type; click; click; type; click; click; (unexpected/occasional image1); click, wait, click wait, click; (unexpected/occasional image2); click; wait; click; wait etc.

This is the main issue I am working with at this time, I'm not trying to overly complicate things, but will get as messy as I need to.

Manfred Hampl (m-hampl) said : #25

If your primary logic is more complicated that just [:wait - click:], then I would like to go back to my recommendation with an observer.
It seems that there was an error in my first proposal; apparently there is old code in an example of the documentation in http://sikulix-2014.readthedocs.io/en/latest/scripting.html?highlight=observer#Settings.ObserveScanRate

Try with something like

def myHandler(e):
         click("image1.5.png")
onAppear("image1.5.png", myHandler)
observeInBackground(FOREVER)

wait("Image_A.png", FOREVER)
click("Image_A.png")
wait("Image_B.png", FOREVER)
click("Image_B.png")
wait("Image_C.png", FOREVER)
click("Image_C.png")
wait("Image_D.png", FOREVER)
click("Image_D.png")
wait("Image_E.png", FOREVER)
click("Image_E.png")
type("username")
click(in the password field)
type("password")
wait("Image_F.png", FOREVER)
click("Image_F.png")

etc.

Maybe the following approach works:

Split the logic into two parts:
 1. the main logic, as already programmed by you

wait("image1", FOREVER)
 click("image1")
 wait("image2", FOREVER)
 click("image2")

and
 2. additional logic that runs when that image1.5 shows up
 For this you can let an observer run in the background.

(part 2 has to go before part 1)

TestMechanic (ndinev) said : #26

David,

As far as I understand you have some workflow that have occasional images only at some steps. Why not just at those places use this logic

def WaitMainOrOccasuionalImage(mainImage,occasionalImage):
 while True: # endless loop for the main image - return only when main image is found&clicked
    if exists(mainImage): click(); return
    if exists(occasionalImage): click()

wait(imageA,FOREVER); click()
wait(imageB,FOREVER); click()
type("username")
wait(imageC,FOREVER); click()
type("password")
wait(imageD,FOREVER); click()
WaitMainOrOccasuionalImage(imageF,image1)
wait(imageG,FOREVER); click()
...

Can you help with this problem?

Provide an answer of your own, or ask DAVID MASTROIANNI for more information if necessary.

To post a message you must log in.