TkInter; Non-responsive when being told to update - python

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!

Related

Working with Excel 4.0 for work, trying to use a button to launch a python script

So, the shop where I work use Excel 4.0 for all its inventory management and orders.
Since the guy before me left without explaining anything, I inherited an old system that works, but is... eh.
The bosses don't want to change to a new Excel nor another program, so I must do what I can with what I have.
Now, I've made a script in python 2.5.4 (this version is needed because the newer versions won't work on the Windows 98 computer they use...) to automate some processes that would be impossible with Excel 4.0 macros, and the script works perfectly for what I need.
But since the bosses want to "only work with Excel", and won't want to go outside of Excel and click the script icon to start it (or, heaven forbid, open cmd and start it manually), I would need to put a button in Excel to start the script.
I've tried to sift through the macros available, but except perhaps "Initiate" (which I don't wholly understand as of now), I can't think of a macro to interact with the script, and haven't found much help with what's available online...
SO, could anyone please help me in making the macro for the button? The only thing the button would need to do is to start the python script, there's no other interactions needed, the rest is done by the script.
Like, the script "foo.py" is in the same folder as "bar.xls", and I only need a button in "bar.xls" to launch "foo.py".
Thanks.
Okay, I found a roundabout way, so I'm gonna share it with y'all.
MacroName
=LAUNCH("cmd",1)
=SEND.KEYS("foo.py~";TRUE)
=SEND.KEYS("exit~")
=RETURN()
It opens a cmd instance, show it for a split second (can't use SEND.KEYS without it being the active app), writes the name of the python script and presses enter, before quitting.
I would like if it didn't need to show the cmd window, but it works for now. Perhaps there'll be another way, but if anyone else wanna do what I did, it does work.
You probably need to get the book out - Excel 4 came with one book called the Function Reference which listed all the commands available.
Commands that we used back in the day were:
EXEC: starts another program
EXECUTE: runs commands in another program called by Initiate
INITIATE: sets a channel to a program
SEND.KEYS: sends keystrokes to a program (we used to send data to a slow server this way...)
Not sure what will be on the web for Excel macro 4, it was retired as vba came out and Excel moved over...
I still use my copy of the book, but it would be worth finding, although the help should list the commands as well. I just used the book as I had macros running...

How to make python program that runs game files at the same time as main code

So I'm very new to Python so I'm not sure of the correct way to do what I need.
Basically I am creating a laser tag game. The whole game is controlled by some python code that runs on a PC, the hardware is basically just inputs and outputs for this code.
I want to have game files that are simple files with just the code for the game itself, that way it is fairly easy for anyone to make their own game modes.
Then there needs to be a main program with a GUI (Probably Tkinter) and code to handle sending/receiving information from the hardware (Laser tag guns). I need some way to select a game file from the GUI and run it, but I still need the main server code to be running (to take care of sending and receiving information from the guns, displaying live scores on the GUI, etc).
What would be the best (preferably fairly simple) way to go about doing something like this? Thanks!
Cool project! Generally you let TkInter run in the main thread, and have the other tasks executed in other threads or processes. Brace for some hacking, parallelism is unfortunately pretty difficult to do right.

Python : How to deal with threads priority in Gtk3

I am building an user interface using Python, Gtk3 and Glade. I want to change several things on the UI at the same time (i.e start an animation and display a new text) which leads to the application freezing.
I have read that Gtk wasn't thread safe so I didn't used the Thread module.
Instead, I used Glib.idle_add and Gdk.threads_add_idle functions. I am tryig to update a treeview, display some text and show an animated logo at the same time. The application works but it freezes a few seconds and then everything appears at the same time. I try to set different priorities to the threads but it does'nt seem to fix it.
Gtk.threads_add_idle(Glib.PRIORITY_DEFAULT, label.set_text, "text_to_set")
Gtk.threads_add_igle(GLib.PRIORITY_DEFAULT, function_to_display_logo)
I expect the different texts and the treeview and the logo to be displayed without any freeze. Does anyone know how I can fix that ?
Please have a look here at a script example in https://github.com/f4iteightiz/UWR_scoreboard : a GTK window is updated all 0,2s for example (countdowns of several timers appearing in labels; I think anything else could be updated) and it stay reactiv the whole time. No freezing noticeable.
I found out what my error was. I was using the GLib.idle_add function too many times even in some cases where I had no use for it.
For example in the main code I had :
Glib.idle_add(my_function,buffer)
but my_function looked like this :
def myfuntion(buffer):
GLib.idle_add(buffer.set_text,"text")
I deleted the GLib.idle_add call in the main code and now it works perfectly.

Python another option to tkinter label counter

I have a program that I'm currently using tkinter to pop up a window and use the root.title of the window as a counter. I call this program through subprocess mutliple times, aka multiple windows pop up and display that I only have to look at the counter to see how long before each of the programs is finished running.
I want to know how long before each and every process is finished. Doing a bit of testing I don't believe using subprocess it will report back to IDLE and show a counter using print(). At least it doesn't appear to be doing so right now for me.
Is there any way of accomplishing this same task without using tkinter?
Below is the link to the other open question right now that I'm currently using to open the tkinter window that closes on me unexpectedly. I'm not completely sure when a windows closes if the whole program stops running or if just the windows closes. Hence why I want the counter...hence why I have always been using a tkinter window as I don't know of any other way of doing this that serves the same purpose.
I want the counter so I can tell the program was finished if my internet connection gets dropped. I don't have internet access at home so I'm always using free-wifi which quite often has timeouts on it. I want to know for sure whether the programs have finished running or if I got timedout and need to rerun the program.
Python program terminating unexpectedly

Waiting for a program to finish its task

I'd like to know how to have a program wait for another program to finish a task. I'm not sure what I'd look for for that...
Also, I'm using a mac.
I'd like to use Python or perhaps even applescript (I could just osascript python if the solution if for applescript anyway)
Basically this program "MPEGstreamclip" converts videos, and it opens what appears to be 2 new windows while it's converting. One window is a conversion progress bar, and the other window is a preview of the conversion. (Not sure if these actually count as windows)
(Also, MPEGstreamclip does not have an applescript dictionary, so as far as I know, it can't listen for certain window names existence)
But basically I want my program to listen for when MPEGstreamclip is done, and then run its tasks.
If it helps, when the conversion is done, the mpegstreamclip icon in the dock bounces once. I'm not sure what that means but I'd think you could use that to trigger something couldn't you?
Thanks!
I realized GUI applescript was the answer in this scenario. With it I could tell the PROCESS to get every window, and that worked. However, I'm leaving this up because I'd like to know other ways. I'm sure this GUI workaround won't work for everything.
If the MPEGstreamclip actually ends when it is done, you could wrap the whole thing up in a python script using various techniques already discussed in another post. Just be sure to wait for the external process to end before continuing with your other steps.

Categories

Resources