Python style Dictionary, string as key

Asked by eliteSKL

This is how i got a normal python dictionary to work with Sikuli.

1) make and image library. i have created my like this:

from sikuli.Sikuli import *

ItemToBeClicked = 12345543.png # aka the screen shot

2) create your main script that imports the images

from imageLib import *

class mytest():
__def __init__(self):
____self.myValues = { 'clickthis':ItemToBeClicked, 'someothervarable':ImageVarableName} #no " or ' around your values
____self.answer = None

__def whatToclick(self):
____self.answer=input("what should i click?") # this is where you would type "clickthis".... aka your key value
____click(self.myValues.get(self.answer))

mt = mytest()
mt.whatToclick()

in short VDict is great for working with that image as your key. but if you want to work the other way/direction it's a bit harder. The why I'm showing allows a user to use a string as your key and and image variable as you value.

i don't hard code my path to image files because that reduces code re-usability(if that's a word... lol) and if i have to change screen resolutions then i have a separate file that allows easy of retaking pictures at a new resolution.

i'm posting this to show other users how to achieve this and to have it looked over to see if the code is correct in procedure.

let me know if there are any problems with my method of handling this.

thanks

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
RaiMan (raimund-hocke) said :
#1

Oh yes, it is really a good idea, to use a dictionary to store your image references. This gives some more options, than simply having a bunch of "imgXXXX = 12345678.png" in the image-library.

But why don't you put the dictionary setup and the wrapper class in the imagelib too? If you need more than one imageset (your resolution case), you could solve that, when initializing the class.

So in the latter case, you had:

--1. the image containers: e.g.
imagesHiRes.sikuli
imagesStandard.sikuli
imagesLowRes.sikuli

each of these contain a dictionary like this (with same name to be reusable ;-)
theImgDict = {}
theImgDict["image1"] = "some-image1.png"
theImgDict["image2"] = "some-image2.png"
theImgDict["image3"] = "some-image3.png"
.....
may be many more - should have some naming convention

--2. now we need a wrapper for that, to select an image set and access the images
we put it in a file imageDictWrapper.sikuli

class imageDictWrapper():

   def __init__(self, imageSet = "HiRes"):
# image set is evaluated to load (import) one of the image sets
# if not given, the HiRes is loaded
      from imagesXXXX import *
# the imported dictionary is assigned to an object variable e.g. images
      self.images = theImgDict

   def getImage(self, imageName):
# we need some logic to assure image exists
      return images[imageName]

--3. now we have a script that uses all this stuff
# supposing sys.path is ready
from imageDictWrapper import *
imgSet = imageDictWrapper("LowRes") # we want the LowRes image set

# and now our first action:
click(imgSet.getImage("image1"))

... and so on

do not blame me please, if something is not correct ;-)
Only wanted to put my idea on the whiteboard.

Revision history for this message
eliteSKL (camaro70s) said :
#2

what you have posted is a great idea. Actually the reason why i haven't created anything as robust as you have suggested is because there hasn't been an immediate need. the separation of pictures and code i feel is just good practice and my personal preference (when possible).

I posted this because i wanted a better way to handle my code rather that a ton of "if/elif" statements that return a picture, and figured maybe the answer might not be as obvious to others (it took me a while to realize how to make a normal dictionary could be applied to this).

my other reason is to show how my image library is setup. I had wondered if making a ton of (see below) references to images as my image library was good practice or not? I like coding with text variables/references rather then screen shots. It looks better in Vim.

ThisScreen_thisbutton_okay = 2345345.png
ThisScreen_thisbutton_okay = 2345345.png
ThisScreen_thisbutton_okay = 2345345.png

it just really took me a long time to come to this conclusion on my own and figured something should be listed here. It might help others out.

Thank you RaiMan for taking a look at this. I'm glad that it passes your quick over view approval. And as always I appreciate your help and insight very much.

Long Live Sikuli!!

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

Totally agreed, I love seeing ideas like yours here, because these are the things, that allow a script to come along as an application.

The great new features in Sikuli X (import, image path, loading jar-files, class App and the possibilities to integrate with other IDE's, frameworks and even applications) motivate to think more in this direction.

keep on running ;-)

Revision history for this message
Launchpad Janitor (janitor) said :
#4

This question was expired because it remained in the 'Open' state without activity for the last 15 days.

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

has some value

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

Here is an example, that makes up a class with some features inheriting its main features from Pythons dictionary class::

- it can collect images
- each image has a short name, the image file name and a message, that is printed if the image is not found
- if the image is not registered, a default message is printed
- you can restrict the search of all contained images to a region

--- the class definition:

class GuiElements(dict): # inherits from Python's dictionary
    def __init__(self):
        self.region = SCREEN # the default region
        dict.__init__(self) # super should be initialized too

    def clickElement(self, img): # the feature
        # click image if it exists and return match
        # print message otherwise and return None
        e = self.get(img, [img, img+" not found"]) # dictionary magic
        msg = e[1]
        if self.region.exists(self[e][0]):
            click(self.region.getLastMatch())
            return self.region.getLastMatch()
        else:
            print msg
            return None

    def setRegion(self, reg): # set the restricting region
        self.region = reg

    def getRegion(self): # access the current region
        return self.region

--- sample usage:

myReg = some_application_window

g = GuiElements() # get instance
g.setRegion = myReg # restrict the searches
g["Button1"] = ["image-of-button1.png", "Sorry, Button1 currently not visible!"] # register a button

# click a registered element
if not g.clickElement("Button1"): exit(1)
print "we clicked Button1", g.getRegion().getLastMatch()

# click a not registered element
img = "some-other-button.png"
if not g.clickElement(img): exit(1)
print "we clicked", img, g.getRegion().getLastMatch()

--- and now?
- you might implement more features and/or make it more robust
- you might add a feature, that adds the last match of a registered image to the container (self[img][2] = self.region.getLastMatch())
- you might add more versions of the imagefile, that reflects different system environments or screen resolutions
- ....