I want a Maya camera orbiting a mesh while user chooses what to do with that mesh on my own script interface.
So i have a while orbiting the camera, but no way to interact with user interface while this happens.
There is anyway to "share", or part the focus in second's decims to be able to interact with user interface?
I tried with cmds.evaldeferred(), but no luck...
Technically, Maya widgets interface is immediately available when script finishes the job...
I'm trying to finish the job with one single camera little orbit, and relaunch it with mouse movement event... Time changing event... But no way how to do that... Would be like a daemon running in the background... No idea how I could reach something like that....
Some code:
import maya.cmds as cmds
#declares global variable
global orbitCam
#just something to see in the scene
cmds.polyCube()
#function to stop camera orbit
def stopOrbiting():
global orbitCam
orbitCam = False
#simplest ui
cmds.window("testWindow")
cmds.formlayout("flo", parent="testWindow")
#button that calls stopOrbit function
cmds.button("pushMeIfYouCan", parent="flo", label="pushMeIfYouCan", c="stopOrbiting()")
cmds.showWindow("testWindow")
#condition for the while
orbitCam=True
#while itself
while orbitCam:
cmds.orbit("persp", ra=(0.2,0.1))
Any way to be able to push the button -and interact with widgets- while camera orbits?
Well, based on solution provided by mhlester in the link I posted under the question (and considering a great answer too by theodox, as a wonderful alternative, thank you both, guys), I'm gonna aswer my own question and provide another new detailed explanation perhaps can help somebody in the future.
First of all, Maya's "scriptjob" command utility puts in memory a script (or a function), haves a trigger to start executing that function, and the condition to Maya to execute that function once registered and triggered, is that Maya must to be doing exactly nothing, so, Maya must be idle.
Being that way, Maya never collapses or crashes or hangs by a scriptJob. ScriptJob is basically a... kind of "daemon" working in the background.
The good thing, is that is possible to limit the maximum number of times per second, so you can even maintain your system fresh and working if you want to care it about.
Once a scriptJob is launched (or registered in Maya memory), it can be killed to never runs again, and obviously, can be registered again if we want to start working again.
Exists an internal scriptJobs list inside of Maya, where you can find the scriptjob if you have forgotten to store that scriptJob in a variable, where you can find the "scriptJob ID", just an integer number you can use to kill the job.
After the first theory, let's see some code now:
This line will register a new daemon (maya scriptjob), its reference will be stored in "activeDaemon" variable, it will call a function called "camDaemon" with some arguments:
activeDaemon = registerDaemon(0.04, BackgroundFunction, ArgumentsForBackgroundFunction)
The point here is not just launch the daemon with conditions, besides, to store the daemon id to be able to kill it with:
cmds.scriptJob(kill=activeDaemon)
If we forgotten to store the daemon (scriptjob) id, we can use this command to watch a list with all scriptJobs of Maya:
cmds.scriptJob(listJobs=True)
We would need to find the last ids in the list with the event "idle", and probably we could hit and finished stopping our daemon killing it.
Now let's see "registerDaemon" function (all the absolute credit for MhLester):
def registerDaemon(seconds, backgroundFunction, *args, **kwargs):
def updateNow():
now = time.time()
if now - updateNow.then > seconds:
updateNow.then = now
backgroundFunction(*args, **kwargs)
updateNow.then = time.time()
return cmds.scriptJob(event=("idle", updateNow))
registerDaemon defines an internal function (updateNow) that calls "automatically" at the backgroundFunction we pass as argument, including this "backgroundFunction" arguments. Just that. A function A that defines a function B that calls a function C. And it calls it every quantity of seconds we specify at register the daemon with the first argument, so if we want it executed 25 times per second, 1seg/25fps = 0.04 would be the right value.
To have this function working, we must import the module time in our script with:
import time
Finally it returns the scriptJob id at the same time it registers it in Maya memory, registering with the event "idle" and with the function (B) that calls the function (C) we really want executed in the background. This way we can control the temperatures of the machine not overwhelming the cpu unnecessary. Very complete last line, brilliant, at least, for me.
At this point no other thing left than just register the function we want to have running the background in the Maya memory (take the code you want in the background, put inside a function and execute it one time in Script Editor)
def backgroundFunction():
print "this message shows in idle time by a daemon (Maya scriptjob)"
Of course there are much more in the documentation (Maya scriptJob documentation), as a list of events or conditions, but the base is this.
Related
my software uses the subprocess.call([sys.executable, SCRIPT_NAME] instruction in order to open others kind of scripts specified by the user using a GUI (Tkinter). I have two issue with this instruction:
the "command line" scripts start and close themeselves quicly and it means that the user can't interact with them. it's a weird behaviour because in all of them there is an input instruction, so they should wait an input by the user before to close themeselves. how can I solve this issue?
the "GUI" scripts instead, start without any kind of issue, but their "life", let me say, put in stuck the main script (it uses Tkinter). in this case I can interact with the second script but not with the main one. how can I call my other scripts with the subprocess.call() function whithout put in stuck the main one? from my point of view this issue happens because the second script is a part of the same process of the main one and in this case Tkinter has to wait. if we open the others scripts using different processes for all of them the main script would be free to live its life independently of the others. but how can I do it?
I have a GUI program built using Tkinter in python 2.7.10.
It works flawlessly, for it's root cause anyways.
Unfortunately, it briefly goes into windows dreaded "Not Responding" state when being interacted with.
Here's the layout in short:
Launch script launches Main script.
Main script reads settings file and boots GUI script.
GUI script starts GUI.
User enters a term to search for in a series of files.
GUI script goes into a side script to process files and retrieve results.
Side script inherits certain aspects of GUI script.
Side script attempts to update user while working using the inherited elements; the GUI has none of it.
GUI goes non-responsive briefly before returning to the GUI script and displaying the results.
Here's how I need it to go in short:
Launch script launches Main script.
Main script reads settings file and boots GUI script.
GUI script starts GUI.
User enters a term to search for in a series of files.
GUI script goes into a side script to process files and retrieve results.
Side script inherits certain aspects of GUI script.
Side script updates the user with a progress bar and imagery while working, using the GUI elements.
GUI returns to the GUI script and displays the results.
I have the progress bar built, but the imagery is not yet, but if the progress bar will not work, I will not waste my time on the imagery.
Sample impossible, not-being-used-but-shows-the-point code;
GUI;
import Tkinter, PIL, SideScript1
Tkinter()
ShowText()
ShowStuff()
input = GetInput()
ShowProgressBar()
SideScript1.processfilesbasedoninput(input, progressbarcontrolvar)
DisplayResults()
SideScript1
def proccessfilesbasedoninput(input, pbcv):
DoStuff()
pbcv.gofurther(5)
DoMoreStuff()
pbcv.goevenfurther(10)
a1sauce = RandomMathsStuffs()
for all the data in every file in that one directory:
ReadData()
pbcv.goabitfurther(a1sauce)
if data is what I want:
break
pbcv.step(-100)
return data
I guess my question is, How would I get the GUI to update those elements instead of going unconscious?
We are talking 100 000 files and 1.5 seconds its done in.
UPDATE: This question has been marked as a duplicate of another. Is it? Yep. but that's both because I was ((and still am)) unsure of how to search for this kind of question, and that the three solutions there; multithreading, multiprocessing, and smaller tasks. Unfortunately, the program was built to run on a single thread and process, and without a complete rewrite, getting the intended GUI response would cause a massive slowdown, if it worked at all.
I do see the issue, being TKinter is a blocking module. Unfortunately, I am fresh out of ideas on how I would un-block it without causing mass errors, and or a total rewrite.
The linked duplicate question held an answer. A bad one - but an answer none the less.
update_idletasks.
I tried that, and, it Worked! Well. Sort of.
It worked at first, then the same result came about. The GUI temporarily froze.
Then an idea popped in my head. Why not try update instead?
I did so, and it worked as I needed it to, however, it had a massive performance hit - nearly identical to update_idletasks.
To tackle this new problem, I added a bit more math to cause updates to happen, in my case, every 300 files, instead of every single file-balancing the performance hit and users not instantly deleting my program, because yes, it takes a toll on your resources. No, I did not initially heed that advice. Shoot first, ask questions later, right?
How did I use it? Glad I asked! Here's an example;
#GUI Code
DoStuff()
SideScript1.proccessdata(arg, kwarg, debate)
DoMoreStuff()
#File Management Code
DoStuff()
filenumber = 0
maxfilenumber = 0
for every file I need to search:
SearchFile()
filenumber +=1
if filenumber == maxfilenumber:
tkinter.update() #in my case, it was tkinst, or "TkInter Instance", since it was inherited from the GUI attributes.
filenumber = 0
if data is what I want:
break
return data
I'm not sure about all the backend and hard facts, but update() seemed a lot more user friendly and quicker than update_idletasks(), and a lot less prone to errors and slowdowns as well.
My shenanigans are now back in order, running in 60 ((30? 120? 250 million??)) frames a seconds, smoothly and efficiently - and Tk doesn't have a sit-down strike every time I ask it for info anymore!
Thanks #Rawing for the attempt to help!
I am building an app that, when the user hits a 'run' button, generates a table of buttons.
Because this process takes a while, I want to add a popup or progress bar to alert the user that the function is running and not frozen. To do this I decided to create a popup and call my function using threading so that the screen will be updated when the function starts (as opposed to once it is done).
mythread = threading.Thread(target=run_function)
mythread.start()
The trouble is that when I call my function from the above code it works very strangely: the columns of my table are the wrong width, some of my buttons are arbitrarily empty, and others have the wrong fill color. To fix this, all I need to do is to remove the threading operation and simply call run_function()
Any idea why this is happening?
I am new to Python, so it is likely some dumb mistake, but I have no idea. What is different between a process running as a thread and its default operation?
Disclaimer: I haven't worked with Kivy.
Not every framework works well with multithreading.
But most of the GUI frameworks have an event loop which is responsible for managing user events (mouse clicks, keyboard) and queued drawing operations (widgets).
In your case if don't want the UI to be freezed, you should regularly give control to your framework's event loop.
I guess kivy.base.EventLoopBase.dispatch_input is what you need to call to show an added widget or to handle user events.
I am working on a gesture recognition project. There is a C program that captures the gestures from video input and write them to the file. Now, I have an image viewer written in Python - GTK. It switches to the next or previous window according to gestures. This continuous file read and application update is defined as follows:
def ai(self):
if self.mtime!=os.stat("input.txt").st_mtime:
self.mtime=os.stat("input.txt").st_mtime
inp=open("input.txt", "r");
line=inp.read()
if len(line)!=0:
line=line[0:len(line)-1]
for x in line.split(' '):
y=x.split('-')
if(y[1]=="R"):
self.next()
print "Move Right"
elif(y[1]=="L"):
self.prev()
print "Move Left"
time.sleep(1)
print "WakeUp"
self.ai()
Now if I comment out the recursive call here, then application works after reading present file and updating images. Of course, then it doesn't update afterwards.
But if I uncomment the recursive call, then the console keeps on working but image-viewer application stops responding.
Is there any way to perform this function? Any event where i could bind this ai() function that could check for file updates every time that event is fired...
Any help would be appreciated.
Not sure if I understand you correctly, but I would expect what you want to do is to schedule a call to ai() in your main GTK loop, so that your program checks if there is input on a regular base.
If this is what you want you have two choices: scheduling the call periodically or schedule the call for when the program is idle (it is not doing anything else).
Your code should look something like:
gobject.idle_add(callback, ...) #execute callback when idle
gobject.timeout_add(interval, callback, ...) #execute callback every interval millisecs
The documentation should be here but presently there is a server error. Here are the relevant passages:
The gobject.idle_add() function adds a function (specified by callback) to be called whenever there are no higher priority events pending to the default main loop. The function is given the default idle priority, gobject.PRIORITY_DEFAULT_IDLE. Additional arguments to pass to callback can be specified after callback. The idle priority can be specified as a keyword-value pair with the keyword "priority". If callback returns FALSE it is automatically removed from the list of event sources and will not be called again.
The gobject.timeout_add() function sets a function (specified by callback) to be called at regular intervals (specified by interval, with the default priority, gobject.PRIORITY_DEFAULT. Additional arguments to pass to callback can be specified after callback. The idle priority may be specified as a keyword-value pair with the keyword "priority".
A catch: you have your callbacks to return True if you want to keep them in the scheduler, failing to do so will make them execute only once.
HTH!
Disclaimer: I have no experience whatsoever using pygtk.
I guess to make this work, you have to let the GTK event loop call your code (your recursive call makes it so that control never returns to the event loop).
You probably have two options:
Either set up a timer event to call your method every nnn milliseconds (tutorial)
Or use some sort of idle event to call your method whenever the GTK program is otherwise idle (tutorial)
Since you're using gtk, you could use gio module to do the monitoring for you, instead of your own custom solution to periodically poll the file state:
monitor = gio.File(filename).monitor()
monitor.connect('changed', file_changed_cb)
Note that you can connect the changed signal to your callback to perform any update that you need.
OK, I'm trying to explain what I want to achieve in another way. Here's an example:
Say if it's an anti virus program, and user can choose between two ways to run the program, choice one, automatically start to scan disks for virus when the program starts up, choice two, hit the start button to make the program scan disks for virus after the program starts up any time the user wants. So, as a wxpython beginner, I know how to bind wx.EVT_BUTTON to let scanning start after the user hit the start button, but I don't know how to make the scanning start once the program starts up. I wonder if there's a program_start event I can bind? Hope you guys can help me out. Thanks!
In wxPython you can override the OnInit method of your Application class to run code when the program launches. For example:
def OnInit(self):
# Check for a running instance for this user. Do not instantiate if found.
if self.checkInstance():
dbcon.cursor().callproc('post_mutex', (self.mutexname,))
dbcon.commit()
self.Cleanup()
return False
# Register for database events.
DataCache['dbListener'] = dbListener()
return True
There is of course another method on my Application class called checkInstance. Depending on it's return value, my application either launches, or triggers the other running instance to launch.
In wxPython you don't have to do anything special with your App class to get the binding to take place for your OnInit method. It'll happen automatically if you override it.
Why don't you run it just in module code? This way it will be run only once, because code in module is run only once per program instance.
In your init or OnInit method, do some kind of check to see if the program should run the startup process on startup (i.e. check a config file or some such). If yes, call the "scan" method using wx.CallAfter or wx.CallLater or call it after you Show() the frame.