Progressbar and combinations in Python - python

I am using itertools.combinations module to find a large number of combinations. While my program finds all its combinations (a lot of them) it checks for sum of every combination to be some number and then program store that combination in list.
from itertools import *
from math import *
import Tkinter as tk
import ttk
x = int(raw_input('Enter number of combinations: '))
z = int(raw_input('Enter sum number: '))
def combinator():
comb = combinations(range(100), x)
for i in comb:
yield i
my_combinations = []
combination_s = combinator()
for i in combination_s:
print i
c = list(i)
if fsum(c)==z:
my_combinations.append(c)
print my_combinations
root = tk.Tk()
root.title('ttk.Progressbar')
pbar = ttk.Progressbar(root, length=300, mode='determinate', maximum = 100)
pbar.pack(padx=5, pady=5)
root.mainloop()
I want to have ttk.progressbar that shows progress every time program evaluates sum of combinations. How can I do that?

Here is an example that increases the progress bar for every combination. It just waits for a short time, but you can easily change it to do some calculations in the for loop in ProgBarApp.start instead of time.sleep
from Tkinter import *
from itertools import combinations
import ttk
import time
class ProgBarApp:
def __init__(self):
self.vals = range(1, 20)
self.combs = list(combinations(self.vals,3))
self.n = len(self.combs)
self.progressbar = ttk.Progressbar(root, maximum = self.n+1)
self.progressbar.pack()
def start(self):
for c in self.combs:
self.progressbar.step()
time.sleep(0.01)
root.update()
root.destroy()
root = Tk()
p = ProgBarApp()
root.after(0, p.start())
root.mainloop()

Related

is it possible to run a function on a timed loop in tkinter with the tkinter window already displayed?

I'm trying to make a tkinter window that displayes then routinely updates the visuals by running a function every few seconds. currently the solutions I have found only display the screen after the functions have run thousands of times without any delay dispite .after(ms,function) being used
import tkinter
from tkinter import *
top = tkinter.Tk()
top.geometry("500x500")
top.title("display screen test")
global reps
def functiontorepeat():
global reps
reps = reps + 1
labelexample.config(text = reps)
top.after(5000,functiontorepeat())
#why does this not have a delay when run
#and why does this only show the screen after the reps hits a recursion depth limmit
labelexample = Label(top,text = "original text")
labelexample.pack(side = TOP)
reps = 0
functiontorepeat()
top.mainloop()
Difference between calling and passing a function.
top.after(5000,functiontorepeat()) will call the function immediately
But you need to pass the function rather than call it.
top.after(5000,functiontorepeat) without brackets!
import tkinter
from tkinter import *
top = tkinter.Tk()
top.geometry("500x500")
top.title("display screen test")
global reps
def functiontorepeat():
global reps
reps = reps + 1
labelexample.config(text = reps)
top.after(5000,functiontorepeat)
labelexample = Label(top,text = "original text")
labelexample.pack(side = TOP)
reps = 0
functiontorepeat()
top.mainloop()

Python tkinter after method not working as expected

I'm trying to learn Tkinter module, but I can't undestand why the after method doesn't behave as expected. From what I know, it should wait ms milliseconds and then execute the function, but in my case the function gets executed many more time, not considering the time I write. Here's the code:
from tkinter import *
def doSomething():
x = int(l["text"])
l["text"] = str(x + 1)
root = Tk()
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
while True:
l.after(1000, doSomething)
root.update()
if int(l["text"]) >= 5:
break
root.mainloop()
After the first 2 seconds the label starts displaying humongous numbers
After the first 2 seconds the label starts displaying humongous numbers
Keep in mind, while True, is an infinite loop, you are making infinite calls to root.after() means alot of events are being scheduled to be called after 1 second. Better way to do this is to remove your while and move it all inside your function.
from tkinter import *
root = Tk()
def doSomething():
x = int(l["text"])
l["text"] = x + 1
if int(l["text"]) < 5: # Only repeat this function as long as this condition is met
l.after(1000, doSomething)
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
doSomething()
root.mainloop()
Though the best way to write the function would be to create a variable and increase the value of that variable inside the function and then show it out:
from tkinter import *
root = Tk()
count = 0 # Initial value
def doSomething():
global count # Also can avoid global by using parameters
count += 1 # Increase it by 1
l['text'] = count # Change text
if count < 5:
l.after(1000, doSomething)
root.geometry("300x300")
l = Label(root, text=count)
l.pack()
doSomething() # If you want a delay to call the function initially, then root.after(1000,doSomething)
root.mainloop()
This way you can reduce the complexity of your code too and make use of the variable effectively and avoid nasty type castings ;)
You are using infinite loop when using while True. Correct way is:
from tkinter import *
def doSomething():
x = int(l["text"])
l["text"] = str(x + 1)
if x < 5:
l.after(1000, doSomething)
root = Tk()
root.geometry("300x300")
l = Label(root, text="0")
l.pack()
doSomething()
root.mainloop()

Add text to tkinter with loop

I have a problem. I want to simplify and explain the problem.
I have this code:
from tkinter import *
from tkinter.scrolledtext import ScrolledText
def do():
global text
for i in range(0, 10):
time.sleep(0.5)
text.insert(INSERT, i)
root = Tk()
global text
text = ScrolledText(root)
text.grid()
button = Button(root, text = 'insert', command = do)
button.grid(row = 1, column = 0)
root.mainloop()
It does a simple job. it has to open the root window and add a number to it every half second, but it does it all at once and after the loop is done.
If your looking for how to use after(ms,func), this is how your function should look like:
lst = [_ for _ in range(10)] #list of numbers to index through
count = 0 #index number
def do():
global count
text.insert(INSERT,lst[count]) #insert the current element onto the textbox
count += 1 #increase the index number
rep = root.after(500, do) #repeat the function
if count >= len(lst): #if index number greater than length of items in list
root.after_cancel(rep) #stop repeating
and root.after_cancel(id) will cancel the repetition. Using global outside the functions holds no good.

Tkinter window not opened

My tkinter window not opened after i add while true function. How can I get this to work. Its works without while true, but i need it in my function.
from tkinter import *
from random import random
import sys
import random
maxcount = int (input("How many times "))
i = 1
cats = Tk()
cats.wm_title("maxcount test")
cats.geometry("500x500")
def black():
while True:
i+1
if i == 5:
break
Button(cats, text="Start", command=black()).grid(row=1, column=0)
Label(cats, text="How many times:").grid(row=0, column=0)
cats.mainloop()
You had two errors:
- i + 1 probably meant i += 1, then i musty be declared global so it can be modicied in the scope of the function.
- the Button command was black(), which is a call to the function black. What is needed is a reference to the function black (without the ())
One thing to note: as remarked by #Sierra_Mountain_Tech, as it is, the user must first input an integer for the
tkinter app to start.
from tkinter import *
from random import random
import sys
import random
maxcount = int (input("How many times "))
i = 1
cats = Tk()
cats.wm_title("maxcount test")
cats.geometry("500x500")
def black():
global i
while True:
i += 1
if i >= 5: # <-- changed from i == 5 at #Sierra_Mountain_Tech suggestion
break
Button(cats, text="Start", command=black).grid(row=1, column=0)
Label(cats, text="How many times:").grid(row=0, column=0)
cats.mainloop()

multiple processes to update to the correct grid location

I am trying to create three processes that will each eventually pull from a text file and do more complex calculations, but at the moment I am just experimenting with tkinter and multiprocessing. I want each of the three labels(lbl1,lbl2,lbl3) to add 1,2,or 3 to their label and return that value. I am new to pipeing and events and dont understand the way to return the values to the synchronize the values so that they return to the correct places, so the output is random in accordance to the position in the grid. How can I make it so that anything I return only returns to the correct position in the grid which I have already specified?
import matplotlib.pyplot as plt
import socket, time, datetime, sys, struct
from datetime import datetime
import numpy as np
import shutil
import os
from random import randint
import Tkinter as tk
from multiprocessing import *
#from Tkinter import *
def count1(pipe,stop):
x = 0
while not stop.is_set():
x+=1
pipe.send(x)
time.sleep(1)
def count2(pipe,stop):
y = 0
while not stop.is_set():
y+=2
pipe.send(y)
time.sleep(1)
def count3(pipe,stop):
z = 0
while not stop.is_set():
z+=3
pipe.send(z)
time.sleep(1)
class UpdatingGUI(tk.Frame):
def __init__(self,parent):
tk.Frame.__init__(self,parent)
self.parent = parent
self.parent_pipe, self.child_pipe = Pipe()
self.stop_event = Event()
self.num1=tk.Label(self, text="Number 1")
self.num1.grid(row=0, column=0)
self.num2=tk.Label(self, text="Number 2")
self.num2.grid(row=0, column=1)
self.num3=tk.Label(self, text="Number 3")
self.num3.grid(row=0, column=2)
# label to show count value
self.updating_int1 = tk.IntVar()
self.updating_int1.set(0)
self.updating_lbl1 = tk.Label(self,textvariable=self.updating_int1)
self.updating_lbl1.grid(row=1, column=0)
self.updating_int2 = tk.IntVar()
self.updating_int2.set(0)
self.updating_lbl2 = tk.Label(self,textvariable=self.updating_int2)
self.updating_lbl2.grid(row=1, column=1)
self.updating_int3 = tk.IntVar()
self.updating_int3.set(0)
self.updating_lbl3 = tk.Label(self,textvariable=self.updating_int3)
self.updating_lbl3.grid(row=1, column=2)
# launch count as a process
self.counter1 = Process(target=count1,args=(self.child_pipe,self.stop_event))
self.counter1.start()
self.update()
self.counter2 = Process(target=count2,args=(self.child_pipe,self.stop_event))
self.counter2.start()
self.update()
self.counter3 = Process(target=count3,args=(self.child_pipe,self.stop_event))
self.counter3.start()
self.update()
def update(self):
# While the pipe has data, read and update the StringVar
while self.parent_pipe.poll():
self.updating_int1.set(self.parent_pipe.recv())
self.updating_int2.set(self.parent_pipe.recv())
self.updating_int3.set(self.parent_pipe.recv())
self.parent.after(1000,self.update)
def main():
root = tk.Tk()
root.geometry("400x200")
gui = UpdatingGUI(root)
gui.pack()
root.mainloop()
if __name__ == "__main__":
main()
Question: ... anything I return only returns to the correct position
Generalize your def count (..., to do so add a position Parameter.
For instance:
def count(position, pipe, stop):
x = 0
while not stop.is_set():
x += 1
pipe.send((position, x))
time.sleep(1)
def update(self):
# While the pipe has data, read and update the StringVar
while self.parent_pipe.poll():
position, data = self.parent_pipe.recv()
if position == 1:
self.updating_int1.set(data)
elif position == 2:
# and so on

Categories