The people who are familiar with the Live Server of VS Code, would have easily understood what is the main motive of this question.
But for others, here's the explanation:
Main motive of Live Server is to Automatically Reload Your Site on Save in web development! (Which get changed for python tkinter).
When ever I change something in my python file which contains tkinter code, the change should be reflected in the main window (the main window should not re-open to reflect the changes).
I have tried to search on web as well as on stack over flow, but all the results are for updating value in entry, label, buttons etc. But what I want is, the whole window should be updated when ever I change something in my main file, and the main window should not be reopened to do so. So in short, updating whole window without closing it, on every changes in the main file or automatically reload your program on save without reopening!
What have I tried?:
I tried to detect change in file using os.getsize which satisfied the first part of my question, but however I am not able to solve the second part i.e window should not be closed.
import os
main__tkinter_filename="myfile.py"
initial_filesize=os.path.getsize(main_tkinter_filename) # Getting size of the file for
# comparison.
while 1:
final_filesize=os.path.getsize(main_tkinter_filename)
if final_filsize<intial_filesize or final_filesize>initial_filesize:
webbrowser.open(main_tkinter_filename)
Example:
from tkinter import *
root=Tk()
root.mainloop
results in the below GUI:
If i have added a=Label(text='text')anda.pack() after root=Tk(), it should show me the label, and if i have removed the same code, it should remove them.
I will answer your question by the best of my understanding,
I have some (a few projects of my own, still way too limited) experience with flutter which has hot-reload feature (same as you described above, which you want with python, mainly tkinter), I recently switched to python for gui (Loved it!), so I would like to share my research here:
I was successfully able to set up hot-reload both with kivy (kivymd hot reload, which comes with watchdog and kaki, which works real-time), and with tkinter, while there is a hitch with the later, you will have to press Ctrl + R as to reload the tkinter window, but it works without having to re-run the python program, I will leave the link to the found resources here, hope it helps with your query!
To setup hot-reload with tkinter (requires Ctrl + R), please refer here.
To setup hot-reload with kivy/kivymd (real-time), which I personally prefer, you can find the official docs here.
To mention, I use the above on Manjaro (Arch linux) with pycharm, atom, but I have also tried and have made it run successfully on Windows 10 with vs code (worked like charm)
Hope I could be of help! If you face any problem regarding the same, please feel free to ask! Thanks!
After digging around I have finally found out a way to implement hot reload feature (which #Stange answers provides) but just updating the selected frame or code.
The basic idea is constanly reading the file and executing the selected code, and removing the object in a list which are meant to be removed.
# Live Checker.py
import keyboard
while 1:
if keyboard.is_pressed("Ctrl+r"):
with open('test.py','r') as file:
file_data=file.read()
file_data_start_index=file_data.find("'#Start#'")
file_data_end_index=file_data.find("'#End#'")
exec_command=file_data[file_data_start_index:file_data_end_index]
with open('exec_log.txt','w') as txt_file:
txt_file.write(exec_command)
Here I am constantly checking if if ctrl+r key is pressed, and if pressed
it reads the file,
writes the selected code from the file into a txt file.
I have specified the start and end of the code to be updated by #Start# and #End# respectively.
# Main.py
def check():
with open('exec_log.txt','r') as exec_c:
exec_command=exec_c.read()
if len(exec_command)==0:
pass
else:
print(exec_command)
exec('for i in root.winfo_children():i.destroy()\n'+exec_command)
print('exec')
with open('exec_log.txt','w') as exec_c:
pass
root.update()
root.after(100,check)
root.after(100,check)
And in the main file, i have added the above code which continusly check if exec_log.txt file has any changes, and if changes are there, then it executes them and all so destroys the widget specified in the remove_list.
This is just a temporary solution which in my case helps me to implement the hot reload feature in tkinter.
Related
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.
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’d like to create a restricted folder/ file explorer in Python (I have version 2.7.9, but I don’t mind changing that) for Windows.
Essentially, I want to initially specify the folder to which the code opens. For example, the code should initially open to: C:\Users\myName\Desktop\myDemoFolder (the user must not know this folder simply by looking at the GUI).
The user must be able to browse downwards (deeper into folders) and backwards (but only up to the initial folder to which the code opens). The user must be able to click to open a file (for example: pdf), and the file must automatically open in its default application.
An example of what I’d like is presented in figure 1. (The look of the interface is not important)
Currently, I am able to get figure 2 using the code presented here:
from Tkinter import Tk
from tkFileDialog import askopenfilename
Tk().withdraw()
filename = askopenfilename()
print(filename)
Research has indicated that it is not possible to change the default buttons in Tkinter windows. Is this true? If it can’t be done with Tkinter (and that’s fine), how else can we do it?
I’d happily choose simple, non-Tkinter code (perhaps using wxPython’s wx.GenericDirCtrl()) rather than elaborate Tkinter code, but no restrictive libraries please.
A modular design approach is not needed. I’d rather have simple (functional) code that is shorter than object-oriented code.
I was trying to do the same thing when I realized that maybe you could create all the buttons you need and then set the color of the buttons you don't need to your background color using:
button-name.config(bg = "background-color")
Just change the "button-name" to your button's name and set "background-color" to the background color!
I think I've pretty much narrowed down the problem, so I'll put it out here:
I made a change to the program I am working on. The change makes a certain tkinter window reopen when an error occurs. This was done by moving it to a function, and having the script call the function if it needed to. This solved users having to restart the program.
All the windows in my program have an icon that is called and implemented in every window using the following lines:
Thumbnail = PhotoImage(file = "C:\\Users\\Owatch\\Pictures\\NetSendClient\\files\\GIF\\TK_ICON.gif")
Window.tk.call("wm","iconphoto",Window._w, Thumbnail)
This works fine for every single window across the program. However, it continues to generate an error when the same window is called to open a second time.
Error:
File "C:\Users\Owatch\Documents\Unisung\Produced Content\NetSendClient[0.9]\files\Program_Files\NS[9].py", line 208, in SCN
Window.tk.call("wm","iconphoto",Window._w, Thumbnail)
_tkinter.TclError: can't use "pyimage4" as iconphoto: not a photo image
I'm not sure why this error occurs the second time the window is opened. To give some more information on why it needs to be reopened. When a user presses a button inside this window, it triggers a function that calls the window to be destroyed before it is later reopened. So maybe it's because it's not being cleanly disposed of or something. I don't know. Thanks for helping!
The problem was created by a confliction between multiple windows using the same icon simultaneously.
I cannot go any more specific than that, but the issue was resolved by eliminating temporary and toplevel windows that did not destroy themselves before another opened.
I hope this can be of some assistance to other individuals. I am afraid I cannot provide any more information than this.
I am planning to do the folliwing:
Create a PyGtk GUI (hardcoded, no Glade) with some widgets, and at the bottom of the screen put some sort of VTE (Virtual Terminal Emulator) from where I could manipulate the widgets, for example changing their attributes and calling their methods from the commandline.
The result would be similar to using AutoCAD's commands, only that I would be acting upon the GUI objects.
I have already found very few things about gtk.VteTerminal widget, but not only could not find a working example or make one myself, it also seem to be a system terminal, not a "current session" python terminal where I could run python commands and access GUI objects.
Any suggestion?
Thanks for reading
What you want exists already: GtkParasite. It's meant for debugging, but I'm sure if you wanted it to actually be a part of your application, you could adapt it.
I'm late to the party, but I had a similar problem.
Look here
Virtual Terminal Question
It's an option if you decide to do something different than what you might have already done.