schedule, calendar, tinter and Threading - multithreading

I want to create a schedule that can update the calendar daily.
I'm using the code below but it seems I'm using the Thread or the Schedule in the wrong way.
If I use Calendar only, the date will never change.
from tkinter import *
import threading
import schedule
import calendar
from tkcalendar import *
root = Tk()
box = Frame(root, width=500, height=550,highlightbackground="red", highlightthickness=5)
box.grid(row=0, column=1)
root.geometry('1000x500')
crm = Calendar (root, firstweekday='sunday',selectmode='none',showweeknumbers=False,
font=('Helvetica',15, 'bold'),
fill='both',expand=True)
calendar.setfirstweekday(calendar.SUNDAY)
crm.grid(ipady=110,ipadx=250,row=0,column=0)
def job1():
threading.Thread(target=job2).start()
def job2():
print('its time')# HERE I WANT to the Schedule UPDATE the Calendar
schedule.every().day.at("00:00").do(job1)
schedule.run_all()
root.mainloop()

I found a way to use the schedule inside a loop so I can manage to update the calendar after midnight.
i used (schedule.run_pending() ) inside the loop. no need for threading.

Related

Is there a way of accessing the methods variables without calling the method?

I want to make a simple GUI that will allow user to pick an excel file to load the data from that will later be used for math calculations. Both modules work correctly when separate. But when I try to use my GUI as an import into my main file I am unable to access the needed var without calling the class method which in turn iterates it. It is troublesome because it is supposed to use this function only after the button press.
Is there something fundamentally wrong that I am doing?
GUI script
import tkinter as tk
import tkinter.filedialog as tkf
class TestClass():
def __init__(self, master):
frame = tk.Frame(master)
frame.pack()
self.dialogButton = tk.Button(frame, text="choose", command=self.chooseFile)
self.dialogButton.pack(side=tk.BOTTOM)
def chooseFile(self):
global filename
filename = tkf.askopenfilename()
print(filename)
Import script
import tkinterTest as tt
import tkinter as tk
root = tk.Tk()
classObject = tt.TestClass(root)
var = classObject.chooseFile()
print(var)
root.mainloop()
I want to access the path string only with the GUI so that it gives me the string only after I press the button to select the file not right after the program starts.

How to make a live date display using Python and tkinter

I'm trying to make an info center and I need to add a live date display, so every day it adds another day to it, if a month passes it would add a month to it. How would I do it?
I've googled and still have no idea, I know how to display it but no clue how to make it automatically update. would it be possible to do it like this below?
def tick():
time_string = time.strftime("%H:%M:%S")
clock.config(text=time_string)
clock.after(200, tick)
root = Tk()
clock = Label(root, font=("none", 50, "bold"), bg="#000000", fg="#910000", bd=5, relief="ridge")
clock.grid(row=0, column=0)
tick()
root.mainloop()
Your logic is fine. If you want to display months and days, you can use datetime module instead:
from datetime import datetime
def tick():
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
clock.config(text=now)
clock.after(200, tick)

How to create a progressbar capturing the progress of a subprocess in tkinter with threading

I am currently programming a GUI with tkinter in Python 3.6 for another Program, which is called through subprocess. I would like to represent the progress of the Program called, with a Progressbar, popping up in another window as soon as I hit the 'Run Program' Button. The value of the progressbar is set by arguments passed from the subprocess script, where I calculate the percentage of progress in a function. What I need:
1. How do I properly use the Threading-Module for spawning the subprocess?
2. How do I import a function (and therefore its arguments) of a script, that runs with command line parameters?
I was looking for a answer in other posts the whole day, but couldn't really connect them to my problem.
I tried to spawn the subprocess by simply calling its function with threading.Thread(target=self.runProgram()).start()
Apparently the GUI-program still waits until the subprocess/Thread is finished and then continues with creating the progressbar, but I expected it to happen at the same time. I then tried to import the percentage value of the subprocess-Program, which didn't work due to missing parameters. Also I don't think that this would really work the way I want it to, because I want the arguments passed during the runtime, when the subprocess is called. It's very hard to properly explain what I am looking for, so here is some code:
GUI-Program:
import tkinter as tk
from tkinter import ttk
from tkinter import *
from tkinter.filedialog import askdirectory,askopenfilename
import os,subprocess
import threading
class eodApplication(tk.Tk):
def __init__(self):
#different entryboxes are created, not necessary for understanding
self.runButton=''
self.progress=''
self.window = tk.Tk()
self.window.geometry("500x350")
self.window.configure(background="white")
self.window.title("End of Day Application")
self.create_widgets()
def create_widgets(self):
#creating entryboxes initiated in __init__-method, containing paths one can browse for and a submit/'Run Program'-Button
self.submit()
def submit(self):
#Button calls function when pressed
self.runButton=ttk.Button(self.window,text='Run Program',command=lambda:self.bar_init())
self.runButton.grid(row=7, columnspan=2)
def bar_init(self):
barWindow = tk.Tk()
barWindow.geometry("250x150")
barWindow.configure(background="white")
barWindow.title("Progress")
self.progress=ttk.Progressbar(barWindow, orient="horizontal", length=200, mode="determinate",value=0)
self.progress.grid(row=0, column=0, sticky=tk.W)
threading.Thread(target=self.runProgram()).start()
from PythonProgrammeDWH import get_percentage
self.progress["value"] = percentage
def runProgram(self):
devnull = open(os.devnull, 'w')
subprocess.call(f"{self.entryboxPyExe.get()} {self.entryboxPyCode.get()} {self.entrybox64.get()} {self.entrybox66.get()} {self.entryboxXsd.get()} {self.entryboxOutput.get()} {self.entryboxXmlExe.get()}",cwd=os.getcwd(),stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,shell=True)
eodApplication=eodApplication()
eodApplication.window.mainloop()
PythonProgrammeDWH (subprocess):
def main(sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4]):
~ a lot of stuff going on ~
sumFiles=len(os.listdir(path))
checkedFiles=0
for file in os.listdir(path):
checkedFiles+=1
get_percentage(sumFiles, checkedFiles)
def get_percentage(sumFiles, checkedFiles):
percentage= round((checkedFiles/sumFiles)*100)
return percentage
#percentage is the argument I want to pass to the other script for updating the progressbar

How can we restrict future date selection from tkCalender Date Entry picker in Python?

I am creating a graphic user application in Python using tkinter. For date picker I am using Date Entry from tkCalendar for this purpose. The requirement is to restrict user from selecting future dates. How can I achieve that in this case?
Python version 3.7
tkCalendar version 1.3.1
For tkcalendar >= 1.5.0 it is now possible to restrict the range of available dates with the mindate and maxdate options. So the following code prevent the user from selecting future dates:
from tkcalendar import DateEntry
from datetime import date
import tkinter as tk
today = date.today()
root = tk.Tk()
d = DateEntry(root, maxdate=today)
d.pack()
root.mainloop()
You can use the set_date method from DateEntry combined with root.after() to control the user input.
import tkinter as tk
from tkcalendar import DateEntry
from datetime import datetime
from tkinter import messagebox
root = tk.Tk()
time_now = datetime.now()
calendar = DateEntry(root, width=12, background='darkblue',foreground='white', borderwidth=2)
calendar.pack()
def date_check():
calendar_date = datetime.strptime(calendar.get(),"%m/%d/%y")
if calendar_date > time_now:
messagebox.showerror("Error", "Selected date must not exceed current date")
calendar.set_date(time_now)
root.after(100,date_check)
root.after(100,date_check)
root.mainloop()

How to create GUI objects one by one with Tkinter

I like to create an object per second and make the show up one by one. However, the code below wait for 3 seconds and show them all at the same time.
from tkinter import *
import time
def create():
for i in range(3):
r4=Radiobutton(root, text="Option 1"+str(i), value=1)
r4.pack( anchor = W )
time.sleep(1)
root = Tk()
create()
root.mainloop()
Your code, as is, creates a one object per second as you desired it, but this objects need to be shown, and they're shown when code flow reaches the mainloop. Hence, for observer, it looks like there're no objects at all after one second.
Of course, you can use sleep and update, but beware - sleeping leads to unresponsive window, so it's OK option (to be honest - not OK at all), if your application isn't drawn and you're outside of mainloop, but if it's not - prepare for a "frozen" window, because GUI can redraw himself only in mainloop (an event loop, you can reach it with update as well) and sleep blocks this behaviour.
But there's a good alternative, the after method, take a look on it!
And there's a snippet, so you can see the difference:
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
def create_with_sleep():
for _ in range(3):
tk.Radiobutton(frame_for_sleep, text="Sleep Option").pack(anchor='w')
time.sleep(int(time_entry.get()))
root.update()
def create_with_after(times=3):
if times != 0:
tk.Radiobutton(frame_for_after, text="After Option").pack(anchor='w')
times -= 1
root.after(int(time_entry.get()) * 1000, lambda: create_with_after(times))
root = tk.Tk()
test_yard_frame = tk.Frame(root)
frame_for_sleep = tk.Frame(test_yard_frame)
frame_for_after = tk.Frame(test_yard_frame)
test_yard_frame.pack()
frame_for_sleep.pack(side='left')
frame_for_after.pack(side='left')
button_frame = tk.Frame(root)
button_for_sleep = tk.Button(button_frame, text='Create 3 radiobuttons with sleep+update', command=create_with_sleep)
button_for_after = tk.Button(button_frame, text='Create 3 radiobuttons with after', command=create_with_after)
button_frame.pack()
button_for_sleep.pack(side='left')
button_for_after.pack(side='left')
time_label = tk.Label(root, text='Time delay in seconds:')
time_label.pack(fill='x')
time_entry = tk.Entry(root)
time_entry.insert(0, 1)
time_entry.pack(fill='x')
root.mainloop()
With 1 seconds delay there's no much difference, but you can try to increase delay to understand why after option is preferable in general.
You can use update to call a refresh on your objects.
In use, you would have to add the line root.update() in your for loop.

Resources