Calling a function every n seconds in python - python-3.x

I'm trying to create a tk widget which auto-updates the score of a cricket match. this is my code. But it is not auto-updating.
please help me with this.
import requests
from bs4 import BeautifulSoup
from tkinter import *
from tkinter import ttk
import time, threading
def scrape_cric():
#this below link can be any link of an ongoing match.
page = 'http://www.cricbuzz.com/live-cricket-scores/18733/engu19-vs-bdeshu19-5th-place-playoff-semi-final-2-icc-under-19-world-cup-2018'
r = requests.get(page)
soup = BeautifulSoup(r.text, 'lxml')
score_1 = soup.find('div', {'class':'cb-min-bat-rw'})
score = soup.find('span', {'class':'cb-font-20 text-bold'})
return score.text
def display_Score():
root = Tk()
top_frame = Frame(root)
bottom_frame = Frame(root)
Label1 = Label(top_frame, text = scrape_cric())
Label1.pack()
top_frame.pack()
mainloop()
threading.Timer(10, display_Score()).start()
display_Score()
It displays the score once on executing and doesn't auto-update. Once i close the tk widget, it again appears with updated scores. I don't want to close it to. It should update without e closing it.

The cause of this problem is beacuse you create a new root Tk in each call to the function instead of changing the text alone
A fix around that would be:
root = Tk()
top_frame = Frame(root)
label = Label(top_frame)
top_frame.pack()
label.pack()
def update():
label['text']=scrape_cric()
threading.Timer(10, update).start() #####
update()
root.mainloop()
Another important note: make sure you set the target of the timer to the function object, instead of calling it inside the creation of your timer

Related

stop ttk.Entry() from reading keyboard

Environment: macOS Catalina, Python 3.7.4, Tcl/Tk 8.6.9, VSC 1.39.1
I have a situation where I am using a bar/qr code scanner to provide a string to a ttk.Entry() method, which then fires off a function.
The reader is seen by the OS as an HID keyboard, so the text from the QR code is received by the ttk.Entry() widget that I give focus to during code execution. I have bound the widget to the key because the scanner sends a cr/lf at the end of the text string, which works as needed.
However, I am running into an issue where if the qr code lingers over the scanner too long it will rescan the qr code and the widget receives the qr code text again, which then causes it to be processed again.
I have tried disabling the ttk.Entry() in the function, deleting the widget contents, and removing focus to no avail. The behavior I'm seeing is occurring even though the widget is disabled and does not have focus, it is still getting input and executing the function again if the scanner rescans the qr code while the function is executing.
In this first example, I simply tried to disable the widget, but that doesn't work. The widget still gets the later scans while in the function.
# test-ttk-entry1.py
import time
import tkinter as tk
from tkinter import StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.configure(state="disabled")
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
The second attempt was to disable the entry widget and upon making it active again delete the text in the field.
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.delete(0, END)
kbEntry.configure(state="disabled")
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbEntry.delete(0, END)
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
And finally, I was reading about taking focus from a widget and giving focus to the root window, so I added that in and it still prints multiple times to the console like there is a keyboard buffer being read by the ttk.Entry() widget. The weird thing is it seems like widgets don't normally respond to any calls to methods when they are disabled, but it appears the ttk.Entry() widget's properties/attributes (excuse me if my OOP terms are not correct) can be manipulated while disabled.
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.delete(0, END)
kbEntry.configure(state="disabled")
root.focus_set()
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbEntry.delete(0, END)
kbEntry.focus_set()
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
So how can I prevent the ttk.Entry() widget from accepting any input from the HID/keyboard device while my function is executing?
Since I am unable to find a way to temporarily disable the .Entry() widget programmatically to keep it from reading successive inputs, I have come up with this solution:
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
tempStr = "" # Global temporary string variable to trip repeated scans
def print_text(event):
global tempStr
textValue = kbEntry.get()
if tempStr == textValue:
kbEntry.delete(0, END)
print ("Duplicate scan")
return
tempStr = textValue
kbEntry.delete(0, END)
print(textValue)
time.sleep(3) # Simulate the time it takes for the function to complete
kbEntry = ttk.Entry(root, width=10)
kbEntry.bind("<Return>", print_text)
kbEntry.grid(row=0, column=0, padx=10, pady=10)
kbEntry.focus_set()
root.mainloop()

python tkinter update content of a label when a file is opened

I'm currently programming a GUI using tkinter and Python 3.
My problem here is i made a Label with which i want to display the path of a file i opened via the askopenfilename() method and this path is not "generated" when i start the program, obviously, so the Label is empty which makes sense but i don't know how to fix it.
I'm gonna put the needed code below (I'm going to cut unnecessary code for this question):
import tkinter as tk
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.fileopenname=tk.StringVar()
self.menubar = tk.Menu(self)
self.create_widgets()
def create_widgets(self):
self.inputpathdisplay = tk.Label(self,textvariable=self.fileopenname,bg="white",width=30)
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
def fileopening(self):
from tkinter.filedialog import askopenfilename
self.fileopenname = askopenfilename(filetypes = [("binary files","*.bin*"),("all files","*.*")])
root = tk.Tk()
app = Graphicaluserinterface(master=root)
root.config(menu=app.menubar)
app.mainloop()
I read about using update_idletasks(). If this is correct in my case how would i go about implementing it here?
Right now you are doing self.fileopenname = askopenfilename() and this will redefine self.fileopenname as a string instead of a StringVar(). To correct this you need to set the value of StringVar with set().
That said you should also define all your imports at the top of your code instead of in your function.
import tkinter as tk
from tkinter.filedialog import askopenfilename
class Graphicaluserinterface(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self.grid()
self.fileopenname=tk.StringVar()
self.menubar = tk.Menu(self)
self.inputpathdisplay = tk.Label(self, textvariable=self.fileopenname, bg="white")
self.inputpathdisplay.grid(row=1,column=8,columnspan=3,sticky = "W")
self.fileopening()
def fileopening(self):
self.fileopenname.set(askopenfilename(filetypes = [("binary files","*.bin*"),("all files","*.*")]))
root = tk.Tk()
app = Graphicaluserinterface(master=root)
root.config(menu=app.menubar)
app.mainloop()

Trying to make a program that you push a button, choose a file, and the program then prints a certain value from that file

I'm very new to coding and I tried a bunch of different things but none of them are working for me.
Here is my code. With this code everything is working correctly so far, but i'm unsure of how to implement the read function into my code. My main problem is that in everyone's read examples they use the exact filename, whereas I need to use raw input.
Edit: I was able to solve this on my own, by using open(filename, "r") it lets you pick which file to read. Instead of having "6543.txt" which would only open that specific file.
from tkinter import Tk
from tkinter import *
from tkinter.filedialog import askopenfilename
root = Tk()
root.title("Amazon Error Handler")
root.geometry("300x150")
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack( side = BOTTOM )
def getfile():
filename = askopenfilename()
print(filename)
getfile = open(filename,"r")
print(getfile.read(1))
print(getfile.read())
button = Button(frame, text="Choose File", fg="black", command=getfile)
button.pack( side = BOTTOM)
root.mainloop()
This is the code I used to solve my own problem. This program is just a button that reads a chosen file and prints it's contents.
from tkinter import Tk
from tkinter import *
from tkinter.filedialog import askopenfilename
root = Tk()
root.title("Amazon Error Handler")
root.geometry("300x150")
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack( side = BOTTOM )
def getfile():
filename = askopenfilename()
print(filename)
getfile = open(filename,"r")
print(getfile.read(1))
print(getfile.read())
button = Button(frame, text="Choose File", fg="black", command=getfile)
button.pack( side = BOTTOM)
root.mainloop()

TKinter auto updating label from urllib

I'm trying make auto updating label from url.
I want to make something like pager. When file on server is changed, label should changes too. with button I can download it manually but I want to automate it. Where I'm making mistake?
from tkinter import *
import urllib.request
import time
root = Tk()
check = ""
#functions
def auto():
time.sleep(5) #becouse I don't want kill server
page = "http://howan.pl/pychal/plik.txt"
g = urllib.request.urlopen(page)
data = g.read()
g.close()
return (str(data, encoding='utf-8'))
def click():
page = "http://howan.pl/pychal/plik.txt"
g = urllib.request.urlopen(page)
data = g.read()
g.close()
label.config(text=str(data, encoding='utf-8'))
#Widgets
label = Label(root, text="zer0")
button = Button(root, text="hey", command= click)
if auto() == check:
check = auto
label.config(text=check)
print(auto())
label.pack()
button.pack()
root.mainloop()
To automate it you need to make a function that does the work, and then use root.after() to call that function on a regular basis. Since you have all the work in "click" already, you could just add:
def auto_click():
click()
root.after(5000, auto_click) # call this function again in 5,000 ms (5 seconds)
auto_click() # start the autoclick loop.

How to run a python tkinter app without appearing in unity panel or alt-tab

I am working on a countdown timer for Ubuntu using Python and tkinter.
I have created most of the parts and now I want my app to be able run without appearing in Unity panel or Alt-Tab switching sequence. Is there any way to do this?
And also I'd like to whether it is possible to create a moveable window without the title bar. I tried root.overrideredirect(1).
But with it I am unable to move the window.
Here's the code for my program.
#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import TOP,LEFT
import time
import datetime
import sys
class Countdown(ttk.Frame):
def __init__(self,parent=None, endDate=None):
ttk.Frame.__init__(self,parent)
self.style = ttk.Style()
self.style.theme_use("clam")
self.pack()
endDate = endDate.split("/")
self.endTime = datetime.datetime(int(endDate[2]),int(endDate[1]),int(endDate[0]))
self.setWidgets()
self.initWidgets()
def setWidgets(self):
self.dLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.dLbl.pack(padx=10,pady=10,side=LEFT)
self.hLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.hLbl.pack(padx=10,pady=10,side=LEFT)
self.mLbl = ttk.Label(self,text="0",font="Ubuntu 14 bold")
self.mLbl.pack(padx=10,pady=10,side=LEFT)
def getTimeDelta(self):
self.curDate = datetime.datetime.now()
self.diff = self.endTime - self.curDate
self.tSec = self.diff.total_seconds()
self.days = self.diff.days
h = int(((self.tSec) - self.days*24*60*60)/3600)
self.hours = h if h>0 else 0
m = int(((self.tSec) - (self.hours*60*60+self.days*24*60*60))/60)
self.minutes = m if m>0 else 0
self.sec = int(self.tSec - self.minutes*60)
return [self.days,self.hours,self.minutes+1]
def initWidgets(self):
def set():
dhm = self.getTimeDelta()
self.dLbl["text"]=str(dhm[0])+" Days"
self.hLbl["text"]=str(dhm[1])+" Hours"
self.mLbl["text"]=str(dhm[2])+" Mins"
self.after(1000,set)
set()
root = tk.Tk()
root.title(sys.argv[1])
app = Countdown(root, sys.argv[2])
app.mainloop()
To move a window without borders you can take a look at this question for a simple example of how to implement what you want and just keep building on top of it.
For the hiding, you could use .iconify(), theoretically minimizing the app to the tray thus hiding it, and .deiconify(), for example:
root = tk.Tk()
root.iconify()
ps. If it don't work on Ubuntu/Unity you may have to use other GUI framework with support for this behavior on Ubuntu, like GTK.
import tkinter
root = tkinter.Tk()
root.withdraw()
root.mainloop()
Will hide the window.
Make your own titlebar, like so:
import sys
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk() #create the window
titlebar = tk.Label(root,height=2, bg='cyan', fg='navyblue', text=sys.argv[0]) #create the titlebar
resizable = ttk.Sizegrip(root) #make the window resizable
titlebar.pack(fill='both') # display the titlebar
root.overrideredirect(1) #make the window run without appearing in alt tab
#root.withdraw()
#root.deiconify()
root.geometry('200x200') #set the window size to 200x200
resizable.pack(fill='y',side='right')
def ontitlebarclicked(event):
global lastposition
lastposition=[event.x,event.y]
def ontitlebardragged(event):
global lastposition
windowposition=[int(i) for i in root.geometry().split('+')[1:]] # get the window position
diffposition=[event.x-lastposition[0],event.y-lastposition[1]]
widthheight=root.geometry().split('+')[0]
root.geometry(widthheight+'+'+str(windowposition[0]+diffposition[0])+'+'+str(windowposition[1]+diffposition[1]))
titlebar.bind('<Button-1>',ontitlebarclicked)
titlebar.bind('<Button1-Motion>',ontitlebardragged)
titlebar.focus_force()

Resources