Looping trouble in Sikuli/Python - python

Not sure where I'm going wrong:
mm = list(r.findAll(rButton))# find all rButtons on main screen
print len(mm) #check how many are detected
for x in range(0,len(mm)):
r.click(mm[x])
if(not r.exists(rButtonDisabled)):
print "this is a test"
r.wait(BeginTask,FOREVER)
r.click(BeginTask)
r.wait(rButton,FOREVER)
else: click(Cancel)
There are 2 screens. Let's call them main screen and screen2. On main screen there are identical buttons, rButton. I want to find all visible rButtons and then start clicking them. Ideally I want it to click on first rButton, which takes it to screen2, if the button on screen2 is disabled, click on cancel which moves us back to main screen, then go to the second rButton on main screen, which again takes us to screen2. Depending on rButtons on main screen, buttons on screen2 can be either disabled or enabled.
My code isn't working to that effect. Not sure where I'm going wrong.

I'm not sure how you've defined Region 'r', but as a default, Sikuli won't search outside the screen that is native to the OS. You need to first make sikuli find the other screen, then define the bounds of that screen.
As it appears now, you're searching Region 'r' no matter what screen you intended... You should define the two screens separately, or Sikuli won't know to switch screens to look for the button you want. For example, you can use the Screen class to define which screen is which--
numScreens = getNumberScreens()
r = SCREEN #in all caps, this is the reserve word for the whole screen native to the OS
#can also use r = Screen(0)
if numScreens > 0 #make sure second screen was counted by sikuli
r2 = Screen(1).getBounds()
else: raise the appropriate error
#Here's your code with some adjustments for multiple monitors
#on main screen
mm = list(r.findAll(rButton))# find all rButtons on main screen
print len(mm) #check how many are detected
for x in range(0,len(mm)):
r.click(mm[x])
#on secondary screen
if(not r2.exists(rButtonDisabled)):
print "this is a test"
r2.wait(BeginTask,FOREVER)
r2.click(BeginTask)
#back to main screen
r.wait(rButton,FOREVER)
#click the cancel button on secondary screen
else: r2.click(Cancel) # <-- the defining region was missing here in your original code
Here's the Sikuli documentation on multi-monitor environments

Related

How to keep all Python Tkinter Windows on top to detect hover

I'm making a clone of windows 98's start menu. I have the program almost finished I just need to get the buttons to open some programs. However for some reason the windows98 lookalike start menu keeps forcing me to start from the beginning in order to get through the menus. Each "tab" it's a docked borderless window because i was not sure how to make the program the shape it needed to be to appear over the operating system and over any open programs like how the old start menu should be. when i made it all one program it sat in the background when opened or it sat on top of the enter operating system making it really unrealistic. Start menu was only able to be placed on top as submenus when each window was created and destroyed using onenter and on exit when hovering over labels. so each tab is filled with labels that when the mouse hovers over it trades the image for the blue one and if it is a label that has a submenu like for example the programs part of the first start window it opens the next label (or in tkinter's world a new window)
as you can see in the video below the on hover events do not stay once the mouse leaves the window
(I created a transparent window in the background so that when the user clicks out of the start menu the program is aware of it and can handle closing the entire program to look like the start menu is just being closed)
the labels also do not turn blue when trying to backtrack to the previous window.
I am wishing for any kind soul here to assist me in solving these mysteries.
Here is a video showing the issue
https://youtu.be/KeK_qfV_X6s
I want to post the code for the program but the editor says that it is using too many characters to post it here.
I will send an example of how the new tabs are created and hope it's enough. I can send the script itself to someone who needs it.
'''code'''
def createProgramsTab():
global ProgramsTabWindow
ProgramsTabWindow = Toplevel(ClickToExitBackground)
ProgramsTabWindow.geometry("+205+270")
ProgramsTabWindow.geometry("150x147")
ProgramsTabWindow.configure(bg='#c0c0c0')
ProgramsTabWindow.deiconify()
EmptyProgramsTabLabelImage = ImageTk.PhotoImage(Image.open(r'assets/StartMenuPrograms.png'))
EmptyProgramsTabLabel = Label(ProgramsTabWindow, image=EmptyProgramsTabLabelImage)
EmptyProgramsTabLabel.photo = EmptyProgramsTabLabelImage
EmptyProgramsTabLabel.place(x=0,y=0)
HomeBaseaccessoriesButtonImage = ImageTk.PhotoImage(Image.open(r'assets/startaccessoriesdefault.png'))
HomeBaseaccessoriesButton = Button(ProgramsTabWindow, image=HomeBaseaccessoriesButtonImage, borderwidth=-10, highlightthickness=-10, relief=FLAT,bd=-10,bg="#c0c0c0")
HomeBaseaccessoriesButton.photo = HomeBaseaccessoriesButtonImage
HomeBaseaccessoriesButton.place(x=3,y=3, bordermode=INSIDE)
HomeBaseProgramsButtonImage = ImageTk.PhotoImage(Image.open(r'assets/startprogramsdefault.png'))
HomeBaseProgramsButton = Button(HomeBaseWindow, image=HomeBaseProgramsButtonImage, borderwidth=-10, highlightthickness=-10, relief=FLAT,bd=-10,bg="#c0c0c0")
HomeBaseProgramsButton.photo = HomeBaseProgramsButtonImage
HomeBaseProgramsButton.place(x=25,y=44, bordermode=INSIDE)
def onEnterPrograms(event):
global HomeBaseProgramsButtonImage
HomeBaseProgramsButtonImage = ImageTk.PhotoImage(Image.open(r'assets/startprogramsblue.png'))
HomeBaseProgramsButton.config(image=HomeBaseProgramsButtonImage)
HomeBaseProgramsButton.photo = HomeBaseProgramsButtonImage
createProgramsTab()
destroyfavoritesTab()
destroysettingsTab()
destroyaccessoriesTab()
destroydevotionalservicesTab()
destroyinitiationTabWindow()
destroydocumentsTab()
def onLeavePrograms(event):
global HomeBaseProgramsButtonImage
HomeBaseProgramsButtonImage = ImageTk.PhotoImage(Image.open(r'assets/startprogramsdefault.png'))
HomeBaseProgramsButton.config(image=HomeBaseProgramsButtonImage)
HomeBaseProgramsButton.photo = HomeBaseProgramsButtonImage
HomeBaseProgramsButton.bind('<Enter>', onEnterPrograms)
HomeBaseProgramsButton.bind('<Leave>', onLeavePrograms)
HomeBaseWindow.attributes('-type', 'dock')
HomeBaseWindow.wait_visibility(HomeBaseWindow)
HomeBaseWindow.wm_attributes('-alpha', 1.0)
'''code'''
thank you again for any help
Billie

Properly close the window using mouse in Ursina

For the past couple of days, I have been playing around in the Ursina Engine in Python, used for creating both 3D and 2D games. But the recurring problem I have been facing with this engine when making 3D games, is that I can't close the window properly. This is happening because mouse is being used inside of the game, to control the player, so if I try to go to the close button, the mouse will always stay in the game. The workaround for this is to move to a different window, position the mouse so it's outside of the window, and then finally hit the close button. But this is a lot of work for the user to do, to simply close the window.
Here is some simple code to demonstrate:
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
import random
game = Ursina()
class Block(Button):
def __init__(self, position = (0,0,0)):
super().__init__(parent = scene, position = position, model = 'cube', color = color.white)
for z in range(20):
for x in range(20):
block = Block(position = (x, 0, z))
player = FirstPersonController()
game.run()
I believe this import statement is causing this:
from ursina.prefabs.first_person_controller import FirstPersonController
How can I close the window properly in Ursina?
One solution to this problem would be to create a way for you to exit the game by pressing a key.
def input(key):
if key == 'escape':
quit()
With this code you can close the game by pressing 'escape'.
Quick solution, Shift+Q (if the exit_button is enabled).
Usually in first person shooters you make a pause menu and put an exit button there. The FirstPersonController hides the mouse cursor and locks the position to the center of the screen. To reverse this, do:
mouse.locked = False
mouse.visible = True
I usually press the "Windows" key. Pressing this button open the windows menu, but it also makes the mouse visible.
Another tip, you can put:
window.exit_button.visible = False
In your code to make it easier to close the window.
Just disable the FPC (First Person Controller)
player.disable()
or just
make the mouse unlocked mouse.locked = False, so it can move

Is there a way to wait for a condition to be true?

I'm attempting to log coordinates 3 separate times when a user clicks on the turtle screen, then continue running other commands once that is completed. Clicking 3 times does nothing, and the shell keeps printing that it's waiting, while one additional click causes the whole thing to not work and I get a "not Responding" message from the turtle graphics window.
import turtle as t
import time
canvas=t.getcanvas()
xlist=[]
ylist=[]
listcomplete=False
def getPos(x,y):
xlist.append(canvas.winfo_pointerx()) ##Logs the x and y coords when mouse is clicked
ylist.append(canvas.winfo_pointery())
print('appended the lists.')
if len(xlist)==3:
listcomplete=True
t.onscreenclick(getPos)
def main():
while listcomplete==False:
time.sleep(1)
print('waiting...') ##Prints periodically just to let me know it's still running
main()
print('list complete.') ##Prints to alert the list has been finished
print(xlist)
(Insert rest of code to follow)
listcomplete=True within getPos() will not change the global variable, instead it will create a new varable of the same name within the local scope.
To change the global variable, you have to tell python to use it from the global scope:
def getPos(x,y):
global listcomplete # tell python to use the variable from the global scope
xlist.append(canvas.winfo_pointerx()) ##Logs the x and y coords when mouse is clicked
ylist.append(canvas.winfo_pointery())
print('appended the lists.')
if len(xlist)==3:
listcomplete=True
That's due to the default behavior of the assignment operator (=).
Other operators, such as the comparision operator (==) will lookup the variable from the enclosing scope(s) if it's not found within the local scope, thus you may use while listcomplete==False: within main() w/o telling pyton to use the variable from the global scope.
But ideally, you do not even have to use that global variable. Instead run the turtle main loop and exit the turtle window when your condition is met:
import turtle as t
canvas=t.getcanvas()
xlist=[]
ylist=[]
def getPos(x,y):
xlist.append(canvas.winfo_pointerx()) ##Logs the x and y coords when mouse is clicked
ylist.append(canvas.winfo_pointery())
print('appended the lists.')
if len(xlist)==3:
t.bye() # exit turtle window
t.onscreenclick(getPos)
t.Screen().mainloop() # will wait until turtle window is closed
print('list complete.') ##Prints to alert the list has been finished
print(xlist)
Is it possible to continue running the turtle window after the lists
have been created?
Things get difficult in turtle when you fight it's event-based model as you're trying to do. Work with the model, and things get easier. The code below presents a blank window, after you click on it in three places, it will connect your points to make a triangle:
from turtle import Screen, Turtle, mainloop
def getPosition(x, y):
screen.onscreenclick(None) # disable the handler inside the handler
positions.append((x, y))
if len(positions) == 3:
screen.ontimer(listComplete) # sometime after this function completes
else:
screen.onscreenclick(getPosition) # restore the handler
def listComplete():
for position in positions:
turtle.goto(position)
turtle.pendown()
turtle.goto(positions[0]) # close our triangle
# (Insert rest of code to follow)
positions = []
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
screen = Screen()
screen.onscreenclick(getPosition)
mainloop() # invoke as function to make Python 2 friendly as well
The key is that "rest of code to follow" will be in functions, not top level code.
def handle_click(mouse_x,mouse_y): # <== I think thats what ya need right dere, I dont think it knows you're clicking
newpin = [[mouse_x,mouse_y], [0,0], 0,0,20, 1000000]
I tried putting a print statement after the click I couldn't get it to even print a test click. That may be me not trying hard enough tho ;) I just remember using something like above to handle a mouse click. (in my situation it created a pin for a pinball game) if you look up the turtle api for circle you can see the [0,0],0,0,20, 100000] means.
But ultimately that last number the 10000 whatever is "mass" so the more of it the less it moves. again my situation. turtle.onscreenclick(handle_click). Thats at least an idea :) also yes u can do a wait after an if. Throw in print statements.

Python using turtle button

I am attempting for a homework assignment to implement Simon Says in python. I'm trying to do it using the turtle library (a requirement).
However, I've run into a stumbling block in that while I can get the screen to register click events (currently just printing the x,y coordinates) I can't get it to wait for a click event.
Specifically what I'm planning on doing is having areas on the screen that when they click within that location it is considered as if they had clicked a button. Screen clears and game does whatever.
However, in experiments in trying to get a working 'button' all that it does is set it so it prints the x,y coordinates but the rest of the program finishes. Didn't wait for the user to click anything. I tried a blocking method of...
while clicked == False:
pass
or
while clicked == False:
time.sleep(1)
but both methods hangs the program until I manually interrupt and then it'll print the clicks.
Am I missing an option somewhere?
Turtles don´t have buttons, but they do have callbacks for clicks.
Furthermore, you should use onclick for Screen to detect general clicks and onclick for turtle to detect clicking in turtles. You can, for example, make a 4 BIG turtles with different colors by using a dynamic shape.
Also, turtle is based on Tk, so you must be aware of things like mainloop()
The following program give some hints for Python 2.7.5.
import turtle as t
from random import randint
class MyTurtle(t.Turtle) :
def __init__(self,**args) :
t.Turtle.__init__(self,**args)
def mygoto(self,x,y) :
t1.goto(x,y)
print x,y
def randonics(self,x,y) :
self.left(randint(90,270))
def minegoto(x,y) :
print x,y
t1.goto(x,y)
wt=t.Screen()
t1=MyTurtle()
wt.register_shape("big",((0,0),(30,0),(30,30),(0,30)))
t1.shape("big")
wt.onclick(t1.mygoto,btn=1)
wt.onclick(minegoto,btn=2)
t1.onclick(t1.randonics,btn=3)
t1.goto(100,100)
t.mainloop()
So after extensive search there isn't necessarily a way pause execution of the code in python while using turtle to wait for some click event. Maybe in Tk I could do that but not in turtle.
However, there is a way to get around that. As an example. A method sets up the fake button on the screen, sets the click event, and terminates. The click event when clicked calls the next method needed for execution. So until the button is clicked the actual code isn't doing anything but remains in memory for use.
So more specifically.
1. Create a 'button'.
2. Have your program behave normally until it needs to wait for a click event.
3. Set up the on screen click (or on turtle) in such a way when the 'button' is clicked the next part of the code is run.
Special note. The code in question can't depend on waiting for a click event for later on in code. Instead, the click causes the next part of the execution of your code.
You can make the function registered with onclick() test the x,y position. If it is inside some region you do whatever you must.
I don´t see the difference between what you want to do and what this code does, the modification of turtle position is just an example, you can do anything when a click is captured by onclick(), even start a thread if you really need it (using Creating Threads in python)
import turtle as t
from random import randint
from threading import Thread
from time import sleep
def threaded_function(arg,t1):
for i in range(arg):
print "running",i
sleep(1)
t1.forward(i*10)
def minegoto(x,y) :
print x,y
t1.goto(x,y)
thread = Thread(target = threaded_function, args = (10,t1 ))
thread.start()
thread.join()
print "thread finished...exiting"
wt=t.Screen()
t1=t.Turtle()
wt.register_shape("big",((0,0),(30,0),(30,30),(0,30)))
t1.shape("big")
wt.onclick(minegoto,btn=1)
t1.goto(100,100)
t.mainloop()

wxPython: Exit Fullscreen

To display a wxPython window in full screen mode you use:
ShowFullScreen(True)
How do you get out of full screen though? I've tried the obvious way:
ShowFullScreen(True)
sleep(5)
ShowFullScreen(False)
This doesn't work though. When I run the script, nothing appears. After 5 seconds a window roughly 200x250 appears in the top-left corner of the screen, without anything inside of it. It doesn't appear to have any borders either.
If I change this to
showFullScreen(True)
then I get stuck with a full screen window that I have to use Alt + F2 -> xkill to get out of.
It looks like you need to Show() the window first. (According to the documentation, you shouldn't have to. Maybe this is a bug.) I tested on Mac OS X and Windows - they both exhibit issues if you don't call Show() first.
Also note that you shouldn't sleep in the main GUI thread. You'll hang the UI. Using CallLater is one potential solution, as shown in my example.
Working example:
import wx
def main():
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, 'Full Screen Test')
frame.Show()
frame.ShowFullScreen(True)
wx.CallLater(5000, frame.ShowFullScreen, False)
app.MainLoop()
if __name__ == '__main__':
main()
The documentation for ShowFullScreen reads:
ShowFullScreen(show, style=wx.FULLSCREEN_ALL)
Depending on the value of show parameter the window is either shown full screen or restored to its normal state.
Parameters:
show (bool)
style (long): is a bit list containing some or all of the following values, which indicate what elements of the window to hide in full-screen mode:
wx.FULLSCREEN_NOMENUBAR
wx.FULLSCREEN_NOTOOLBAR
wx.FULLSCREEN_NOSTATUSBAR
wx.FULLSCREEN_NOBORDER
wx.FULLSCREEN_NOCAPTION
wx.FULLSCREEN_ALL (all of the above)
So put your Full Screen toggle event/s in a Menu and start full screen mode with:
self.window.ShowFullScreen(True, style=(wx.FULLSCREEN_NOTOOLBAR | wx.FULLSCREEN_NOSTATUSBAR |wx.FULLSCREEN_NOBORDER |wx.FULLSCREEN_NOCAPTION))
Note that I omitted wx.FULLSCREEN_NOMENUBAR, in this way you will still be able to access the menu to turn full screen mode off again.

Categories

Resources