Tk - Kalender

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Ein Tkinter - Kalender:

http://paste.pocoo.org/show/125448/

Gruß Frank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich erlaube mir mal ein paar Anmerkungen:

- Aus den inneren Dictionaries würde ich Tupel machen. Die durchnummerierten Schlüssel sind ein relativ eindeutiges Zeichen.
- Du hast einmal "WEEK_DAYS" und "MONTH". Ich würde beide Male Singular oder Plural verwenden.
- Ich finde es etwas seltsam, eine leere Liste mittels "list()" zu erzeugen und nicht mit "[]".
- "build_gui" kann man sicher noch zusammenfassen
- Bei der range-Funktion kannst du die 0 als Startindex sparen.
- Bei einer Funktion "set_date" würde ich erwarten, dass ich etwas als Parameter übrgeben kann.
- Zu "change_month": Benutze Konstanten. Das geht ganz einfach, wenn du wie im ersten Punkt erwähnt, Tupel verwendest. Außerdem ist hier ein ideales Einsatzgebiet für den Modulo-Operator.
Das Leben ist wie ein Tennisball.
BlackJack

@EyDu: Leere Listen und Dictionaries erzeuge ich in der Regel auch mit ``list()`` bzw. ``dict()``. Ist IMHO lesbarer als [] und {}, die man bei der "richtigen" Schriftgrösse leichter verwechseln kann.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo EyDu !

Danke Dir !

1. Eine Dict mit Schlüsseln für die Sprachversion und den Rest als Tupel ?
2. ist geändert
3. Man könnte die Buttons und Labels noch über einen Schleife erzeugen !?
4. ist geändert
5. make_date ?
6. Für mich ist es eine Konstante (nicht als eine ausgewiesen - ok), da man eigentlich
immer nur einen "1-step" macht. Mache es noch mit Konstante und Modulo-Operator -
nur wie ? Muss mal probieren.
Das mit list() habe ich von BlackJack abgeschaut - hat er auch so festgestellt :-)

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Das mit dem Modulo-Operator hab ich nicht so geklappt.

http://paste.pocoo.org/show/126052/

Gruß Frank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das WNR hat meiner Meinung nach nichts in den Wochentage zu suchen, das würde ich dort immer explizit einfügen, wo es gebraucht wird.

Dann solltest du deinen Code noch einmal auf Konstanten untersuchen. Die Werte in den range-Funktionen kann man sicher ersetzen.

Zum Modulo:

Code: Alles auswählen

def change_date(self, step_month, step_year):
        self.month = (self.month + 1) % len(self.MONTHS[self.language])
        self.year_label.config(text = self.year)
        self.month_label.config(text=self.MONTHS[self.language][self.month])
        self.make_date()
Du könntest noch ein paar Eigenschaften zusammenfassen:

Code: Alles auswählen

properties = dict(calendar_frame, text=day_name, width=5, font=self.font,  relief=self.relief, fg=self.control_fg, bg=self.control_bg)

for column, day_name in enumerate(self.WEEK_DAYS[self.language]):
    tk.Label(**properties).grid(row=0, column=column)

for row in xrange(1, 7):
    week_number = tk.Label(**properties)
    week_number.grid(row=row, column=0)
    self.week_numbers.append(week_number)
    
    week = list()
    for column in xrange(1, 8):
        day = tk.Label(**properties) 
        week.append(day)
        day.grid(row=row, column=column)

Sebastian
Das Leben ist wie ein Tennisball.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke EyDu!

Das mit "properties=dict(...)" ist ja eine elegante Lösung. Die range-Funktionen nehme ich, um eine gleichmäßiges Feld zu bekommen, da Calendar nur Listen mit tatsächlichen Tagen bzw. Wochen erzeugt und somit die Größe des Feldes variieren würde.

Der Modulo-Operator erzeugt bei Dezember eine 0 und es ensteht ein IndexError - ok kann man noch lösen und man hat einen Bezug zu der Anzahl der Monate und keine Konstante, doch bei einem Kalender verändert diese sich doch nicht ?!

Meinst Du auch Konstanten in den frames, labels, buttons etc. ? Die Größe des eigentlichen Kalenders, wollte ich nur über die Schriftgröße veränderbar machen, damit das Layout bestehen bleibt.

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Verbesserte Version: http://paste.pocoo.org/show/126443/

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Ich habe einen Versuch gemacht mit dem Kalender zu kommunizieren, doch dies geht nur über ein Hilfskonstruktion mittels "after". Hat jemand eine bessere Idee oder neuen Ansatz wählen ?

Code: Alles auswählen

def main():
    
    def update_gui(label):
        label.config(text=cal.select_date)
    
    def set_select_date(event, label):
        label.after(1, update_gui, label)
        
    root = tk.Tk()
    cal = Tk_Calendar(root, "Arial 10 bold", "black", "white", "black", 
        "green", "black", "gray85", "groove", "eng")
    cal.pack(padx=5, pady=5)
    current_date_label = tk.Label(root, text=cal.current_date)
    current_date_label.pack()
    cal.bind("<Enter>", lambda event, label=current_date_label: 
        set_select_date(event, label))
    root.title("Calendar")
    root.mainloop()
     
if __name__ == "__main__":
    main()
Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Diese Version funktioniert nur beim Einschalten von visuellen Effekten unter Ubuntu 9.04 ?

Sind sie abgeschaltet funktioniert das "updaten" nicht ?

Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

So klappt es jetzt !

Code: Alles auswählen

class Gui(object):
    def __init__(self, root):
        self.root = root
        self.date_select_status = True
        self.calendar = Tk_Calendar(root, "Courier 10 bold", "black", "white", 
            "black", "green", "black", "gray85", "groove", "eng")
        self.calendar.pack()
        self.date_label = tk.Label(root, text=self.calendar.select_date.strftime(
            "%d.%m.%y"))
        self.date_label.pack()
        self.calendar.bind("<Enter>", self.start_get_select_date)
        self.calendar.bind("<Leave>", self.stop_get_select_date)
        
        
    def start_get_select_date (self, event):
        if self.date_select_status:
            self.date_label.config(text = self.calendar.select_date.strftime(
            "%d.%m.%y"))
            self.root.after(50, self.start_get_select_date, event)
            
        
    def stop_get_select_date(self, event):
        self.date_select_status = False
        self.root.after(100, self.config_status)
        
        
    def config_status(self):
        self.date_select_status = True
        
        
def main():
       
    root = tk.Tk()
    gui = Gui(root)
    root.title("Calendar")
    root.mainloop()
     
if __name__ == "__main__":
    main() 
Gruß Frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Noch einige Änderungen gemacht: http://paste.pocoo.org/show/127456/

Gruß Frank
Benutzeravatar
krisi12345
User
Beiträge: 205
Registriert: Mittwoch 4. März 2009, 16:56
Wohnort: Das schöne München
Kontaktdaten:

Neues Design:

Code: Alles auswählen

#! /usr/bin/env python
# -*- coding: utf-8

import Tkinter as tk
from calendar import Calendar
import time
from datetime import datetime
class Tk_Calendar(tk.Frame):
    WEEK_DAYS = {"de" : ("Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"),
                 "eng" : ("Mo","Tu", "We", "Th", "Fr", "Sa", "So")}              
    MONTHS = {"de" : ("Januar", "Februar", "Maerz", "April", "Mai", 
                      "Juni", "Juli", "August", "September", "Oktober",
                      "November", "Dezember"),
              "eng" : ("January", "February", "March", "April", "May",
                       "June", "July", "August", "September", "Oktober",
                       "November","December")}             
    MONTH_LABEL_WIDTH = 10
    YEAR_LABEL_WIDTH = 5
    DAY_LABEL_WIDTH = 5
    CONTROL_RELIEF = "flat"       
    def __init__(self, root, font=("arial",15,"bold"), day_fg="black",
        day_bg = "white", current_day_fg = "black", current_day_bg = "#FF6051",
            control_fg = "black", control_bg = "gray85", relief = "flat",
                select_day_bg = "#4765FF", language = "de"):
        tk.Frame.__init__(self, root, bg=control_bg)
        self.week_numbers = list()
        self.weeks = list()
        self.calendar = Calendar()
        self.select_day = time.localtime().tm_mday
        self.select_year = time.localtime().tm_year
        self.select_month = time.localtime().tm_mon
        self.select_date = datetime(self.select_year, self.select_month,
            self.select_day)
        self.language = language
        self.day_fg = day_fg
        self.day_bg = day_bg
        self.current_day_fg = current_day_bg
        self.current_day_bg = current_day_bg
        self.select_day_bg = select_day_bg
        control_properties = dict(font = font, fg = control_fg,  
            bg = control_bg, relief = self.CONTROL_RELIEF)
        calendar_properties = dict(font = font, fg = control_fg,
            bg = control_bg, relief = relief, width = self.DAY_LABEL_WIDTH)    
        control_frame_date_left = tk.Frame(self, bg = control_bg)
        control_frame_date_left.grid(row=0, column=0, sticky="w", 
            padx=3, pady=3)
        control_frame_date_right = tk.Frame(self, bg = control_bg)
        control_frame_date_right.grid(row=0, column=1, sticky="e",
            padx=3, pady=3)
        control_buttons = ((control_frame_date_left, "<<", -1, 0, 
                            self.change_date, 0, 0),
                           (control_frame_date_left, ">>", 1, 0, 
                            self.change_date, 0, 2),
                           (control_frame_date_right, "<<", 0, -1, 
                            self.change_date, 0, 3),
                           (control_frame_date_right, ">>", 0, 1, 
                            self.change_date, 0, 5))          
        for frame, text, step_month, step_year, command, row, column\
            in control_buttons:
            tk.Button(frame, text=text, relief="flat", width=1, 
                fg=control_fg, bg=control_bg, font=font,
                    command=lambda step_month=step_month, step_year=step_year: 
                        command(step_month, step_year)
                            ).grid(row=row, column=column)                  
        self.month_label = tk.Label(control_frame_date_left, 
            width=self.MONTH_LABEL_WIDTH, **control_properties)
        self.month_label.grid(row=0, column=1)
        self.year_label = tk.Label(control_frame_date_right,
            width = self.YEAR_LABEL_WIDTH, **control_properties)
        self.year_label.grid(row=0, column=4)
        calendar_frame = tk.Frame(self, bg=control_bg)
        calendar_frame.grid(row=1, columnspan=2) 
        tk.Label(calendar_frame, **calendar_properties).grid(row=0, column=0)
        for column, day_name in enumerate(self.WEEK_DAYS[self.language]):
            tk.Label(calendar_frame, text=day_name, **calendar_properties
                ).grid(row=0, column=column+1)       
        for row in xrange(1, 7):
            week_number = tk.Label(calendar_frame, **calendar_properties)
            week_number.grid(row=row, column=0)
            self.week_numbers.append(week_number)
            week = list()
            for column in xrange(1, 8):
                day = tk.Label(calendar_frame, **calendar_properties)
                day.grid(row=row, column=column) 
                week.append(day)
                day.bind("<Leave>", lambda event, label=day, row=row, 
                    bg=self.day_bg, column=column: 
                        self.config_bind_label(event, label, row, column, bg))
                day.bind("<Enter>", lambda event, label=day, row=row,
                    bg=self.select_day_bg, column=column:
                        self.config_bind_label(event, label, row, column, bg))
                day.bind("<Button-1>",lambda event, row=row, column=column: 
                    self.selected_date(event, row, column))
            self.weeks.append(week)
        self.make_date()
    def get_day(self, row, column):
        try:
            day = self.calendar.monthdayscalendar(
                self.select_year, self.select_month)[row-1][column-1]
        except IndexError:
            day = 0
        return day
    def config_bind_label(self, event, label, row, column, bg):
        label.config(bg = bg)
        day = self.get_day(row, column)
        if day == 0:
            label.config(fg = self.day_bg, bg = self.day_bg)
        elif day == time.localtime().tm_mday and\
            self.select_month == time.localtime().tm_mon and\
                self.select_year == time.localtime().tm_year:
                    label.config(bg = self.current_day_bg)
    def selected_date(self, event, row, column):
        day = self.get_day(row, column)
        if day > 0:
            self.select_day = day
            self.select_date = datetime(self.select_year, 
                self.select_month, self.select_day)
    def make_date(self):
        self.year_label.config(text = self.select_year)
        self.month_label.config(
            text = self.MONTHS[self.language][self.select_month-1])
        for week in self.weeks:
            for day in week:
                day.config(text = "", bg = self.day_bg)
        for week_number in self.week_numbers:
            week_number.config(text = "")
        for index_week, week in enumerate(self.calendar.monthdayscalendar(
            self.select_year, self.select_month)):
            for index_day, day in enumerate(week):
                if day > 0:
                    iso_calendar = datetime(self.select_year, 
                        self.select_month, day)
                    iso_year, iso_week, iso_day = iso_calendar.isocalendar()
                fg = self.day_fg
                bg = self.day_bg
                if day == 0:
                    fg = self.day_bg
                elif day == time.localtime().tm_mday and\
                    time.localtime().tm_mon == self.select_month and\
                        time.localtime().tm_year == self.select_year:
                            bg = self.current_day_bg
                self.weeks[index_week][index_day].config(text = day, fg =fg, 
                    bg = bg)
            self.week_numbers[index_week].config(text = iso_week)
    def change_date(self, step_month, step_year):
        self.select_month += step_month
        self.select_year += step_year
        self.select_month = self.select_month % len(self.MONTHS[self.language])
        if self.select_month == 0:
            self.select_month = len(self.MONTHS[self.language])
        self.make_date()  
class Gui(object):
    def __init__(self, root):
        self.root = root
        self.date_select_status = True
        self.calendar = Tk_Calendar(root)
        self.calendar.pack()
        self.date_label = tk.Label(root, text=self.calendar.select_date.strftime(
            "%d.%m.%y"))
        self.date_label.pack()
        self.calendar.bind("<Enter>", self.start_get_select_date)
        self.calendar.bind("<Leave>", self.stop_get_select_date)
    def start_get_select_date (self, event):
        if self.date_select_status:
            self.date_label.config(text = self.calendar.select_date.strftime(
            "%d.%m.%y"))
            self.root.after(50, self.start_get_select_date, event)
    def stop_get_select_date(self, event):
        self.date_select_status = False
        self.root.after(100, self.config_status)        
    def config_status(self):
        self.date_select_status = True      
def main():    
    root = tk.Tk()
    gui = Gui(root)
    root.title("Calendar")
    root.mainloop()
if __name__ == "__main__":
    main() 
[url=http://www.pc-tutos.de/Tutorials/Tutorials.htm]Wie verändert man Spiele oder Computer nach Wunsch? www.PC-Tutos.de[/url]
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

krisi: Es existiert das babel-Modul (babel.edgewall.org), um Wochentagsnamen und Monatsnamen automatisch zu lokalisieren.
Benutzeravatar
krisi12345
User
Beiträge: 205
Registriert: Mittwoch 4. März 2009, 16:56
Wohnort: Das schöne München
Kontaktdaten:

krisi: Es existiert das babel-Modul (babel.edgewall.org), um Wochentagsnamen und Monatsnamen automatisch zu lokalisieren.
Also eigentlich wollte Ich nur die Farben und Schriftart/größe ändern.
[url=http://www.pc-tutos.de/Tutorials/Tutorials.htm]Wie verändert man Spiele oder Computer nach Wunsch? www.PC-Tutos.de[/url]
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo !

Einige Änderungen: http://paste.pocoo.org/show/131766/

Gruß Frank
Benutzeravatar
krisi12345
User
Beiträge: 205
Registriert: Mittwoch 4. März 2009, 16:56
Wohnort: Das schöne München
Kontaktdaten:

passt! :D
[url=http://www.pc-tutos.de/Tutorials/Tutorials.htm]Wie verändert man Spiele oder Computer nach Wunsch? www.PC-Tutos.de[/url]
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

krisi12345 hat geschrieben:
krisi: Es existiert das babel-Modul (babel.edgewall.org), um Wochentagsnamen und Monatsnamen automatisch zu lokalisieren.
Also eigentlich wollte Ich nur die Farben und Schriftart/größe ändern.
Oh, tut mir leid. Da hab ich wohl zu schnell geguckt. Das ist aber trotzdem kein Grund, um von kaytac überhört zu werden ;)
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Wenn habe ich überhört ?

Gruß Frank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo kaytec!

Ein paar Vorschläge hätte ich da noch:
- Die __init__-Methode ist mittlerweile etwas lang und sehr unübersichtlich. Ich würde sie in mehrere Methoden unterteilen. Sollte auch nicht schwierig sein, die Blöcke bestehen im Prinzip ja schon.
- In "for column in xrange(1, 8):" sind mit 1 und 8 doch sicherlich die Tage der Wochen gemeint, das würde ich noch über ein "len" über "WEEK_DAYS" verweden.
- Sehe ich das richtig, dass Monate und Tage mit 1 beginnen? Das ist, zumindest aus Informatiker-Sicht, sehr ungewöhnlich. Das spart außerdem einige Sonderfälle, wie beispielsweise den in den Zeilen 199-201.
- "functools.partial" ist noch einen Blick wert, damit könnte man wohl die lambdas etwas loswerden.
- Ein "if state == True:" geht natürlich gar nicht ;-)
- Zeilen 153 bis 155 kann man sicher eleganter über den Vergleich von Tupeln lösen: (day, self.select_month, self.select_year) == time.localtime()[:3]

Sebastian
Das Leben ist wie ein Tennisball.
Antworten