Reputation: 101
In tcl, I made the following simple login program.
package require Tk
wm geometry . "150x125"
set systemTime [clock seconds]
ttk::entry .loginUser
ttk::entry .loginPass -show "*"
ttk::label .l -text "Username:"
ttk::label .l2 -text "Password:"
ttk::button .b -text "Login"
pack .l
pack .loginUser
pack .l2
pack .loginPass
pack .b
bind . <Return> ".b invoke"
proc CheckLogin {} {
if {[.loginUser get] eq "None"} {
if {[.loginPass get] eq "1234"} {
destroy {*}[winfo children .]
ttk::label .time -text [clock format $::systemTime -format %T]
ttk::button .b -text "Check time" -command {
.time configure -text [clock format $::systemTime -format %T]
pack .time
}
pack .b
}
}
}
.b configure -command CheckLogin
With this program, once you log in, you are presented with a single button: Check time. When the button is pressed, it gives a clock displaying the time as %H %M %S, %H being hours, %M being minutes, and %S being seconds. However, when you click the button, the time shows once, and it doesn't change. My question is, is there a way to make the clock update itself, like going 14:29:1 to 14:29:2 WITHOUT the previous time showing?
Upvotes: 0
Views: 585
Reputation: 137627
The primary problem you've got is that the systemTime
global variable is not being kept up to date with the actual system time. We either need to switch to using [clock seconds]
directly, or we need to add a little worker “task” to keep the variable up to date. Here's the latter option:
proc updateTheTime {} {
set ::systemTime [clock seconds]
after 500 updateTheTime
}
updateTheTime
That'll keep the variable current and can be just added to your current code simply. Though you can do better and make it so that the current time display is also automatically updated. Doing that easily requires the -textvariable
option to the ttk::label
(and many other widgets support it as well):
proc updateTheTime {} {
global systemTime displayedTime
set systemTime [clock seconds]
set displayedTime [clock format $systemTime -format "%T"]
after 500 updateTheTime
}
updateTheTime
# ...
ttk::label .time -textvariable displayedTime
That's all it requires to make an active GUI; the widget will automatically notice the changed variable and update itself (it uses the same machinery that powers Tcl's variable traces). An update every half second is so cheap in computational terms that you'll not notice it, except for the fact that the timestamp will be updating. Want the widget to show something else? Just change the code that generates the value in the variable.
Upvotes: 5
Reputation: 16428
We have to use the clock seconds
each time so that we can get the current time exactly. In your case, you have used ::systemTime
to access the time, but it static since it is obtained at the start of the program.
If you have used
ttk::label .time -text [clock format [clock seconds] -format %T]
Then you could have got the current time on each time you click the button.
I have added a loop to get the current time with a interval of 500ms and there is a button placed to stop the update of the time where update
command places a role in it.
package require Tk
wm geometry . "150x125"
set systemTime [clock seconds]
ttk::entry .loginUser
ttk::entry .loginPass -show "*"
ttk::label .l -text "Username:"
ttk::label .l2 -text "Password:"
ttk::button .b -text "Login"
pack .l
pack .loginUser
pack .l2
pack .loginPass
pack .b
bind . <Return> ".b invoke"
set ::done 0
proc CheckLogin {} {
if {[.loginUser get] eq "None"} {
if {[.loginPass get] eq "1234"} {
destroy {*}[winfo children .]
ttk::label .time -text [clock format [clock seconds] -format %T]
ttk::button .b -text "Check time" -command {
.time configure -text [clock format [clock seconds] -format %T]
pack .time
puts "init done : $::done"
while {!$::done} {
.time configure -text [clock format [clock seconds] -format %T]
after 500
update
}
}
pack .b
ttk::button .stop -text "Stop Updating" -command {
after 100 {
puts "user stopped the time update"
set ::done 1
}
}
pack .stop
}
}
}
.b configure -command CheckLogin
Upvotes: 1