Pausing a loop in python - python

I have a loop that creates windows using PySide depending on the number the user enters
each window will have some calls for other functions.
I would like the second window opens after all the commands belongs to the first window is done.
So, Is there a way in Python to tell the loop to stop until a certain flag is True for example
Here's what I'm doing
for i in range(values):
self.CreatWindow() # the function that creates the window
def CreatWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
combo = QtGui.QComboBox(window)
combo.addItem(" ")
combo.addItem("60")
combo.addItem("45")
combo.activated[str].connect(self.onActivated)
btn = QtGui.QPushButton('OK', window)
btn.clicked.connect(self.ComputeVec)
window.show()
def onActivated(self, text):
angle = int(text)
def ComputeVec(self):
window.close()
getVecValue(angle)
Now in that function the window have some calls to other functions, and I want to set the flag to True in the last function getVecValue which will do some computations and store the result.

Instead of having a different loop to open new windows you could call CreatWindow in ComputeVec
and use a global variable count to maintain count of windows created before.
count = 0
def ComputeVec(self):
window.close()
getVecValue(angle)
global count
count += 1
if count in range(values) :
self.CreatWindow()

The loop does already behave like this, since the function call self.CreateWindow waits for the return value of the called function.
You can return an appropriate value from self.CreateWindow for example return True and do this:
for i in range(values):
success = self.CreateWindow()
if success:
continue
Anyway, if there is no return value in self.CreateWindow, the statement self.CreateWindow() is still evaluated and results to None. The loop is not finished until this result is achieved.

Related

Making a script that will cycle through 3 different states in Maya Python

I want to create a script in Maya using Python and bind it on a hotkey. Every time I run the script I want to loop through 3 states, cube/ cylinder / plane. So for example first time I run the script it will create a cube, second time delete the cube and create a cylinder third time delete the cylinder and create a plane., fourth time delete the plane and create a cube etc... I want this to happen until the user decides what primitive he wants and end the loop. I tried using while loop but I failed miserably.
Ended up with this:
def createCube():
return "cube"
def createCylinder():
return "cylinder"
def createPlane():
return "plane"
def numbers_to_primitives(argument):
switcher = {
1: createCube,
2: createCylinder,
3: createPlane,
}
# Get the function from switcher dictionary
func = switcher.get(argument, lambda: "Invalid primitive")
# Execute the function
print func()
numbers_to_primitives(2)
This kinda seems to work. But I foresee issues when running the command over and over as I am creating more and more primitives instead of replacing the existing ones. Would also need to create a toggle button to cycle through these?
You have several questions problems to solve. First, you want to use the script in a hotkey what means it should produce a different result every time you call numbers_to_primitive() without any argument. So you first need to save and read the current state. You have several ways to do it. If you only need the state in the current maya session, you can use a global variable like this:
state = 0
def box():
print "Box"
def cyl():
print "Cylinder"
def sph():
print "Sphere"
def creator():
global state
print "current state", state
state = state + 1
if state > 2:
state = 0
creator()
This way the state variable cycles through values 0-2. Now you want to create geometry and replace it as soon as the function is called again. It works very similiar: Save the current object and delete it as soon as the function is called again like this:
import maya.cmds as cmds
state = 0
transformName = "" #again a global variable
def box():
print "Box"
global transformName #to use the global variable you have do use "global" keyword
transformName, shape = cmds.polyCube()
def cyl():
print "Cylinder"
global transformName
transformName, shape = cmds.polyCylinder()
def sph():
print "Sphere"
global transformName
transformName, shape = cmds.polySphere()
def creator():
global state
funcs = [box, cyl, sph]
print "current state", state
print "TransformName", transformName
if cmds.objExists(transformName):
cmds.delete(transformName)
funcs[state]()
state = state + 1
if state > 2:
state = 0
Now you can call the creator() function and every time it will delete the old object and create a new one.

Python tkinter buttons are not working during a -while loop- condition

i am doing some measurement with raspberry pi. I made a GUI with python tkinter. measurement is done every seconds. when the measured value is higher than a particular value, i want to set some pin high for 30 seconds (counter). but measurement should continue. and during this time, if there is another high value, again reset the counter to 30 seconds. So i used a while loop. I am displaying measured values in GUI. I am calling the main function (readSensor) every seconds using .after method. During while loop condition, GUI is frozen and value is not updated on screen and buttons are not working. Shall i remove while loop and use .after? but how to use the counter there?
status = False
def start():
global status
status = True
def stop():
global status
status = False
def readSensor():
# there is a start and stop button in GUI
if status:
measuredValues = []
pi.write(23,0) # pin 23 is low now
# code to do measurement is here
#it works fine
#result is a list with name measuredValues
#then checking the conditions below
if((measuredValues[0] > Limit_1) or (measuredValues[1] > Limit_2) or (measuredValues[2] > Limit_3) or (measuredValues[3] > Limit_4)):
counter = 0
print(measuredValues)
while (counter <=30):
# this while is the problematic part. if condition is true, i will set the pin 23 high.
# i would like to set the pin high for 30 seconds
# no any buttons seems working during this time. why?
# stop button is also not working.
pi.write(23,1)
time.sleep(1.0) #shall i avoid this sleep?
print(counter)
measuredValues = []
#measurement will continue here
#same code to do measurement as before
#output is the same list with name measuredValues
print(measuredValues)
# if any of the new measuring values is/are higher than limit, want to reset the counter to 30
# shall I use .after method here? and avoid while loop?
# how to use it with a condition like maiximum 30s
if ((measuredValues[0] > Limit_1) or (measuredValues[1] > Limit_2) or (measuredValues[2] > Limit_3) or (measuredValues[3] > Limit_4) ):
counter = 0
else:
counter +=1
else:
pi.write(23,0)
print(measuredValues)
win.after(1000, readSensor) # new measurement every second
win = Tk()
# code for GUI here
win.after(1000, readSensor)
win.mainloop()
You should consider placing your function in a thread. So your start button in your GUI should call the function using:
import threading
start_button = Button(YourFrame, command = lambda:threading.Thread(target = readSensor).start()) #YourFrame is the Frame widget where you placed the start button
That should make the UI responsive while doing the calculations inside your funtion.

python appjar function doesn't thread

having issues trying to get threading working in python using the awesome Appjar package.
The following program needs to count through a list, and update a progress bar simultaneously. I've followed the appjar documentation for threading, but it's returning NameError: name 'percent_complete' is not defined in the app.thread (line 35), in which you're meant to insert function params - my code is below:
from appJar import gui
import time
# define method the counts through a list of numbers, and updates the progress meter
def press(btn):
objects = [1,3,6]
total = len(objects)
current_object = 0
for i in objects:
print(i)
current_object += 1
current_percent_complete = (current_object / total) * 100
updateMeter(current_percent_complete)
time.sleep(1)
def updateMeter(percent_complete):
app.queueFunction(app.setMeter, "progress", percent_complete)
# create a GUI variable called app
app = gui("Login Window")
app.setBg("orange")
app.setFont(18)
# add GUI elements : a label, a meter, & a button
app.addLabel("title", "COUNTER")
app.setLabelBg("title", "blue")
app.setLabelFg("title", "orange")
app.addMeter("progress")
app.setMeterFill("progress", "green")
app.addButton("START COUNTING", press)
# put the updateMeter function in its own thread
app.thread(updateMeter, percent_complete)
# start the GUI
app.go()
I can get rid of the error by defining percent_complete like so:
from appJar import gui
import time
# define method the counts through a list of numbers, and updates the progress meter
percent_complete = 0
def press(btn):
...
However, when GUI loads and button is pressed it doesn't thread. Instead it iterates through the list, then updates the progress bar afterwards.
Has anyone come across the same issue? any insight would be awesomely appreciated!
Thanks!
There are a couple of issues here:
First, I'm not sure your maths result in good percentages to update the meter with, so you might not see much change - should you be using i?
Second, the GUI won't be updated until the loop (and the sleeps inside it) all complete. Instead, you should try counting how many items to process, and iterating through them with an after() function, see here: http://appjar.info/pythonLoopsAndSleeps/#conditional-loops
Third, the call to app.thread() at the end doesn't achieve much - it calls the update_meter() function with a parameter that doesn't exist, it can be removed.
Fourth, the actual update_meter() function isn't necessary, as you're not really using a thread - that can be removed as well...
Give this a try, once you've had a look at the maths:
current_object = 0
def press(btn):
global current_object
current_object = 0
processList()
def processList():
global current_object
objects = [1,3,6]
total = len(objects)
if current_object < total:
i = objects[current_object]
print(i)
current_object += 1
current_percent_complete = (current_object / total) * 100
app.setMeter("progress", current_percent_complete)
app.after(1000, processList)
UPDATE: just to clarify on the maths issue, you're dividing one integer by another: 0/3, 1/3, 2/3, 3/3 and so on. In python2 this will result in 0, in python3 you'll get fractions.

"else" statement executed before "if" statement after `undo` is used in Python

I have created the following function that allows the user to change the shape of the Python turtle to an image he/she selects from a file dialog file dialog that pops up when a specific button is pressed:
def TurtleShape(iop = None):
# "iop" is supposed to be an image path
try:
manipulateimage.config(state = NORMAL)
flipButton.config(state = NORMAL)
mirrorButton.config(state = NORMAL)
originalButton.config(state = NORMAL)
resetturtle.config(state = NORMAL)
rotateButton.config(state = NORMAL)
global klob
# The following "if-else" statement uses the "iop" argument's value as the value for "klob" if `iop` is NOT `None`
if iop != None:
klob = iop
print("lmcv")
else:
klob = filedialog.askopenfilename()
print("klobby")
global im
im = Image.open(klob)
pictures.append(im)
edited.clear()
print(im)
im.save(klob + '.gif', "GIF")
register_shape(klob + '.gif')
shape(klob + '.gif')
update()
except:
pass
The above function is also supposed to use the iop argument's value as the turtle's image if it is not None.
Now, consider this situation; you draw a bunch of things, set the turtle to an image, and just when you are about to stamp the image, you accidentally press the button that resets the turtle to its normal shape (yes, that button exists in my program). Oh no! How would you get it back without going through all the steps to open and edit it again? Well, that is where my undoHandler function (shown below) comes in. It just essentially undoes the last function called using many stacks, which I created as deques. It is pretty straightforward if you are proficient in Python:
def undoHandler():
if len(function) > 0 and draw.drawing == True:
undoHandler.handling = True
if not hasattr(undoHandler, "counter"):
undoHandler.counter = 0
undoHandler.counter += 1
# clear the canvas
Clear()
# Pop a point object from function deque
function.pop()
penup()
goto(-200, 100)
pendown()
try:
# Execute everything up to point before last function called
for i in function:
# Set canvas and turtle to previous state
tsd = i.recieveshape()
shape(tsd)
mndf = i.recieveheading()
setheading(mndf)
hk = i.getletterheight()
global letter_height
letter_height = hk
rk = i.getletterwidth()
global letter_width
letter_width = rk
milk = i.getspacewidth()
global space_width
space_width = milk
hw = i.getwidth()
width(hw)
op = i.getcolor()
try:
color(op)
except:
for g in colors:
cp = g.getcolor2()
colormode(255)
color(cp)
# Get function wrapped in Point object and execute it
j = i.getfunction()
j()
# Following is the code block where the issue occurs. Basically, if the function being run is equal to `TurtleShape`, then do the following...
if j.__name__ == "TurtleShape":
# `hfl` is a deque that holds all of the `pictures` deque's contents as it is cleared when the turtle is set to its default state
pictures.extend(hfl)
lmcv = pictures.pop()
pictures.append(lmcv)
try:
# Resize image to previous size if user changes it. Otherwise, skip this.
bun = picwidth.pop()
picwidth.append(bun)
mun = picheight.pop()
picheight.append(mun)
clob = lmcv.resize((int(bun), int(mun)), Image.ANTIALIAS)
except:
clob = lmcv
clob.save(klob + str(undoHandler.counter) + ".gif")
# Use the `clob.save` output from above as source image in `TurtleShape` function (this is where issue occurs)
TurtleShape(klob + str(undoHandler.counter) + ".gif")
print("Undone!")
else:
pass
except:
pass
Basically what happens here is that it takes the function (wrapped in a Point object) from a queue through which the main functions go through as they are called. The functions then get appended to the function deque, after which, when undoHandler is called by the user, the screen gets cleared, and latest value is popped from the function deque so that all the other actions except the last one will be executed again. This issue I am facing occurs specifically in the if j.__name__ == "TurtleShape": code block. Basically, for some reason, when the user chooses to undo the resetting of the turtle to its original shape, it works as it should until the TurtleShape function is executed by the undoHandler. For some reason, when the undoHandler executes the TurtleShape function, even when I give a valid argument for the iop attribute of the TurtleShape function (as you can see in the if j.__name__ == "TurtleShape": code block), the else statement is executed first (i.e. the file dialog comes up instead of continuing from the if statement). Only if the user clicks cancel in that dialog will the turtle get set to the previous image.
What is wrong in my code that is leading to this occurrence, and how would I stop this from happening? I have tried changing the klob attribute in the function where the output is saved in the undoHandler function to, for example, "SaveImage", but still no luck. I have also tried to add an if-elif statement in the TurtleShape when it is supposed to choose between iop or a file dialog as the value for klob, but still the issue occurs. Apparently, it executes the elif statement even when it is not necessarily true. Therefore, any help is very much appreciated in remedying this issue! :)
It's happening here:
j = i.getfunction()
j()
If the function you've just gotten is the TurtleShape() function, then you're calling it once with its default arguments (i.e., iop = None). Then you go into your big if j.__name__ == "TurtleShape": statement and call it again inside the if block.
Move that j() call into the else: block of your big if j.__name__ == "TurtleShape": statement, and your problem should go away.
Does that brief explanation make enough sense for you to understand why the problem is happening? Or do you need me to explain a bit more in-depth how calling j() is calling TurtleShape with the parameter iop = None?

Count number of times function with varying arguments executed, then reset count when ENTER key pressed

I would like to be able to count the number of times a defined function that requires a varying argument is executed, then reset that counter to 0 every time the ENTER key is pressed. I want to be able to utilize this action with the defined function below:
def draw(x):
global drawing
q.put(x)
process = False
drawingLock.acquire()
if not drawing:
process = True
drawing = True
drawingLock.release()
if process:
if not q.empty():
x()
drawingLock.acquire()
drawing = False
drawingLock.release()
This function is a queue that takes function arguments and executes them one by one, and the arguments for this function are functions that draw letters in the turtle graphics window. Additionally, this function gets called by a keypress of a certain letter that corresponds to the letter drawn. For example:
onkey(lambda: draw(draw_A), "a")
# This draws an "A" in the Turtle Graphics window when "a" is pressed on the keyboard
# If multiple "A"s pressed, it draws them one by one
How would I count how many times this draw() function has been executed by the user in the turtle graphics window, and then reset it every time the ENTER key is pressed? I have tried creating a decorator for this, but the ones I have created does not return ANYTHING with turtle graphics, and does not seem to work with functions whose arguments can vary with those chosen by the user. Any help regarding this issue is greatly appreciated! :)
Functions allow attributes:
def draw(x):
if not hasattr(draw, 'counter'):
draw.counter = 0
draw.counter += 1
# body
Catch the ENTER from the user:
def handle_enter():
draw.counter = 0
onkey(handle_enter, 'Enter')
Find out how many times it has been called:
print('`draw` has been called {} times'.format(draw.counter))

Categories