I need to make a GUI with a button where the button will appear in a random interval of time (from 1 to 10 seconds). I know I need to use the random.randrange() command but I dont know how to.
This is my code so far:
#Importere værktøjer
from tkinter import*
import datetime
import time
import os
import datetime
import random
#Tiden
start = time.clock()
finish = time.clock()
elapsed_time = finish - start
t = datetime.datetime.now()
#Definitioner
def myClickMe1():
label1["text"]='{0:.2f}'.format(elapsed_time)
print('{0:.2f}'.format(elapsed_time))
return
#rod defineres
window=Tk()
#Vinduet
window.geometry("700x800")
window.title("Reaktionshastighehs test")
#Labels
label1=Label(window, text="Klik nu!")
#indstillinger til objekter
button1=Button(window, text="Klik her!", command=myClickMe1)
#Placering af objekter
button1.place(x=330, y=460)
label1.place(x=335,y=500)
print(t.second/1000)
I wany my button1 to appear at a random time from 1 to 10 seconds. Can anyone help me plsease?
Thanks
Kasper
Tkinter has an after method that you can run on your root window that will call a function after an amount of time (in milliseconds).
Random has a randint() method that can return an integer between two numbers.
So, call after and pass a randint between 0 and 10 seconds, then call the function to create the Button:
def placeButton():
Button(window, text='Click').pack()
window.after(random.randint(0,10000), placeButton)
Related
How to show text when certain time comes
Such as when the time to 0:30:0 will display the text
import time
def countdown(time_sec):
time_msec = time_sec*10
while time_msec:
mins, secs = divmod(time_msec, 600)
secs, msecs = divmod(secs, 10)
timeformat = "{:02d}:{:02d}.{:01d}".format(mins, secs, msecs)
print(timeformat, end='\r')
time.sleep(1/10)
time_msec -= 1
print("stop")
countdown(61)
I can show you an example I coded some time ago, which displays a message every time the clocl hits 30 seconds.
import datetime
import time
# set the target time to 30 seconds
target_seconds = 30
while True:
# get the current time in seconds
current_seconds = datetime.datetime.now().time().second
# check if the current time matches the target time
if current_seconds == target_seconds:
print("It's time!")
# wait for 1 second before checking the time again
time.sleep(1)
you should be able to adapt it for your needs. Basically you do an if cluase that checks if your target time has come.
We can eliminate that remote possibility of 'skipping' by making clock independent. A modified version of #fallouthase :
import datetime
import time
target_seconds = 30
def print_str(time):
if time==target_seconds:
print("Its time")
def time_call(time):
print(current_seconds)
while True:
current_seconds = datetime.datetime.now().time().second
time_call(current_seconds)
print_str(current_seconds)
time.sleep(1)
I have my process working with Tkinter, but when I run my code my program freeze I understandt It´s because of the main loop, I have been reading the documentation of Tkinter and reading some other questions but I can´t really understand how to implement the Progress Bar to my process, my code It´s really simple it just dowload some information and then save It like an excel but It takes some time to do the process, so how can I implement the progress bar here.
root=Tk()
root.title('Info Dowload')
root.iconbitmap('Logo.ico')
root['bg'] = '#E1FAF9'
#VariablesInicio
fecha1=Entry(root)
fecha2=Entry(root)
date1.insert(0, "ejm:2022-03-15")
date2.insert(0, "ejm:2022-03-15")
#Label
label1=Label(root,text="First Date(aaaa-mm-dd):",font=('Bahnschrift',11))
label2=Label(root,text="Second date(aaaa-mm-dd):",font=('Bahnschrift',11))
def Click():
boton1.config(state= "disable")
label3=Label(root,text="Working with: "+date1.get())
label4=Label(root,text="Working with: "+date2.get())
label3.grid(row=3,column=0)
label4.grid(row=4,column=0)
startFac=str(date1.get())+' 00:00:00'
endFac=str(date2.get())+' 23:59:59'
##First Query
startMF=str(date1.get())
endMF=str(date2.get())
startMF=startMF.replace('-','/')
endMF=endMF.replace('-','/')
df=query1(startMF, endMF)
df1=query2(startFac, endFac, df)
sales=pd.merge(left=df,right=df1,how='left',on=['code1','code2','code3'])
sales.to_excel('sales.xlsx',index=None)
#Button
import tkinter as tk
boton1=tk.Button(root,text='Ejecutar',bg='#20bebe',fg='white',height=1,width=6,command=Click)
#Print info
label1.grid(row=0,column=0)
label2.grid(row=1,column=0)
fecha1.grid(row=0,column=1)
fecha2.grid(row=1,column=1)
boton1.grid(row=2,column=0)
root.mainloop()
In order to add a progress bar, you can use the Progressbar class as follows:
progressbar = Progressbar(root, orient='horizontal',mode='indeterminate',length=<your preferred length>)
Additionally, you would also have to define when to start and stop displaying your progress bar. In order to do this, add the pb.start() and pb.stop() commands at the start and end of your click() function respectively.
[Suggested by #Matiss]
In order to solve the problem of the progress bar not moving, you can import threading module and use it as follows:
root=Tk()
root.title('Info Dowload')
root.iconbitmap('Logo.ico')
root['bg'] = '#E1FAF9'
#VariablesInicio
fecha1=Entry(root)
fecha2=Entry(root)
date1.insert(0, "ejm:2022-03-15")
date2.insert(0, "ejm:2022-03-15")
#Label
label1=Label(root,text="First Date(aaaa-mm-dd):",font =('Bahnschrift',11))
label2=Label(root,text="Second date(aaaa-mm-dd):",font =('Bahnschrift',11))
def Click():
boton1.config(state= "disable")
label3=Label(root,text="Working with: "+date1.get())
label4=Label(root,text="Working with: "+date2.get())
label3.grid(row=3,column=0)
label4.grid(row=4,column=0)
progressbar.start()
t1.start()
def download():
startFac=str(date1.get())+' 00:00:00'
endFac=str(date2.get())+' 23:59:59'
##First Query
startMF=str(date1.get())
endMF=str(date2.get())
startMF=startMF.replace('-','/')
endMF=endMF.replace('-','/')
df=query1(startMF, endMF)
df1=query2(startFac, endFac, df)
sales=pd.merge(left=df,right=df1,how='left',on=['code1','code2','code3'])
sales.to_excel('sales.xlsx',index=None)
progressbar.stop()
#Code for multithreading
t1 = threading.Thread(target=download)
#Code for progress bar
progressbar = Progressbar(root, orient='horizontal',mode='indeterminate',length=<your preferred length>)
progressbar.grid()
I have a button which inserts text into a 'scrolltext' box when it is clicked.
I want to delay parts of the text being inserted into the text box. As in, one line of text is insert, there a 3 second delay, the next line of text is inserted and so on...
The I attempted using 'time' to make this work. However, this just delays all the text being inserted by the combined value and then all the text is inserted at once. Is there a way to make it work how I wish? And is it possible to delay it, so that each letter is inserted one at a time?
This is a much simplified version of what I've tried:
import tkinter as tk
from tkinter import *
from tkinter import scrolledtext
import time
# This is the GUI
trialGUI = Tk()
trialGUI.geometry('710x320')
trialGUI.title("Test GUI")
#This is the text that should be inserted when the button is pressed
def insertText():
trialBox.insert(tk.INSERT, 'This line should be inserted first.\n')
time.sleep(1)
trialBox.insert(tk.INSERT, 'This line should be inserted after a 1 second delay.\n')
time.sleep(3)
trialBox.insert(tk.INSERT, 'This line should be inserted after a 3 second delay.\n')
time.sleep(3)
trialBox.insert(tk.INSERT, 'This line should be inserted after a 3 second delay.\n')
#This is the scrolling text box
trialBox = scrolledtext.ScrolledText(trialGUI, wrap = tk.WORD, width = 42, height = 10, font=(14))
trialBox.grid(row = 0, column = 0, columnspan = 4, pady = 3)
#This button runs the code to insert the text
trialButton = Button(trialGUI, text = "Run Code", command = insertText)
trialButton.grid(row = 1)
trialGUI.mainloop()
Here's a solution using the .after() method:
def insertText():
global previousDelay
previousDelay = 0
delayedInsert('This line should be inserted first.\n',0)
delayedInsert('This line should be inserted after a 1 second delay.\n',1)
delayedInsert('This line should be inserted after a 3 second delay.\n',3)
delayedInsert('This line should be inserted after a 3 second delay.\n',3)
def delayedInsert(text, delay):
global previousDelay
trialGUI.after((delay + previousDelay) * 1000, lambda: trialBox.insert(tk.INSERT,text))
previousDelay += delay
It uses a delayedInsert function which takes the text and delay in seconds and the global variable previousDelay to make the delays appear asynchronous (they are still happening at the same time but the delays are changed to make it appear like they are not). If the delays were not changed, each delay would start at the same time, not one after the other. The delayedInsert function waits for the delay specified plus the previous delay before inserting the text. This gives the same effect as time.sleep() but it works with Tkinter.
I have a function that generates a random reaction time and waits before printing out to the console.
Here is my code
import time
import random
def saySnap(player):
reactionTime = random.randint(120, 401) / 1000
time.sleep(reactionTime)
print("{} : Snap!".format(player))
saySnap("p1")
saySnap("p2")
This results in 'p1' always being first since time.sleep blocks the program. How can I make sure that either player can print first?
You can use threading:
import time
import random
import threading
def saySnap(player):
reactionTime = random.randint(120, 401) / 1000
time.sleep(reactionTime)
print(f"{player}: Snapped in {reactionTime}!")
p1_thread = threading.Thread(target=saySnap, args=("p1",))
p2_thread = threading.Thread(target=saySnap, args=("p2",))
p1_thread.start()
p2_thread.start()
Which gives results randomly on your reaction times you set above.
You can use the threading.Timer class from built in threading module which represents an action that should be run only after a certain amount of time has passed.
Use:
import threading
def printSnap(player): # action that will be performed after reactionTime has been elapsed
print("{} : Snap!".format(player))
def saySnap(player):
reactionTime = random.randint(120, 401) / 1000
# instantiate and start the timer.
threading.Timer(reactionTime, printSnap, args=(player,)).start()
Or, if you don't want to define another function printSnap, Use:
def saySnap(player):
reactionTime = random.randint(120, 401) / 1000
threading.Timer(
reactionTime, lambda p: print(f"{p} : Snap!"), args=(player,)).start()
Calling the function:
saySnap("p1")
saySnap("p2")
Am a new in GUI programming and I am trying to make a GUI for one of my python parser.
I know that :
Tkinter is single threaded. Screen updates happen on each trip through the event loop. Any time you have a long running command you are preventing the event loop from completing an iteration, thus preventing the processing of events, thus preventing redraws.
My program call a big function that takes about 5 minutes to be ran entirely. So I guess the only solution is tu use thread for the long running command.
BUT, my long running command in already threaded so I don't really know how to proceed.
--> As soon as I click on BUT1 in the GUI, the program freeze until the function is entirely done. I'd like to run this function in the backgroung, so the program will not freeze.
--> I'm not looking for a complete solution but if someone can put me on a good track, it will be wonderful !
Main.py -> The GUI
Module_1.py -> The function that we call by clicking on the button BUT1
Thank you in advance !
Here is Main.py --> the GUI
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import *
import sys
import tkMessageBox
import tkFileDialog
import Module_1
import csv
from time import strftime, gmtime
DATE = strftime("_%d_%b_%Y")
class App:
def __init__(self, master):
self.frame = Frame(master, borderwidth=5, relief=RIDGE)
self.frame.grid()
class IORedirector(object):
def __init__(self,TEXT_INFO):
self.TEXT_INFO = TEXT_INFO
class StdoutRedirector(IORedirector):
def write(self,str):
self.TEXT_INFO.config(text=self.TEXT_INFO.cget('text') + str)
self.TEXT_HEADER = self.text_intro = Label(self.frame, bg="lightblue",text="THIS IS \n MY SUPER PROGRAM")
self.TEXT_HEADER.grid(row=0, column=0, columnspan=2, sticky=W+E+N+S)
self.MENU = Frame(self.frame, borderwidth=5, relief=RIDGE, height=12)
self.MENU.grid(row=1, column=0, sticky=N)
self.button = Button(self.MENU, text="QUIT", bg="red", command=self.frame.quit)
self.button.grid(row=4, column=0)
self.BUT1 = Button(self.MENU, text="BUT1", command=self.BUT1)
self.BUT1.grid(row=0, column=0,sticky=W+E)
self.TEXT_INFO = Label(self.frame, height=12, width=40, text="SOME TEXT", bg="grey",borderwidth=5, relief=RIDGE)
self.TEXT_INFO.grid(row=1, column=1, sticky = N+W)
sys.stdout = StdoutRedirector(self.TEXT_INFO)
def BUT1(self):
self.BUT1.config(text="RUNNING")
self.TEXT_INFO.config(text="BUT1 LAUNCHED")
Module_1.main("BUT1")
## HERE WE NEED TO RUN THE FUNCTION
## THE PROGRAMM FREEZE HERE UNTIL THE FUNCTION IS ENTIRELY RUN
self.TEXT_INFO.config(text="BUT1 FINISHED")
self.BUT1.config(text="DONE")
root = Tk()
app = App(root)
root.mainloop()
And here is Module_1.py --> contain the big function
#!/usr/bin/python
# -*- coding: utf-8 -*-
import Queue
import threading
import urllib2
import time
from bs4 import BeautifulSoup as soup
from urllib2 import urlopen
import re
import os
import random
import sys
import logging
import csv
from time import strftime, gmtime
import os
import random
import shutil
import sys
import re
import logging
from threading import RLock
from time import strftime, gmtime
import csv
import urllib
from urllib import urlretrieve
from grab.spider import Spider, Task
logging.basicConfig(level=logging.CRITICAL) # Loggin to DEBUG / INFO
log = logging.getLogger()
DATE = strftime("_%d_%b_%Y")
class SPIDER1(Spider):
initial_urls = ['URL_THAT_I_NEED_TO_PARSE']
def __init__(self):
super(SPIDER1, self).__init__(
thread_number=20,
network_try_limit=20,
task_try_limit=20
)
self.result = {}
def task_initial(self, grab, task):
for opt in grab.css_list("select[name='Template$TestCentreSearch1$SubRegionList'] option")[1:]:
grab.set_input('Template$TestCentreSearch1$SubRegionList', opt.attrib['value'])
grab.submit(extra_post={
'__EVENTTARGET': 'Template$TestCentreSearch1$SubRegionList'
}, make_request=False)
yield Task('parse', grab=grab, country=opt.text_content())
def task_parse(self, grab, task):
log.info('downloaded %s' % task.country)
city_gen = (x.text_content() for x in grab.css_list(".TestCentreSearchLabel+br+span"))
title_gen = (x.text_content() for x in grab.css_list(".TestCentreSearchTitle"))
id_gen = (x.attrib['href'][-36:] for x in grab.css_list(".TestCentreSearchLink"))
for x in zip(city_gen, title_gen, id_gen):
self.result[x[2]] = {
'country': task.country,
'city': x[0],
'name': x[1],
'id': x[2],
'price':'',
'currency':'',
'fee':''
}
yield Task('info', 'URL_URL=%s' % x[2], id=x[2])
def task_info(self, grab, task):
for label in grab.css_list(".TestCentreViewLabel"):
if label.text_content().strip()=="Test Fee:":
fees = label.getnext().text_content().strip()
self.result[task.id]['fee'] = fees
price = re.findall('\d[\d\., ]+\d',fees)
if price:
price = re.findall('\d[\d\., ]+\d',fees)[0]
self.result[task.id]['price'] = price.replace(' ','').replace(',','.')
currency = re.findall('[A-Z]{2,3}[$|€|£]?',fees)
if not currency:
currency = re.findall('[$|€|£]',fees)
if not currency:
currency = fees.replace(price,'').strip().replace(' ','')
if isinstance(currency,list):
currency = currency[0]
self.result[task.id]['currency'] = currency
#log.info(' %(price)s %(currency)s - %(fee)s ' % self.result[task.id])
break
def dump(self, path):
"""
Save result as csv into the path
"""
with open(path, 'w') as file:
file.write("ID;Country;State;City;Name;Price;Currency;Original Fee\n")
for test_center in sorted(self.result.values(), key=lambda x: "%(country)s%(city)s%(name)s" % x):
file.write(("%(id)s;%(country)s;;%(country)s;%(name)s;%(price)s;%(currency)s;%(fee)s\n" % test_center).encode('utf8'))
def main(choice):
parser, path, name = None, None, None
def run(name,parser,path):
log.info('Parsing %s...' % name)
parser.run()
parser.dump(path)
log.info('Parsing %s completed, data was dumped into %s' % (name, path))
log.info(parser.render_stats())
if choice == "NONE":
# DO NOTHING
# HERE I'D LIKE TO HAVE ANOTHER CALL TO ANOTHER THREADED FUNCTION
elif choice == "BUT1":
run('Function1',SPIDER1(),'C:\LOL\Output1'+DATE+'.csv')
So by clicking on BUT1, we run the main("BUT1") function contained in the Module_1.py file with argument BUT1 that launch -> run('Function1',SPIDER1(),'C:\LOL\Output1'+DATE+'.csv')
And then the program freeze until the parser has finished is work .. :)
The problem is simple: BUT1 won't return until the call to main returns. As long as main (and thus, BUT1) doesn't return, your GUI will be frozen.
For this to work you must put main in a separate thread. It's not sufficient that main spawns other threads if all it's doing is waiting for those threads.
If you call root.update() occasionally from the BUT1 function, that should prevent the GUI from freezing. You could also do that from a python thread with a fixed interval.
For example, updating every 0.1 seconds:
from threading import Thread
from time import sleep
self.updateGUIThread = Thread(target=self.updateGUI)
def updateGUI(self):
while self.updateNeeded
root.update()
sleep(0.1)
After the big function completes you can set self.updateNeeded to False.