I'm trying to make an alarm clock in Python. The problem I'm having lies in the displayTime function. It's supposed to count down the number of seconds until the alarm will go off.
I need the aTime variable to be passed into the displayTime function. However, if I make aTime a parameter of the displayTime function, then I can't use displayTime as a parameter for timelabel.after(timelabel.after(1000, displayTime(aTime))), as it will make it an instance of displayTime rather than a parameter.
Since displayTime is nested within the alarm function, why doesn't it inherit aTime from alarm()?
Also how else can I get aTime into displayTime? Is there any other way besides using a parameter?
Here is the code:
from Tkinter import *
import time
def alarm() :
cHours = float(nHours.get())
cHours = cHours * 3600
cMinutes = float(nMinutes.get())
cMinutes = cMinutes * 60
aTime = cHours + cMinutes
print aTime
def displayTime():
timelabel = Label(alarmGUI, text = "%d seconds until it's time to wake up" % aTime)
timelabel.grid(row=9, column=0)
aTime -=1
timelabel.after(1000, displayTime)
displayTime()
alarmGUI = Tk()
alarmGUI.geometry('500x400')
alarmGUI.title("Alarm Clock")
nHours = IntVar()
nMinutes = IntVar()
label1 = Label(alarmGUI, text = "Enter the number of hours and number of minutes that you want to sleep").grid(row=1, column=1)
label2 = Label(alarmGUI, text = "Hours").grid(row = 3, column = 0)
label3 = Label(alarmGUI, text = "Minutes").grid(row = 5, column = 0)
hours = Entry(alarmGUI, textvariable = nHours).grid(row = 3, column = 1)
minutes = Entry(alarmGUI, textvariable = nMinutes).grid(row = 5, column = 1)
button1 = Button(alarmGUI, text = "Start", command = alarm).grid(row = 7, column = 0)
alarmGUI.mainloop()
Related
I am trying to make a simple gui where you can press a button to start a a timer, and see it count down, similar to https://web.5217.app/, But I cannot get the timer to display in the gui, any help would be appreciated.
Also this is my first question so I may have done something wrong.
from tkinter import Tk, Button, DISABLED, Label, ACTIVE
import time
#main window configuration
root = Tk()
root.title ("PyDoro")
root.geometry ("400x400")
root.configure(bg = "#383838")
#colours for the text
Colour1 = "#c4c4c4"
Colour2 = "#292828"
def Date(): #Defines the date for displaying under the clock
day = time.strftime("%d")
month = time.strftime("%b") # %B can be used for full month
year = time.strftime("%Y")
Calendar.config (text= day + " " + month + " " + year)
def clock(): # for creating the clock
tizo = time.strftime("%X") #Find the time for your locale
Time.config (text = tizo)
Time.after (1000, clock)
Date() #calling the Date because it makes sense to do it here
def Stop():
print ("nothing")
def Start():
time_left = (50)
Stop.config (state = ACTIVE)
timer = Label (root, text = time_left)
timer.pack()
for i in range (50):
timer.config (text = time_left)
Start.after (1000) # this waits for 1 minute (60000 miliseconds)
#print (i) # This is just for debugging
time_left = time_left - 1
print (time_left)
Start = Button (root, text = "Start!", fg = Colour1, bg = Colour2, padx = 40, command = Start)
Stop = Button (root, text = "stop", fg = Colour1, bg = Colour2, state = DISABLED)
Time = Label (root, text="", font = ("Helvetica", 50), fg = Colour1, bg = "#383838")
Time.pack (pady = 5)
Calendar = Label (root, font = ("Helvetica", 12), fg = Colour1, bg = "#383838")
Calendar.pack (pady = 5)
Start.pack (pady = 10)
Stop.pack (pady = 10)
clock()
root.mainloop() #Runs the program
Replace your Start() function with the following code:
def Start():
time_left = (50)
Stop.config (state = ACTIVE)
timer = Label (root, text = time_left)
timer.pack()
def update(time_left):
timer['text'] = time_left
if time_left > 0:
root.after(1000, update, time_left-1)
update(time_left)
After you create your label, the program calls a function called update, which sets the text of the timer label to time_left. It will then call root.after if time_left is greater than 0, and it passes time_left -1 back into the update function. This will make the timer countdown until it reaches 0.
The reason the timer Label isn't being shown is because the display is never given a chance to update. To fix that, try using the Start() function shown below which calls the universal widget method update_idletasks() to update it after it's been changed.
def Start():
time_left = 50
Stop.config(state=ACTIVE)
timer = Label(root, text=time_left)
timer.pack()
for i in range(50):
timer.config(text=time_left)
time_left -= 1
root.update_idletasks() # Update display.
root.after(1000) # Pause for 1000 milliseconds (1 second).
I have a 2 popups triggered by the same button : One have a progress bar, a label and a button. The other only have 2 labels and a button. If I comment the update function of the progress bar : neither of the popup is displayed. If I try to only display the second (without progress bar) it doesn't display. I can only display both at the same time and I want only to display the second one (without progress bar)
Here is the code of the first popup :
def sim_process_bar(self):
self.popup_process = Tk()
self.popup_process.wm_title("Simulation process...")
self.progressBar = ttk.Progressbar(self.popup_process, orient = 'horizontal', length = 286, mode = 'determinate')
self.progressBar['maximum'] = 100
self.stopBtn = Button(self.popup_process, text="Stop Simulation", command = self.popup_process.destroy)
self.progressBar.grid(column = 1, row = 1, pady = 10)
self.stopBtn.grid(column = 1, row = 2)
self.labelPercentage = Label(self.popup_process, text="Percentage complete : 0% ")
self.labelPercentage.grid(column = 1, row = 3, pady = 10)
def update_value_process_bar(self, value):
self.progressBar['value'] = value
self.progressBar.update()
The code of the second popup :
def process_feedback(self):
self.popupFeedback = Tk()
self.popupFeedback.wm_title("Simulation process...")
self.labelTimestep = Label(self.popupFeedback, text="Current timestep : ")
self.labelTimestep.grid(column = 0 , row = 1, pady = 10)
self.labelPercentage2 = Label(self.popupFeedback, text="Percentage complete : ")
self.labelPercentage2.grid(column = 0, row = 2, pady = 10)
self.Btnstop = Button(self.popupFeedback, text="Stop Simulation", command = self.popupFeedback.destroy)
self.Btnstop.grid(column = 0, row = 3)
I call the function at the just before the beggining of a loop and then update values inside this same loop :
the update :
if(round(k/self.total_timestep_of_simulation*100,1).is_integer()):
self.update_value_process_bar(k/self.total_timestep_of_simulation*100)
self.labelPercentage['text'] = "Percentage complete : " + str(round(k/self.total_timestep_of_simulation*100,1)) + "%"
#UPDATE POPUP FEEDBACK
self.labelTimestep['text'] = "Current timestep : " + str(data_update.strftime("%b %d %Y %H:%M:%S"))
self.labelPercentage2['text'] = "Percentage complete : " + str(round(k/self.total_timestep_of_simulation*100,1)) + "%"
so if I comment the "self.update_value"... function, nothing shows up on screen and if I only try to display the second one nothing shows up neither. I'm sure it's a dumb problem, but I'm struggling with this...
Your code is ok, but try to remove the line self.stopBtn = Button(self... or replace it by
self.stopButton = Button(self.popup_process,
text="Stop Simulation",
command = self.destroy_popup)
and add
def destroy_popup(self):
self.popup_process.destroy()
And same for the other popup:
self.Btnstop = Button(self.popupFeedback,
text="Stop Simulation",
command = self.destroy_popup)
...
def destroy_popup(self):
self.popupFeedback.destroy()
Sometimes the button "makes the connection" to the control to which it is attached. In this example, self.popup_process.destroy is a loop contained in Tkinter module. So the button executes that command. Putting it in a def avoids this.
That is only valid for certain versions. Maybe the one you're using is one of them. Otherwise I don't know.
I am using tkinter GUI. Created GUI, Now at one of my GUI ask Input value and I need to display that Input Value in another function and print that value.
Code is as below:
def EventOnBtnIO():
#some commutation
ForceNumericItem() #Called the function to open the new GUI
request = 'FF'+Value
print request
return
This is my GUI which consists of entry box and buttons
def ForceNumericItem():
global Subtop
Subtop = Toplevel(top)
Subtop.geometry("350x110+500+200")
Subtop.title("Force Numeric Items")
Subtop.grab_set()
frame = Frame(Subtop,width=15, height=200,bd = 1)
frame.pack(fill = 'both',padx=3, pady=3)
# frame.config(relief=RIDGE)
global entry2
global entrytext2
entrytext2 = IntVar()
entry2 = Entry(frame,textvariable=entrytext2, width = 45)
entry2.pack(padx = 5, pady = 5)
entry2.focus_set()
entry2.selection_range(0, END)
topButtonShow = Button(frame, text = 'OK',command = ForceValue,width = 10)
topButtonBack = Button(frame, text = 'Cancel',command = okclose,width = 10)
topButtonShow.pack(side = LEFT,padx=45,pady=5)
topButtonBack.pack(side = RIGHT,padx=45,pady=5)
return
After OK click, it should take the Value and display in my EventOnBtnIO function
def ForceValue():
global Value
Value = int(entrytext2.get())
print Value
Subtop.destroy()
top.deiconify()
return
I think it is related to local or global varibale, but not able to fix it. Getting value now
FF
Expected value
FF + Value
The function in which you create your popup window returns before the user has input a number in it. To fix this, you could use the .wait_window() method:
def EventOnBtnIO():
ForceNumericItem()
top.wait_window(Subtop)
request = 'FF'+str(Value)
print request
class AppetiserClass():
root = Tk()
root.title("Appetiser Page")
root.geometry("1920x1080")
meal1 = 0
def plus1():
global meal1
meal1 = meal1 + 1
DisplayButton["text"]=str(meal1)
return
def neg1():
global meal1
meal1 = meal1 + 1
DisplayButton["text"]=str(meal1)
return
app = Frame(root)
app.grid()
Label(app, text = "", width = 75, height = 20).grid(row = 1, column = 0, sticky = N)
DisplayButton = Button(app, text = meal1)
DisplayButton.grid(column = 1, row = 2, sticky = W)
DisplayButton.config(height = 10, width = 10 )
Plus1Button = Button(app, text = "+1", command=plus1, bg="green")
Plus1Button.grid(column = 2, row = 2, sticky = W)
Plus1Button.config(height = 10, width = 10 )
Neg1Button = Button(app, text = "-1", command=neg1, bg="green")
Neg1Button.grid(column = 3, row = 2, sticky = W)
Neg1Button.config(height = 10, width = 10 )
root.mainloop()
The problem I am having is that I have set a value to my global variable (meal1, being 0) but when I press the +1, or -1 button, a value is not being displayed on the "DislpayButton" and I am receiving this message:
"NameError: global name 'DisplayButton' is not defined "
"DisplayButton", is a button i have placed, to display a value onto. Nothing more, but I am receiving this error message.
If i remove the classes, and just run this code, with the single window, The code works fine.
Any help would be much appreciated!
If your indentation is correct, the problem isn't that DisplayButton and meal1 are global, it's that they're class-level and you're not accessing it that way, which means you should use self keyword to access it. (It doesn't have to be "self" - the first argument of any function in a class always defines the variable through which you can access other members in the same class - but it's Python style to use "self.") Add self as an argument to all your functions in that class, like so:
def neg1(self):
And then access meal1 and DisplayButton through self:
self.meal1 += 1
and:
self.DisplayButton["text"] = str(meal1)
I've re-written your class so that all the important stuff within the class can be accessed by everything else using self:
from tkinter import *
class AppetiserClass:
meal1 = 0
root = Tk()
app = Frame(self.root)
def __init__(self):
self.root.title("Appetiser Page")
self.root.geometry("1920x1080")
self.app.grid()
Label(self.app, text = "", width = 75, height = 20).grid(row = 1, column = 0, sticky = N)
self.DisplayButton = Button(self.app, text = self.meal1)
self.DisplayButton.grid(column = 1, row = 2, sticky = W)
self.DisplayButton.config(height = 10, width = 10 )
self.Plus1Button = Button(self.app, text = "+1", command=self.plus1, bg="green")
self.Plus1Button.grid(column = 2, row = 2, sticky = W)
self.Plus1Button.config(height = 10, width = 10 )
self.Neg1Button = Button(self.app, text = "-1", command=self.neg1, bg="green")
self.Neg1Button.grid(column = 3, row = 2, sticky = W)
self.Neg1Button.config(height = 10, width = 10 )
self.root.mainloop()
def plus1(self):
self.meal1 += 1
self.DisplayButton["text"]=str(self.meal1)
def neg1(self):
self.meal1 -= 1
self.DisplayButton["text"]=str(self.meal1)
if __name__ == "__main__":
AppetiserClass()
I changed a decent amount. First off, you had a lot of code written outside any particular method, which is something I prefer to keep inside the class methods except for class variable definitions (meal1 = 0 and etc.). It's fairly arbitrary - anything defined within a method as self.whatever has the same accessibility as stuff defined at the class scope. I've also made it so that you can keep reference to your buttons with self.ButtonName. Lastly, I've made it so that the window is instantiated only if you're running the file and not importing your code into a different file.
I have a problem using lambda: ... in my program. As I don't want my TkInter GUI to execute the functions automatically, I am using lambda. Problem is though that for Button3 it makes my program crash and I have no idea why. Without lambda it works absolutely fine. Here is my code:
import ogr, osr, sys, os
import psycopg2
import ppygis
from datetime import datetime, date
import time
import re
from Tkinter import *
import tkFileDialog
from tkFileDialog import askopenfilename # Open dialog box
from tkMessageBox import showerror
class trip_calculator:
def __init__(self):
global root
root = Tk()
def open_file_dialog():
returned_values = {}
returned_values['filename'] = askopenfilename()
Label(root, text= returned_values.get('filename')[52:] + ' selected').grid(row=2)
filepath = returned_values.get('filename')
#OPEN GPX DRIVER
driver = ogr.GetDriverByName('GPX')
datasource = driver.Open(filepath)
if datasource is None:
print 'not open'
else:
print 'open'
#GEOMETRY
datasource_layer = datasource.GetLayer(2)
#GRAB TIMESTAMPS, ELEVATION, CADENCE ETC.
datasource_layer2 = datasource.GetLayer(4)
#GRAB GEOMETRY INFORMATION AND TRANSFORM TO UTM
datasource_feature = datasource_layer.GetNextFeature()
geoSR = osr.SpatialReference()
geoSR.ImportFromEPSG(4326)
utmSR = osr.SpatialReference()
utmSR.ImportFromEPSG(32633)
coordTrans = osr.CoordinateTransformation(geoSR, utmSR)
geom = datasource_feature.GetGeometryRef()
geom1 = geom.Simplify(0)
geom.Transform(coordTrans)
geom1.Transform(coordTrans)
Label(root, text= 'geometries transformed successfully').grid(row=2, column=5)
#
# This is where the crash of Python occurs,
# `lambda: calculation(...)` won't start.
# It crashes at `features = iter(datasource_layer2)`
#
self.button3 = Button(root, text='calculate attributes', command=lambda:calculation(self,geom1,datasource_layer2)).grid(row=10, column=10, pady=10, padx=10)
def quit_me():
root.quit()
def calculation(self, geom1, datasource_layer2):
#NET AND GROSS TIME CALCULATION
timestamps_net = []
timestamps_net_helper = []
timestamps_elapsed = []
elevation_helper = []
print datasource_layer2
features = iter(datasource_layer2)
next(features)
for feature in features:
if len(timestamps_net_helper) == 2:
timestamps_net_helper = timestamps_net_helper[-1:]
timestamp = feature.GetField(4)
elevation = feature.GetField(3)
elevation_helper.append(elevation)
timestamp_stripped = timestamp[:-3]
day = timestamp[:-11]
#FOR GROSS CALCULATION
timestamps_elapsed.append(timestamp_stripped)
#FOR NET CALCULATION
timestamps_net_helper.append(timestamp_stripped)
if len(timestamps_net_helper) == 2:
#CALCULATE SECONDS BETWEEN
time_a = datetime.strptime(timestamps_net_helper[0], "%Y/%m/%d %H:%M:%S")
time_b = datetime.strptime(timestamps_net_helper[1], "%Y/%m/%d %H:%M:%S")
time_difference = time.mktime(time_b.timetuple()) - time.mktime(time_a.timetuple())
#IF SECONDS LESS THAN 20 BETWEEN GPS TIMESTAMP THEN ADD UP NET TIME
if time_difference < 20:
timestamps_net.append(time_difference)
seconds = sum(timestamps_net)
hours = seconds/60/60
time_length_net = time.strftime('%H:%M:%S', time.gmtime(seconds))
#CLIMB.....
positive_climb = []
negative_climb = []
for a, b in zip(elevation_helper, elevation_helper[1:]):
if a > 0.0 and b > 0.0:
if b > a:
positive_climb.append(b-a)
elif b == a:
pass
else:
negative_climb.append(a-b)
positive_climb = sum(positive_climb)
negative_climb = sum(negative_climb)
#GROSS (ELAPSED TIME)
start = datetime.strptime(timestamps_elapsed[0], "%Y/%m/%d %H:%M:%S")
end = datetime.strptime(timestamps_elapsed[-1], "%Y/%m/%d %H:%M:%S")
time_length = end - start
#LENGTH
length_km = float(geom1.Length()/1000)
#AVERAGE SPEED
avg_speed = (geom1.Length()/1000)/hours
#CREATE LINESTRING FOR PPYGIS AND OGR LINESTRING
myLine = ogr.Geometry(ogr.wkbLineString)
polyline = []
for z in range(geom1.GetPointCount()):
x = geom1.GetX(z)
y = geom1.GetY(z)
myLine.AddPoint(x, y)
point = ppygis.Point(x, y)
polyline.append(point)
myLine_ppy = ppygis.LineString(polyline)
Label(root, text= time_length).grid(row=10, column=5)
Label(root, text= length_km).grid(row=11, column=5)
Label(root, text= avg_speed).grid(row=12, column=5)
self.button1 = Button(root, text='browse', command= open_file_dialog).grid(row=0,pady=10, padx=25)
self.button2 = Button(root, text='close', command= quit_me).grid(row=3, pady=10, padx=25)
root.mainloop()
trip_calculator()
The error occuring is libc++abi.dylib: pure virtual method called but only using lambda in the command of button3. Any ideas how to fix this?
The problem is likely due to the fact that some of the arguments you have in thelambdaexpression -- namelygeom1anddatasource_layer2-- are variables local to the nestedopen_file_dialog() function and don't exist later when the button is pressed and it has returned.
A simple fix would be to make them attributes of the trip_calculator instance, by adding a self.datasource_layer2 = datasource_layer2andself.geom1 = geom1 statements somewhere before the function returns (or just assigning them toselfand referencing them that way everywhere else).