Datepicker schließen Problem

Fragen zu Tkinter.
Antworten
DMD-OL
User
Beiträge: 315
Registriert: Samstag 26. Dezember 2015, 16:21

hallo leute
ich sitze jetzt schon seit längerem an einem naja kleinen (großen) Problem mit einem Datepicker-Code, den ich
aus dem Internet habe und dann leicht verändert habe.
Mein Problem ist, ich möchte gern, daß sich das Datepicker-Fenster nach Click wieder schließt (hatte das auch schon mal vor ein paar
Monaten beschrieben, leider ohne Ergebnis).
Hat jemand einen Tip?

Code: Alles auswählen

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

import Tkinter
import tkFont
import ttk
import datetime
import calendar
import sys

rech_fenster = Tkinter.Tk()
#rech_fenster.title('DMD-DATA.soft')
rech_fenster.geometry('400x400+350+180')

def get_calendar(locale, fwday):

    if locale is None:
        return calendar.TextCalendar(fwday)
    else:
        return calendar.LocaleTextCalendar(fwday, locale)

class Calendar(ttk.Frame):

    datetime = calendar.datetime.datetime
    timedelta = calendar.datetime.timedelta

    def __init__(self, master=None, **kw):

        fwday = kw.pop('firstweekday', calendar.MONDAY)
        year = kw.pop('year', self.datetime.now().year)
        month = kw.pop('month', self.datetime.now().month)
        locale = kw.pop('locale', None)
        sel_bg = kw.pop('selectbackground', '#ecffc4')
        sel_fg = kw.pop('selectforeground', '#05640e')
        self._date = self.datetime(year, month, 1)
        self._selection = None
        ttk.Frame.__init__(self, master, **kw)
        self._cal = get_calendar(locale, fwday)
        self.__setup_styles()
        self.__place_widgets()
        self.__config_calendar()
        self.__setup_selection(sel_bg, sel_fg)
        self._items = [self._calendar.insert('', 'end', values='')for _ in range(6)]
        self._build_calendar()

    def __setitem__(self, item, value):
        if item in ('year', 'month'):
            raise AttributeError("attribute '%s' is not writeable" % item)
        elif item == 'selectbackground':
            self._canvas['background'] = value
        elif item == 'selectforeground':
            self._canvas.itemconfigure(self._canvas.text, item=value)
        else:
            ttk.Frame.__setitem__(self, item, value)

    def __getitem__(self, item):
        if item in ('year', 'month'):
            return getattr(self._date, item)
        elif item == 'selectbackground':
            return self._canvas['background']
        elif item == 'selectforeground':
            return self._canvas.itemcget(self._canvas.text, 'fill')
        else:
            r = ttk.tclobjs_to_py({item: ttk.Frame.__getitem__(self, item)})
            return r[item]

    def __setup_styles(self):

        style = ttk.Style(self.master)
        arrow_layout = lambda dir: (
            [('Button.focus', {'children': [('Button.%sarrow' % dir, None)]})])
        style.layout('L.TButton', arrow_layout('left'))
        style.layout('R.TButton', arrow_layout('right'))

    def __place_widgets(self):

        hframe = ttk.Frame(self)
        lbtn = ttk.Button(hframe, style='L.TButton', command=self._prev_month)
        rbtn = ttk.Button(hframe, style='R.TButton', command=self._next_month)
        self._header = ttk.Label(hframe, width=15, anchor='center')
        self._calendar = ttk.Treeview(self, show='', selectmode='none', height=7)
        hframe.pack(in_=self, side='top', pady=4, anchor='center')
        lbtn.grid(in_=hframe)
        self._header.grid(in_=hframe, column=1, row=0, padx=12)
        rbtn.grid(in_=hframe, column=2, row=0)
        self._calendar.pack(in_=self, expand=1, fill='both', side='bottom')

    def __config_calendar(self):
        cols = self._cal.formatweekheader(3).split()
        self._calendar['columns'] = cols
        self._calendar.tag_configure('header', background='grey90')
        self._calendar.insert('', 'end', values=cols, tag='header')
        font = tkFont.Font()
        maxwidth = max(font.measure(col) for col in cols)
        for col in cols:
            self._calendar.column(col, width=maxwidth, minwidth=maxwidth,
                anchor='e')

    def __setup_selection(self, sel_bg, sel_fg):
        self._font = tkFont.Font()
        self._canvas = canvas = Tkinter.Canvas(self._calendar,
            background=sel_bg, borderwidth=0, highlightthickness=0)
        canvas.text = canvas.create_text(0, 0, fill=sel_fg, anchor='w')
        canvas.bind('<ButtonPress-1>', lambda evt: canvas.place_forget())
        self._calendar.bind('<Configure>', lambda evt: canvas.place_forget())
        self._calendar.bind('<ButtonPress-1>', self._pressed)

    def __minsize(self, evt):
        width, height = self._calendar.master.geometry().split('x')
        height = height[:height.index('+')]
        self._calendar.master.minsize(width, height)

    def _build_calendar(self):
        year, month = self._date.year, self._date.month
        header = self._cal.formatmonthname(year, month, 0)
        self._header['text'] = header.title()
        if len(list) == 0:
            list.extend((month, year))
        else:
            if len(list) == 2:
                list[0]=month
                list[1]=year
            else:
                list[1]=month
                list[2]=year
        cal = self._cal.monthdayscalendar(year, month)
        for indx, item in enumerate(self._items):
            week = cal[indx] if indx < len(cal) else []
            fmt_week = [('%02d' % day) if day else '' for day in week]
            self._calendar.item(item, values=fmt_week)

    def _show_selection(self, text, bbox):

        x, y, width, height = bbox
        textw = self._font.measure(text)
        canvas = self._canvas
        canvas.configure(width=width, height=height)
        canvas.coords(canvas.text, width - textw, height / 2 - 1)
        canvas.itemconfigure(canvas.text, text=text)
        canvas.place(in_=self._calendar, x=x, y=y)

    def _pressed(self, evt):

        x, y, widget = evt.x, evt.y, evt.widget
        item = widget.identify_row(y)
        column = widget.identify_column(x)
        if not column or not item in self._items:
            return
        item_values = widget.item(item)['values']
        if not len(item_values):
            return
        text = item_values[int(column[1]) - 1]
        if not text:
            return
        bbox = widget.bbox(item, column)
        if not bbox:
            return
        text = '%02d' % text
        self._selection = (text, item, column)
        self._show_selection(text, bbox)
        if len(list) == 2:
            list.insert(0, text)
        else:
            list[0]=text
        tag = list[0]
        monat = list[1]
        jahr = list[2]
        ausgabe_Datum(tag, monat, jahr)

    def _prev_month(self):

        self._canvas.place_forget()
        self._date = self._date - self.timedelta(days=1)
        self._date = self.datetime(self._date.year, self._date.month, 1)
        self._build_calendar()

    def _next_month(self):

        self._canvas.place_forget()
        year, month = self._date.year, self._date.month
        self._date = self._date + self.timedelta(
            days=calendar.monthrange(year, month)[1] + 1)
        self._date = self.datetime(self._date.year, self._date.month, 1)
        self._build_calendar()
    @property
    def selection(self):

        if not self._selection:
            return None
        year, month = self._date.year, self._date.month
        return self.datetime(year, month, int(self._selection[0]))

def auswahl_Datum():

    anzDa=Tkinter.Toplevel(rech_fenster)
    anzDa.title('Datum')
    anzDa.geometry('250x200+370+200')
    anzDa.attributes("-topmost", True)
    ttkcal = Calendar(anzDa,firstweekday=calendar.MONDAY)
    ttkcal.pack(expand=2, fill='both')

    if 'win' not in sys.platform:
        style = ttk.Style()
        style.theme_use('clam')

list = []
def ausgabe_Datum(tag, monat, jahr):
    monat = '%02d' % monat
    datum = (str(tag)+"."+str(monat)+"."+str(jahr))
    day, month, year = (int(x) for x in datum.split('.'))
    ans = datetime.date(year, month, day)
    wochenTag = ans.strftime("%A")
    tAg = wochenTag[0:3]
    if tAg == 'Mon':
        tAg = 'Mo'
    elif tAg == 'Tue':
        tAg = 'Di'
    elif tAg == 'Wed':
        tAg = 'Mi'
    elif tAg == 'Thu':
        tAg = 'Do'
    elif tAg == 'Fri':
        tAg = 'Fr'
    elif tAg == 'Sat':
        tAg = 'Sa'
    else:
        if tAg == 'Sun':
            tAg = 'So'

    hallo = tAg+", "+datum
    print hallo
    
b_ew7 = Tkinter.Button(rech_fenster, text=('Datum wählen'), width=15, relief="raised", borderwidth=3, font=('Arial', 9, 'bold'), justify='center', command=auswahl_Datum)
b_ew7.place(relx=.2, rely=.65, anchor="w")

rech_fenster.mainloop()
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@DMD-OL: Fenster schließt man mit destroy.

Das verwenden von festen Geometrien ist extrem abhängig von der gewählten Auflösung. Das bestimmen von Jahr und Monat ist fehlerhaft. Und warum man year und month nicht per Item setzen kann, kommt mir als Anwender komisch vor. Die doppelten Unterstriche Deiner Methoden wollen nur einen haben. In _build_calendar begehst Du gleich 3 Totsünden. 1. keine globalen Variablen, zumal das hier ja so undurchsichtig ist. 2. keine Builtin-Namen überschreiben, erst recht nicht global. 3. keine magischen Indizes in Listen, vor allem nicht, wenn die Magie auch noch von der Länge der Liste abhängt. Der Sinn des Ganzen erschließt sich mir sowieso nicht. In ausgabe_Datum machst Du auch umständliche Sachen: Erst tag, monat und jahr in einen String umwandeln, um ihn dann per split wieder in Zahlen umzuwandeln, die Du dann in ein datetime-Date umwandelst um dann den Wochentag als String zu bekommen, den Du dann vom Englischen ins Deutsche übersetzt. Es gibt weekday und LocaleTextCalendar.
Antworten