前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python clock 时钟

python clock 时钟

作者头像
用户5760343
发布2022-05-13 10:41:12
8600
发布2022-05-13 10:41:12
举报
文章被收录于专栏:sktj

image.png

--------------------------------windows.py------------------------------- """ ############################################################################### Classes that encapsulate top-level interfaces. Allows same GUI to be main, pop-up, or attached; content classes may inherit from these directly, or be mixed together with them per usage mode; may also be called directly without a subclass; designed to be mixed in after (further to the right than) app-specific classes: else, subclass gets methods here (destroy, okayToQuit), instead of from app-specific classes--can't redefine. ############################################################################### """

import os, glob from tkinter import Tk, Toplevel, Frame, YES, BOTH, RIDGE from tkinter.messagebox import showinfo, askyesno

class _window: """ mixin shared by main and pop-up windows """ foundicon = None # shared by all inst iconpatt = '*.ico' # may be reset iconmine = 'py.ico'

代码语言:javascript
复制
def configBorders(self, app, kind, iconfile):
    if not iconfile:                                   # no icon passed?
        iconfile = self.findIcon()                     # try curr,tool dirs
    title = app
    if kind: title += ' - ' + kind
    self.title(title)                                  # on window border
    self.iconname(app)                                 # when minimized
    if iconfile:
        try:
            self.iconbitmap(iconfile)                  # window icon image
        except:                                        # bad py or platform
            pass
    self.protocol('WM_DELETE_WINDOW', self.quit)       # don't close silent

def findIcon(self):
    if _window.foundicon:                              # already found one?
        return _window.foundicon
    iconfile  = None                                   # try curr dir first
    iconshere = glob.glob(self.iconpatt)               # assume just one
    if iconshere:                                      # del icon for red Tk
        iconfile = iconshere[0]
    else:                                              # try tools dir icon
        mymod  = __import__(__name__)                  # import self for dir
        path   = __name__.split('.')                   # poss a package path
        for mod in path[1:]:                           # follow path to end
            mymod = getattr(mymod, mod)                # only have leftmost
        mydir  = os.path.dirname(mymod.__file__)
        myicon = os.path.join(mydir, self.iconmine)    # use myicon, not tk
        if os.path.exists(myicon): iconfile = myicon
    _window.foundicon = iconfile                       # don't search again
    return iconfile

class MainWindow(Tk, _window): """ when run in main top-level window """ def init(self, app, kind='', iconfile=None): self.findIcon() Tk.init(self) self.__app = app self.configBorders(app, kind, iconfile)

代码语言:javascript
复制
def quit(self):
    if self.okayToQuit():                                # threads running?
        if askyesno(self.__app, 'Verify Quit Program?'):
            self.destroy()                               # quit whole app
    else:
        showinfo(self.__app, 'Quit not allowed')         # or in okayToQuit?

def destroy(self):                                       # exit app silently
    Tk.quit(self)                                        # redef if exit ops

def okayToQuit(self):                                    # redef me if used
    return True                                          # e.g., thread busy

class PopupWindow(Toplevel, _window): """ when run in secondary pop-up window """ def init(self, app, kind='', iconfile=None): Toplevel.init(self) self.__app = app self.configBorders(app, kind, iconfile)

代码语言:javascript
复制
def quit(self):                                        # redef me to change
    if askyesno(self.__app, 'Verify Quit Window?'):    # or call destroy
        self.destroy()                                 # quit this window

def destroy(self):                                     # close win silently
    Toplevel.destroy(self)                             # redef for close ops

class QuietPopupWindow(PopupWindow): def quit(self): self.destroy() # don't verify close

class ComponentWindow(Frame): """ when attached to another display """ def init(self, parent): # if not a frame Frame.init(self, parent) # provide container self.pack(expand=YES, fill=BOTH) self.config(relief=RIDGE, border=2) # reconfig to change

代码语言:javascript
复制
def quit(self):
    showinfo('Quit', 'Not supported in attachment mode')

# destroy from Frame: erase frame silent               # redef for close ops

----------------------------------------clock.py------------------------------- """ ############################################################################### PyClock 2.1: a clock GUI in Python/tkinter.

With both analog and digital display modes, a pop-up date label, clock face images, general resizing, etc. May be run both standalone, or embedded (attached) in other GUIs that need a clock.

New in 2.0: s/m keys set seconds/minutes timer for pop-up msg; window icon. New in 2.1: updated to run under Python 3.X (2.X no longer supported) ############################################################################### """

from tkinter import * from tkinter.simpledialog import askinteger import math, time, sys

###############################################################################

Option configuration classes

###############################################################################

class ClockConfig: # defaults--override in instance or subclass size = 200 # width=height bg, fg = 'beige', 'brown' # face, tick colors hh, mh, sh, cog = 'black', 'navy', 'blue', 'red' # clock hands, center picture = None # face photo file

class PhotoClockConfig(ClockConfig): # sample configuration size = 320 picture = '../gifs/ora-pp.gif' bg, hh, mh = 'white', 'blue', 'orange'

###############################################################################

Digital display object

###############################################################################

class DigitalDisplay(Frame): def init(self, parent, cfg): Frame.init(self, parent) self.hour = Label(self) self.mins = Label(self) self.secs = Label(self) self.ampm = Label(self) for label in self.hour, self.mins, self.secs, self.ampm: label.config(bd=4, relief=SUNKEN, bg=cfg.bg, fg=cfg.fg) label.pack(side=LEFT) # TBD: could expand, and scale font on resize

代码语言:javascript
复制
def onUpdate(self, hour, mins, secs, ampm, cfg):
    mins = str(mins).zfill(2)                          # or '%02d' % x
    self.hour.config(text=str(hour), width=4)
    self.mins.config(text=str(mins), width=4)
    self.secs.config(text=str(secs), width=4)
    self.ampm.config(text=str(ampm), width=4)

def onResize(self, newWidth, newHeight, cfg):
    pass  # nothing to redraw here

###############################################################################

Analog display object

###############################################################################

class AnalogDisplay(Canvas): def init(self, parent, cfg): Canvas.init(self, parent, width=cfg.size, height=cfg.size, bg=cfg.bg) self.drawClockface(cfg) self.hourHand = self.minsHand = self.secsHand = self.cog = None

代码语言:javascript
复制
def drawClockface(self, cfg):                         # on start and resize
    if cfg.picture:                                   # draw ovals, picture
        try:
            self.image = PhotoImage(file=cfg.picture)          # bkground
        except:
            self.image = BitmapImage(file=cfg.picture)         # save ref
        imgx = (cfg.size - self.image.width())  // 2           # center it
        imgy = (cfg.size - self.image.height()) // 2           # 3.x // div
        self.create_image(imgx+1, imgy+1,  anchor=NW, image=self.image)
    originX = originY = radius = cfg.size // 2                 # 3.x // div
    for i in range(60):
        x, y = self.point(i, 60, radius-6, originX, originY)
        self.create_rectangle(x-1, y-1, x+1, y+1, fill=cfg.fg)   # mins
    for i in range(12):
        x, y = self.point(i, 12, radius-6, originX, originY)
        self.create_rectangle(x-3, y-3, x+3, y+3, fill=cfg.fg)   # hours
    self.ampm = self.create_text(3, 3, anchor=NW, fill=cfg.fg)

def point(self, tick, units, radius, originX, originY):
    angle = tick * (360.0 / units)
    radiansPerDegree = math.pi / 180
    pointX = int( round( radius * math.sin(angle * radiansPerDegree) ))
    pointY = int( round( radius * math.cos(angle * radiansPerDegree) ))
    return (pointX + originX+1), (originY+1 - pointY)

def onUpdate(self, hour, mins, secs, ampm, cfg):        # on timer callback
    if self.cog:                                        # redraw hands, cog
        self.delete(self.cog)
        self.delete(self.hourHand)
        self.delete(self.minsHand)
        self.delete(self.secsHand)
    originX = originY = radius = cfg.size // 2          # 3.x div
    hour = hour + (mins / 60.0)
    hx, hy = self.point(hour, 12, (radius * .80), originX, originY)
    mx, my = self.point(mins, 60, (radius * .90), originX, originY)
    sx, sy = self.point(secs, 60, (radius * .95), originX, originY)
    self.hourHand = self.create_line(originX, originY, hx, hy,
                         width=(cfg.size * .04),
                         arrow='last', arrowshape=(25,25,15), fill=cfg.hh)
    self.minsHand = self.create_line(originX, originY, mx, my,
                         width=(cfg.size * .03),
                         arrow='last', arrowshape=(20,20,10), fill=cfg.mh)
    self.secsHand = self.create_line(originX, originY, sx, sy,
                         width=1,
                         arrow='last', arrowshape=(5,10,5), fill=cfg.sh)
    cogsz = cfg.size * .01
    self.cog = self.create_oval(originX-cogsz, originY+cogsz,
                                originX+cogsz, originY-cogsz, fill=cfg.cog)
    self.dchars(self.ampm, 0, END)
    self.insert(self.ampm, END, ampm)

def onResize(self, newWidth, newHeight, cfg):
    newSize = min(newWidth, newHeight)
    #print('analog onResize', cfg.size+4, newSize)
    if newSize != cfg.size+4:
        cfg.size = newSize-4
        self.delete('all')
        self.drawClockface(cfg)  # onUpdate called next

###############################################################################

Clock composite object

###############################################################################

ChecksPerSec = 10 # second change timer

class Clock(Frame): def init(self, config=ClockConfig, parent=None): Frame.init(self, parent) self.cfg = config self.makeWidgets(parent) # children are packed but self.labelOn = 0 # clients pack or grid me self.display = self.digitalDisplay self.lastSec = self.lastMin = -1 self.countdownSeconds = 0 self.onSwitchMode(None) self.onTimer()

代码语言:javascript
复制
def makeWidgets(self, parent):
    self.digitalDisplay = DigitalDisplay(self, self.cfg)
    self.analogDisplay  = AnalogDisplay(self,  self.cfg)
    self.dateLabel      = Label(self, bd=3, bg='red', fg='blue')
    parent.bind('<ButtonPress-1>', self.onSwitchMode)
    parent.bind('<ButtonPress-3>', self.onToggleLabel)
    parent.bind('<Configure>',     self.onResize)
    parent.bind('<KeyPress-s>',    self.onCountdownSec)
    parent.bind('<KeyPress-m>',    self.onCountdownMin)

def onSwitchMode(self, event):
    self.display.pack_forget()
    if self.display == self.analogDisplay:
        self.display = self.digitalDisplay
    else:
        self.display = self.analogDisplay
    self.display.pack(side=TOP, expand=YES, fill=BOTH)

def onToggleLabel(self, event):
    self.labelOn += 1
    if self.labelOn % 2:
        self.dateLabel.pack(side=BOTTOM, fill=X)
    else:
        self.dateLabel.pack_forget()
    self.update()

def onResize(self, event):
    if event.widget == self.display:
        self.display.onResize(event.width, event.height, self.cfg)

def onTimer(self):
    secsSinceEpoch = time.time()
    timeTuple      = time.localtime(secsSinceEpoch)
    hour, min, sec = timeTuple[3:6]
    if sec != self.lastSec:
        self.lastSec = sec
        ampm = ((hour >= 12) and 'PM') or 'AM'               # 0...23
        hour = (hour % 12) or 12                             # 12..11
        self.display.onUpdate(hour, min, sec, ampm, self.cfg)
        self.dateLabel.config(text=time.ctime(secsSinceEpoch))
        self.countdownSeconds -= 1
        if self.countdownSeconds == 0:
            self.onCountdownExpire()                # countdown timer
    self.after(1000 // ChecksPerSec, self.onTimer)  # run N times per second
                                                    # 3.x // trunc int div
def onCountdownSec(self, event):
    secs = askinteger('Countdown', 'Seconds?')
    if secs: self.countdownSeconds = secs

def onCountdownMin(self, event):
    secs = askinteger('Countdown', 'Minutes')
    if secs: self.countdownSeconds = secs * 60

def onCountdownExpire(self):
    # caveat: only one active, no progress indicator
    win = Toplevel()
    msg = Button(win, text='Timer Expired!', command=win.destroy)
    msg.config(font=('courier', 80, 'normal'), fg='white', bg='navy')
    msg.config(padx=10, pady=10)
    msg.pack(expand=YES, fill=BOTH)
    win.lift()                             # raise above siblings
    if sys.platform[:3] == 'win':          # full screen on Windows
        win.state('zoomed')

###############################################################################

Standalone clocks

###############################################################################

appname = 'PyClock 2.1'

use new custom Tk, Toplevel for icons, etc.

from windows import PopupWindow, MainWindow

class ClockPopup(PopupWindow): def init(self, config=ClockConfig, name=''): PopupWindow.init(self, appname, name) clock = Clock(config, self) clock.pack(expand=YES, fill=BOTH)

class ClockMain(MainWindow): def init(self, config=ClockConfig, name=''): MainWindow.init(self, appname, name) clock = Clock(config, self) clock.pack(expand=YES, fill=BOTH)

b/w compat: manual window borders, passed-in parent

class ClockWindow(Clock): def init(self, config=ClockConfig, parent=None, name=''): Clock.init(self, config, parent) self.pack(expand=YES, fill=BOTH) title = appname if name: title = appname + ' - ' + name self.master.title(title) # master=parent or default self.master.protocol('WM_DELETE_WINDOW', self.quit)

###############################################################################

Program run

###############################################################################

if name == 'main': def getOptions(config, argv): for attr in dir(ClockConfig): # fill default config obj, try: # from "-attr val" cmd args ix = argv.index('-' + attr) # will skip x internals except: continue else: if ix in range(1, len(argv)-1): if type(getattr(ClockConfig, attr)) == int: setattr(config, attr, int(argv[ix+1])) else: setattr(config, attr, argv[ix+1])

config = PhotoClockConfig()

代码语言:javascript
复制
config = ClockConfig()
if len(sys.argv) >= 2:
    getOptions(config, sys.argv)         # clock.py -size n -bg 'blue'...

myclock = ClockWindow(config, Tk()) # parent is Tk root if standalone

myclock = ClockPopup(ClockConfig(), 'popup')

代码语言:javascript
复制
myclock = ClockMain(config)
myclock.mainloop()
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Option configuration classes
  • Digital display object
  • Analog display object
  • Clock composite object
  • Standalone clocks
  • use new custom Tk, Toplevel for icons, etc.
  • b/w compat: manual window borders, passed-in parent
  • Program run
  • config = PhotoClockConfig()
  • myclock = ClockWindow(config, Tk()) # parent is Tk root if standalone
  • myclock = ClockPopup(ClockConfig(), 'popup')
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档