ttk progress bar freezing - python

I want a progress bar that shows the user the download progress. When updating the GUI and downloading at the same time the progress bar freezes, and I understand why but I don't know how to solve it. I tried multithreading using this post:
Tkinter: How to use threads to preventing main event loop from “freezing” and using The Basics of Python Multithreading and Queues as a guid to help me fit it to my needs. The problem is that which way I try to achieve my goal, I always seem to make a mistake when changing it to do what I need it to do.
The most basic version of my code (without multithreading):
from Tkinter import *
import ttk
from urllib import URLopener # Downloading files
# Make frame to tell user what file is getting downloaded
self.Progressmsg = Label(self, text="TempValue")
self.Progressmsg.pack(pady=(10,0))
# Make progress bar to show user download progress
self.Progressbar = ttk.Progressbar(self, mode="determinate", orient='horizontal', lengt=280, maximum=len(self.AllClasses))
self.Progressbar.pack(padx=10, pady=10)
self.Progressbar["value"] = 0
def DownloadFile(Class):
# Update progress message
self.Progressmsg["text"] = "Downloading {0}.ics...".format(Class)
# Download each file from saxion website
CalFile = URLopener()
CalFile.retrieve("http://[school website]/ical/group/{0}.ics".format(Class), "Data/{0}.ics".format(Class))
# Update progress bar
self.Progressbar["value"] += 1
for Study in self.Parameters["Classes"]:
for Class in Study:
DownloadFile(Class)
Notes: In this code AllClasses is a list of different classes from which a calendar file has to be downloaded.
The code itself is part of a fairly large class which I didn't include. This is why I am using self.[variablename]
When this code runs the progressbar doesn't load or update, all the files download properly and when they are downloaded the progress bar updates everything at once. My question is: how do I solve this problem in my case?

Try this:
# Update progress bar
self.Progressbar["value"] += 1
self.Progressbar.update_idletasks()
If it does not work then use self.Progressbar.update() instead.
The GUI won't reflect your changes if there is something else to do (like downloading the next file) unless you call update_idletasks() or update().

Related

Real Time Data with tkinter

I am looking for a simple way to display changing real time data in a GUI in python. I am connected to 2 devices and want to display data constantly (like 20 different values), and when I press a button I want to control the one device.
Unfortunately I fail already with the display of the data. For this I have looked at some tkinter tutorials and explanations.
My idea was to implement it with a config function and to overwrite the label continuously. As example how I wanted to display one value:
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
show_data()
#### or different solution
# showing the data as a lable
data_label_output = tk.Label(window, comand=show_data)
data_label_output.grid(row=1, column=1)
window.mainloop()
Unfortunately, the value is displayed only once at the beginning and nothing changes after that.
Another problem:
When I press the button, I want to be able to control the one device. For this I have a while True loop that permanently checks if a button is pressed and then executes actions. As a separate program no problem, but how do I integrate this into the tkinter GUI? When I start this PyCharm always crashes.
I use PyCharm and Python 3.8
About simple and functional ideas I would be happy, also to other tools/modules etc., as long as you can easily and quickly implement the idea. It's only for a research project and the programming is only a means to an end.
You can use the after method in tkinter to run something after a short delay. The following code will run show_data once the GUI is ready and then again every 1000 milliseconds.
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
window.after(1000,show_data)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
window.after_idle(show_data)
window.mainloop()
This resolves the updating issue, I'm not sure what behaviour you want when you press the button but if you elaborate and explain, I might be able to help and update this answer.

Progress bar for uploading file in Python

I want to upload one large .ndjson to Python. Is there a way to add a progress bar so that I know how much of the file is uploaded?
import json
import pandas as pd
df = map(json.loads, open('dump.ndjson'))
df = pd.DataFrame.from_records(records)
This is the way to upload the file. Code is good because when I split the file into 100 pieces I can upload one by one. But is there a way to add a progress bar so that I can upload the file at once and to see the progress of uploading?
PS. Im not thinking on gui, I have head for tqdm progress bar. I was thinking something like that, so that I can see progress in my console
If the question is about a GUI, there's PySimpleGUI that allows easy using of progress bars that rely on Tk, Wx or Qt frameworks.
This works on Linux / Windows.
Example from their cookbook:
import PySimpleGUI as sg
# layout the window
layout = [[sg.Text('Uploading...')],
[sg.ProgressBar(100, orientation='h', size=(20, 20), key='progressbar')],
[sg.Cancel()]]
# create the window`
window = sg.Window('My Program Upload', layout)
progress_bar = window['progressbar']
# loop that would normally do something useful
for i in range(1000):
# check to see if the cancel button was clicked and exit loop if clicked
event, values = window.read(timeout=10)
if event == 'Cancel' or event == sg.WIN_CLOSED:
break
# update bar with loop value +1 so that bar eventually reaches the maximum
progress_bar.UpdateBar(i + 1)
# TODO: Insert your upload code here
# done with loop... need to destroy the window as it's still open
window.close()
I use that kind of progress bar and keep my upload function in a separate thread so the UI is non blocking.

Python Tkinter Label Refresh Woes

Im back again with another python issue.
A short while ago I wrote a console based program that pulls stats from a bitcoin miner on your local network. I've decided I'd like to turn it into a gui, and choose a combination of EasyGUI and Tkinter for my program.
My input boxes (ip, refresh rate,asic type) are all using EasyGUI, simply to save lines of code as Tkinter would take far more writing to accomplish the same. However, My actual results page is written using Tkinter as it allows me to refresh the displayed data at a user-defined interval.
My issue is this:
I had my program running happily, and then made some small ui tweaks (title, font, etc) and now after my most recent compile (using pyinstaller) I've noticed the stats (labels) don't update at all. I have looked over my code countless times now and cannot seem to find what is blocking the stats from changing at the defined intervals.
I am hoping someone with a fresh pair of eyes can help me find my stupid mistake, as it was running perfectly before these small additions.
Heres a cut-down version that still runs and produces the same issue:
import Tkinter as tk
from pycgminer import CgminerAPI
cgminer = CgminerAPI()
cgminer.host = 192.168.x.x
summary = cgminer.summary()
update = 1000
def L1(label):
def hashrate():
msg = "Your current GH/S = "
speed = msg , summary['SUMMARY'][0]['GHS 5s']
label.config(text=speed)
label.after(update, hashrate)
hashrate()
root = tk.Tk()
root.title("Eyes On Miner GUI V0.2")
label = tk.Label(root)
label.pack()
L1(label)
root.mainloop()
Full code on pastebin, in case you'd like to try to run it yourself. (python 2.7) Full Code
I ran this much of your code, substituting time() for the summary. It works in IDLE. From the console, either run with python -i program.py or add root.mainloop.
import tkinter as tk
from time import time
update = 1000
def L1(label):
def hashrate():
msg = "Your current GH/S = "
speed = msg , time()
label.config(text=speed)
label.after(update, hashrate)
hashrate()
root = tk.Tk()
root.title("Eyes On Miner GUI V0.2")
label = tk.Label(root)
label.pack()
L1(label)
If the problem is not with summary['SUMMARY'][0]['GHS 5s'], then there must be an incompatibility with either CgminerAPI or more likely with easygui. The latter is meant to replace tkinter, not be used together with it. If the code worked at first and then quit, then one of the additional functions you used must have triggered a conflict.

Scrolling Progress Bar in Tkinter

I have been trying to set up a progress bar in a python tkinter gui that shows that a process is running. The process is long and I have no way to really measure the progress, so I need to use an indeterminate progress bar. However, I really dislike the style of the ttk indeterminate progress bar that bounces back and forth. I want one that scrolls across the bar over and over again, kind of like this image
Is this possible with tkinter?
have you tried ttk's determinate Progressbar? You can make the progress just continuously scroll across the bar.
for example:
#!/usr/bin/env python3
import tkinter
import tkinter.ttk as ttk
root = tkinter.Tk()
frame = ttk.Frame()
pb = ttk.Progressbar(frame, length=300, mode='determinate')
frame.pack()
pb.pack()
pb.start(25)
root.mainloop()
I know its an old question, but I have found a way to do this for anyone else writing tkinter.
I've been working on a tkinter app for a bit now and have determined that to handle tkinter objects, you absolutely need a separate thread. Although it is apparently frowned upon to handle tkinter objects via something else than the mainloop() method, it has been working well for me. I've never had a main thread is not in main loop error and never experienced objects that didn't update correctly.
I edited Corey Goldberg's code a bit and got it working. Here's what I got (some explanations in the comments).
import tkinter
import tkinter.ttk as ttk
import threading
def mainProgram(): # secure the main program initialization in its own def
root = tkinter.Tk()
frame = ttk.Frame()
# You need to use indeterminate mode to achieve this
pb = ttk.Progressbar(frame, length=300, mode='indeterminate')
frame.pack()
pb.pack()
# Create a thread for monitoring loading bar
# Note the passing of the loading bar as an argument
barThread = threading.Thread(target=keepLooping, args=(pb,))
# set thread as daemon (thread will die if parent is killed)
barThread.daemon=True
# Start thread, could also use root.after(50, barThread.start()) if desired
barThread.start()
pb.start(25)
root.mainloop()
def keepLooping(bar):
# Runs thread continuously (till parent dies due to daemon or is killed manually)
while 1:
"""
Here's the tricky part.
The loading bar's position (for any length) is between 0 and 100.
Its position is calculated as position = value % 100.
Resetting bar['value'] to 0 causes it to return to position 0,
but naturally the bar would keep incrementing forever till it dies.
It works, but is a bit unnatural.
"""
if bar['value']==100:
bar.config(value=0) # could also set it as bar['value']=0
if __name__=='__main__':
mainProgram()
I've added if __name__=='__main__': because I feel it defines the scope a bit better.
As a side note I've found that running threads with while 1: will crank my CPU at about 20-30% usage for that one thread in particular. It's easily solvable by importing time and using time.sleep(0.05) thereafter significantly lowering the CPU usage.
Tested on Win8.1, Python 3.5.0.

Urwid ProgessBar does not update properly

I'm playing around with the urwid library and it's been pretty great so far.
But i can't get the Progressbar to work. I wrote a simple test program like this:
import os
import urwid
# a function that takes some times to complete
def dosomething(steps, bar):
bar.done = steps
for i in range(steps + 1):
bar.set_completion(i)
os.system('sleep 0.2')
# make a button to start
task_btn = urwid.Button(u'Task')
# progressbar object
pbar = urwid.ProgressBar('pg normal', 'pg complete')
# function called when the task button is clicked
def on_task_clicked(button):
dosomething(10, pbar)
# setup signal handler for the button
urwid.connect_signal(task_btn, 'click', on_task_clicked)
"""
create the interface and the mainloop.
filler objects are our friend to prevent unpacking errors :D
"""
loop = urwid.MainLoop(urwid.Pile([urwid.Filler(task_btn), urwid.Filler(pbar)]))
loop.run()
If i start it the progressbar is to 0% as it should be. Then i press the button, and a few seconds later the progressbar shows 100%. but i'm missing the steps between 0% and 100%. they just won't show up.
Also an additional call of the render function won't work.
I've also tried something like this:
def on_task_clicked(button):
pbar.set_completion(pbar.current+1)
And this works just fine. It just seems that the progressbar is not happy with being called in a loop. That seems strange?! Someone got any ideas in order to resolve this?
Thanks in advance :)
PS:
INFO:
urwid 1.2.0
tested on python 2.6.6, 2.7, 3.3 all the same
It's probably because the main loop's draw_screen method isn't being called (it's normally called automatically when the loop enters the idle state).
Add loop.draw_screen() inside your for-loop.

Categories

Resources