Why my progressbar in toplevel window is not moving? - python

I am actually creatng a gui which include searching data.I want to show a loading progress bar (indeterminate) to show results are being loaded .I want this progress bar in a new toplevel window but I tried to place it but it didn't showed at first.So after many research ,I make it to appear on screen but there is a problem with it. It opens the window with progress bar and everything freezes and progressbar doesn't work itself.But window is destroyed on time.I want that progressbar moves so that it looks responsive so that user gets idea that something is going on.I start progress bar just before loading results and then starts loading results which include for loops for 2-3 times then all results are gathered then the toplevel window is completely destroys .
Everything is happening accept the new window is freezing and progressbar is not moving.
I have tried everything I could.
class Loading:
def __init__(self,title):
self.title = title
self.window = Toplevel()
self.window.geometry('350x40+100+100')
self.window.title(self.title)
self.window.lift()
self.window.grab_set()
self.window.focus()
def start(self):
self.pbar = Progressbar(self.window, orient="horizontal",length=300,
mode="indeterminate")
self.pbar.place(x=10,y=5,height = 20,width = 300)
print('starting loading')
self.pbar.start()
self.window.update()
def stop(self):
self.window.destroy()
I want that my toplevel window display progressbar moving till all rseults are loaded from different files and it gets destroyed after this

Maybe you can try this snippet of code !
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.geometry('100x100')
def progressbar():
pwin = Toplevel(root)
pwin.geometry('350x40+100+100')
pwin.title('Sample progressbar')
pbar = Progressbar(pwin, orient="horizontal", length=300,
mode="indeterminate")
pbar.place(x=10, y=5, height=20, width=300)
print('starting loading')
pbar.start()
pwin.update()
Button(root, text='PBAR', command=progressbar).pack()
root.mainloop()
And then you can use pwin.destroy() to destroy the progressbar after loading is finished !

Related

How to disable the movement of the Tkinter Window without removing the title bar

I have been creating an application for taking the test. So, for that, I have to do two things.
First, disable the drag of the Tkinter window and don't let the user focus on other windows rather than my application window. This means I wanted to make my application such that, No other application can be used while my application is in use.
Try this:
import tkinter as tk
class FocusedWindow(tk.Tk):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Force it to be unminimisable
super().overrideredirect(True)
# Force it to always be on the top
super().attributes("-topmost", True)
# Even if the user unfoceses it, focus it
super().bind("<FocusOut>", lambda event: self.focus_force())
# Take over the whole screen
width = super().winfo_screenwidth()
height = super().winfo_screenheight()
super().geometry("%ix%i+0+0" % (width, height))
root = FocusedWindow()
# You can use it as if it is a normal `tk.Tk()`
button = tk.Button(root, text="Exit", command=root.destroy)
button.pack()
root.mainloop()
That removed the title bar but you can always create your own one by using tkinter.Labels and tkinter.Buttons. I tried making it work with the title bar but I can't refocus the window for some reason.
One way to do this is by the following, another could be to overwrite the .geometry() method of tkinter.
In the following code I simply had get the position by using winfo_rootx and winfo_rooty. After this you can force the window by calling the geometry method via binding the event every time the window is configured.
import tkinter as tk
def get_pos():
global x,y
x = root.winfo_rootx()
y = root.winfo_rooty()
def fix_pos():
root.bind('<Configure>', stay_at)
def stay_at(event):
root.geometry('+%s+%s' % (x,y))
root = tk.Tk()
button1 = tk.Button(root, text='get_pos', command=get_pos)
button2 = tk.Button(root, text='fix_pos', command=fix_pos)
button1.pack()
button2.pack()
root.mainloop()

display single image in fullscreen mode (like powerpoint)

I am trying to open an image in fullscreen to overlap the taskbar and show no menu bar using python.
I got it to work using Tkinter with following code, but since its just a single image that does not need to be updated (ever), the blocking loop of mainloop() is very inconvenient and unnecessary. However, I can't get tkinter to stay open without that update loop. I've tried using root.after() to run the function afterwards but that froze my program (and isn't really what I want to do anyway)
root = tk.Tk()
root.update_idletasks()
root.attributes('-fullscreen', True)
root.overrideredirect(1)
output = self.create_image_from_array(image_array)
canvas = tk.Canvas(root, width=root.winfo_width(), height=root.winfo_height())
canvas.create_image(0, 0, image=output, anchor="nw")
canvas.pack(fill=tk.BOTH, expand=1)
# after freezes my window
# root.after(0,someFunction)
# main loop blocking the function.
root.mainloop()
How can I display a single image on the entire screen using python (in both windows and linux) or how can I "pause" the tkinter loop to prevent the window from closing and updating?
It looks like you will have to handle tkinter's thread yourself rather than relying on mainloop(). Here is one way to do it:
import tkinter as tk
from threading import Thread
import time
class SomeFunc:
def __init__(self):
self.running=True
t = Thread(target=self.func)
t.start()
def func(self):
self.root = tk.Tk()
self.root.update_idletasks()
#root.attributes('-fullscreen', True)
#root.overrideredirect(1)
canvas = tk.Canvas(self.root, width=self.root.winfo_width(), height=self.root.winfo_height())
#canvas.create_image(0, 0, image=output, anchor="nw")
canvas.pack(fill=tk.BOTH, expand=1)
while self.running:
self.root.update()
a = SomeFunc()
x = 10
while x:
x-=1
time.sleep(1)
print(x)

Python Tkinter, destroy toplevel after function

I'm programming some drives with python using Tkinter as GUI. When my machine is running, I'd like to show the user a toplevel window with some information which should close itself after the function completes. This is my minimal example:
from Tkinter import *
import time
def button_1():
window = Toplevel()
window.title("info")
msg = Message(window, text='running...', width=200)
msg.pack()
time.sleep(5.0)
window.destroy()
master = Tk()
frame = Frame(width=500,height=300)
frame.grid()
button_one = Button(frame, text ="Button 1", command = button_1)
button_one.grid(row = 0, column = 0, sticky = W + E)
mainloop()
The main problem is, that the toplevel window just appears after 5 seconds are over. Any suggestions?
Thanks!
time.sleep(5) is launched before the GUI has time to update, that's why the toplevel only appears after the 5 seconds are over. To correct this, you can add window.update_idletasks() before time.sleep(5) to force the update the display.
But, as Bryan Oakley points out in his answer, the GUI is frozen while time.sleep(5) is executed. I guess that your ultimate goal is not to execute time.sleep but some time consuming operation. So, if you do not want to freeze the GUI but do not know how long the execution will take, you can execute your function in a separated thread and check regularly whether it is finished using after:
import Tkinter as tk
import time
import multiprocessing
def function():
time.sleep(5)
def button_1():
window = tk.Toplevel(master)
window.title("info")
msg = tk.Message(window, text='running...', width=200)
msg.pack()
thread = multiprocessing.Process(target=function)
thread.start()
window.after(1000, check_if_running, thread, window)
def check_if_running(thread, window):
"""Check every second if the function is finished."""
if thread.is_alive():
window.after(1000, check_if_running, thread, window)
else:
window.destroy()
master = tk.Tk()
frame = tk.Frame(width=500,height=300)
frame.grid()
button_one = tk.Button(frame, text ="Launch", command=button_1)
button_one.grid(row = 0, column = 0, sticky = "we")
master.mainloop()
A general rule of thumb is that you should never call sleep in the thread that the GUI is running in. The reason is that sleep does exactly what it says, it puts the whole program to sleep. That means that it is unable to refresh the window or react to any events.
If you want to do something after a period of time, the correct way to do that is with after. For example, this will destroy the window after five seconds:
window.after(5000, window.destroy)

Automatically Activate Main Window in TkInter

Is it possible to automatically activate the main window of a tkinter app? I am using Yosemite on a Mac. When the window comes up, the title bar is grayed out, and I have to click on the window before it will respond to events. The Tk manual says that event generate, "Generates a window event and arranges for it to be processed just as if it had come from the window system." I tried generating a <Button-1> event, but it had no effect. The manual goes on to say, "Certain events, such as key events, require that the window has focus to receive the event properly." I tried focus_force, but it didn't work either.
Is it possible to do what I want? Is this a Mac peculiarity? In the code below, the text changes as the mouse cursor enters and leaves the label, but the app is unresponsive until you click on the window.
import tkinter as tk
root = tk.Tk()
def visit(event):
kilroy['text'] = 'Kilroy was here.'
def gone(event):
kilroy['text'] = 'Kilroy has left the building'
def startup():
root.focus_force()
root.event_generate('<Button-1>')
frame = tk.Frame(root, width=500,height=100)
kilroy = tk.Label(frame, text="Kilroy hasn't been here.", width = 50)
kilroy.grid(row=0,column=0)
frame.grid(row=0,column=0)
kilroy.grid_propagate(0)
frame.grid_propagate(0)
kilroy.bind('<Enter>', visit)
kilroy.bind('<Leave>', gone)
root.after(100,startup)
root.mainloop()

Refreshing a window in Tkinter

I am trying to make a GUI in Tkinter and am wondering how to refresh a window, namely if I fill in a rectangle, I want the GUI to delete it a specified time later. How would I go about doing this? Documentation on Tkinter seems to be thin...
Each Tkinter widget has a after method, which you can use to call your rectangle delete function e.g. in the example below first I change a msg using after, and then destruct the window using after
from Tkinter import *
def changeMsg():
label.configure(text="I will self destruct in 2 secs")
label.after(2000, root.destroy)
root = Tk()
mainContainer = Frame(root)
label = Label(mainContainer, text="")
label.configure(text="msg will change in 3 secs")
label.pack(side=LEFT, ipadx=5, ipady=5)
mainContainer.pack()
label.after(3000, changeMsg)
root.title("Timed event")
root.mainloop()

Categories

Resources