Tkk Label Farbe abhängig vom Wert

Fragen zu Tkinter.
Antworten
onkelhamu
User
Beiträge: 20
Registriert: Freitag 20. Oktober 2017, 21:07

Hallo,
ich habe sowas im Code

Code: Alles auswählen

        for eintraege in templiste:
            if datetime.datetime.strptime(eintraege, '%d.%m.%Y-%S') < datetime.datetime.now():
                label_bg_color = '#%02x%02x%02x' % (255, 65, 65)
            else:
                label_bg_color = '#%02x%02x%02x' % (255, 244, 222)
            self.labels[eintraege].configure(background = label_bg_color)

            self.labels[eintraege].grid(        row = last_row,
                                                column = 0,
                                                sticky = "nesw"
                                                )
            last_row += 1
gedacht hab ich das das Label die Farbe ändert, aber es ändert sich nicht komplett sondern bekommt nur einen roten Rand.
Geht das bei tkinter nicht?
Oder liegt das an windows10? Lässt das nicht zu oder so?
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Wo werden die Labels erzeugt? Warum hast Du Zeiten als Strings und nicht als datetime-Objekte gespeichert und warum heißt eine Zeit eintraege? Und warum sind die Zeiten in einer Liste, die laut Name irgendwas mit Tempeln zu tun hat?
Ist es Absicht, dass jeder Eintrag mit einer anderen Zeit verglichen wird? Die aktuelle Zeit sollte einmal vor der Liste ermittelt werden.

Zeige bitte ein vollständiges lauffähiges Programm, sonst können wir hier nicht sehen was alles sonst noch passiert.
onkelhamu
User
Beiträge: 20
Registriert: Freitag 20. Oktober 2017, 21:07

Das ist aber viel...
aber bitte nicht soviel meckern :D

Code: Alles auswählen

# !/usr/bin/env python3
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# # Name:        todolist
# # Project:     todolist
# #
# # Author:      Hamu
# #
# # Created:     21.11.2019
# # Copyright:   (c) Hamu 20xx
# # Licence:
# #
# -----------------------------------------------------------------------------

import tkinter as tk
from tkinter import ttk
import json
import os
import binascii
import cryptography.exceptions
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import calendar
import datetime
from functools import partial
import base64
from cryptography.fernet import Fernet

# -----------------------------------------------------------------------------

class todolist(tk.Frame):
    def __init__(self, parent, todo_dic, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.labels = {}
        self.todo_dic = todo_dic
        for zaehler in self.todo_dic.keys():
            self.labels[zaehler] = todolabel(   self,
                                                self.todo_dic[zaehler][1],
                                                self.todo_dic[zaehler][2],
                                                zaehler
                                                )
        self.fuelle_liste()

    def edit_label(self, datums_key):
        self.parent.parent.frames[2].eingabe_start(
            self.todo_dic[datums_key][1],
            self.todo_dic[datums_key][2],
            datums_key
            )

    def fuelle_liste(self):
        last_row = 0

        templiste = []
        templiste2 = []
        for eintraege in self.labels.keys():
            templiste.append(datetime.datetime.strptime(eintraege, '%d.%m.%Y-%M'))
        templiste2 = sorted(templiste)
        templiste = []    
        for eintraege in templiste2:
            templiste.append(eintraege.strftime('%d.%m.%Y-%M'))

        for eintraege in templiste:
            if datetime.datetime.strptime(eintraege, '%d.%m.%Y-%S') < datetime.datetime.now():
                label_bg_color = '#%02x%02x%02x' % (255, 65, 65)
            else:
                label_bg_color = '#%02x%02x%02x' % (255, 244, 222)
            self.labels[eintraege].configure(background = label_bg_color)

            self.labels[eintraege].grid(        row = last_row,
                                                column = 0,
                                                sticky = "nesw"
                                                )
            last_row += 1

    def leere_liste(self):
        for self.widget in self.winfo_children():
            self.widget.grid_forget()

    def add_label(self, datum, todo_string, datums_key = None):
        if datums_key == None:
            datums_key_nr = 0
            datums_key = "{0:s}-{1:02d}".format(datum, datums_key_nr)
            while datums_key in self.todo_dic.keys():
                datums_key_nr += 1
                datums_key = "{0:s}-{1:02d}".format(datum, datums_key_nr)

        self.todo_dic[datums_key] = [           "dummisalt", 
                                                datum,
                                                todo_string
                                                ]
        
        self.labels[datums_key] = todolabel(   self,
                                            self.todo_dic[datums_key][1],
                                            self.todo_dic[datums_key][2],
                                            datums_key
                                            )
        self.fuelle_liste()                                       

    def del_label(self, datums_key):
        del_datum, del_index = datums_key.split("-")
        for zaehler in self.todo_dic.keys():
            datum, index = zaehler.split("-")
            if del_datum in zaehler and index > del_index:

                new_datums_key = "{0:s}-{1:02d}".format(datum, int(index) - 1)
                temp = self.todo_dic[new_datums_key]
                temp2 = self.labels[new_datums_key]                
                self.todo_dic[new_datums_key] = self.todo_dic[zaehler]
                self.labels[new_datums_key] = self.labels[zaehler]
                self.todo_dic[zaehler] = temp
                self.labels[zaehler] = temp2                

        for zaehler in self.todo_dic.keys():
            if del_datum in zaehler:
                last_zaehler = zaehler
        del self.todo_dic[last_zaehler]
        del self.labels[last_zaehler]
        self.leere_liste()
        self.fuelle_liste()

class todolabel(tk.Frame):
    def __init__(self, parent, datum = None, text = None, datums_key = None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.datum = str(datum)
        self.text = str(text)
        self.datums_key = datums_key
        self.label_text = "{0:s}\t{1:s}".format(self.datum, self.text)

        style = ttk.Style()
        style.configure(                        
                                                "todoliste.TLabel",
                                                font = ("TkDefaultFont", 12),
                                                foreground = "black",
                                                anchor = "w",
                                                background = '#%02x%02x%02x' % (255, 244, 222)
                                                )        
        self.columnconfigure(
                                                0,  
                                                minsize = 600,
                                                )
        self.label = ttk.Label(    
                                                self,
                                                text = self.label_text,
                                                style = "todoliste.TLabel" 
                                                )
        self.label.grid(           
                                                row = 0, 
                                                column = 0, 
                                                sticky = (tk.W + tk.E)
                                                )
        self.erledigt_bt = ttk.Button(         
                                                self,
                                                text = "Erledigt",
                                                command = partial(parent.del_label, self.datums_key)
                                                )
        self.erledigt_bt.grid(               
                                                row = 0,
                                                column = 1,
                                                sticky = (tk.E + tk.W + tk.N + tk.S)
                                                )
        self.edit_bt = ttk.Button(         
                                                self,
                                                text = "Bearbeiten",
                                                command = partial(parent.edit_label, self.datums_key)
                                                )
        self.edit_bt.grid(                      
                                                row = 0,
                                                column = 2,
                                                sticky = (tk.E + tk.W + tk.N + tk.S)
                                                )

class datepicker(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.WOCHENTAGE = [" Mo", " Di", " Mi", " Do", " Fr", " Sa", " So"]
        self.MONATE = [None,    "Januar", "Februar", "März",
                                "April", "Mai", "Juni", 
                                "Juli", "August", "September", 
                                "Oktober", "November", "Dezember"]
        self.kalender = calendar.TextCalendar(calendar.MONDAY)
        self.heute = datetime.datetime.now()

        self.jahr = self.heute.year
        self.monat = self.heute.month
        self.gew_datum_liste = [None, None, None]
        self.angez_monat_string = tk.StringVar()
        self.angez_monat_string.set(self.MONATE[self.monat])
        self.angez_jahr_string = tk.StringVar()
        self.angez_jahr_string.set(str(self.jahr))

        self.frame_oben = ttk.Frame(self)
        self.frame_oben.pack(fill = "x")
        self.frame_unten = ttk.Frame(self)
        self.frame_unten.pack(fill = "x")

        style = ttk.Style()
        style.configure(                    "Red.TButton", 
                                            foreground = "red"
                                            )

        self.make_leiste()
        self.make_calender(self.jahr, self.monat)

    def get_weeklist(self, jahr, monat):
        self.jahr = jahr
        self.monat = monat
        self.monat_str = self.kalender.formatmonth(self.jahr, self.monat) 
        self.templiste = self.monat_str.splitlines()
        self.ausgabeliste = []
        del self.templiste[0:2]
        if len(self.templiste) < 6:
            self.templiste.append("                     ")
        for self.zaehler in self.templiste:
            self.woche = (""" {0:s}""".format(self.zaehler))
            for self.zaehler_2 in range(0, 19, 3):
                self.tempstring = self.woche[0 + self.zaehler_2: 3 + self.zaehler_2]
                if self.tempstring == "":
                    self.tempstring = "   "
                self.ausgabeliste.append(self.tempstring)

        return self.ausgabeliste

    def make_calender(self, jahr, monat):
        self.jahr = jahr
        self.monat = monat
        self.datebutton_liste = self.get_weeklist(      self.jahr,
                                                        self.monat
                                                        )
        for self.zaehler in range(7):
            self.frame_unten.columnconfigure(           self.zaehler,  
                                                        minsize = 36,
                                                        weight = 0
                                                        )
        for self.zaehler in range(7):
            self.frame_unten.rowconfigure(              self.zaehler,
                                                        minsize = 36,  
                                                        weight = 0
                                                        )
        
        self.tagesnamen = []
        for self.zaehler_2 in range(7):
            self.tagesnamen.append(ttk.Label(           self.frame_unten,
                                                        text = self.WOCHENTAGE[self.zaehler_2]
                                                        ))
            self.tagesnamen[self.zaehler_2].grid(       row = 0,
                                                        column = self.zaehler_2,
                                                        sticky = "nesw"
                                                        )

        self.date_button = []
        self.labelindex = 0
        for self.zaehler in range(6):
            for self.zaehler_2 in range(7):
                self.date_button.append(ttk.Button(     self.frame_unten,
                                                        width = 4, 
                                                        text = self.datebutton_liste[self.labelindex]
                                                        ))
                self.date_button[self.labelindex].bind("<Button-1>", self.kal_clicked)
                if self.datebutton_liste[self.labelindex] == "   ":
                    self.date_button[self.labelindex].state(["disabled"])

                self.heute = datetime.datetime.now()
                if  self.heute.year == self.jahr and self.heute.month == self.monat and self.datebutton_liste[self.labelindex] != "   " and self.heute.day == int(self.datebutton_liste[self.labelindex]):
                    self.date_button[self.labelindex].configure(style = "Red.TButton")
                    # Heutigen Tag Rot Färben

                self.date_button[self.labelindex].grid( row = self.zaehler + 1,
                                                        column = self.zaehler_2,
                                                        sticky = "nesw"
                                                        )
                self.labelindex += 1
     
    def make_leiste(self):

                  
        self.prev_monat_button = ttk.Button(            self.frame_oben,
                                                        width = 3,
                                                        text = u"\u2190",
                                                        command = lambda:self.show_prev_monat(self.angez_monat_string.get(), self.angez_jahr_string.get())
                                                        )
        self.prev_monat_button.pack(side = "left")
        self.angez_monat_label = ttk.Label(             self.frame_oben,
                                                        width = 12,
                                                        anchor = "center",
                                                        textvariable = self.angez_monat_string
                                                        )
        self.angez_monat_label.pack(side = "left")
        self.next_monat_button = ttk.Button(            self.frame_oben,
                                                        width = 3,
                                                        text = u"\u2192",
                                                        command = lambda:self.show_next_monat(self.angez_monat_string.get(), self.angez_jahr_string.get())
                                                        )
        self.next_monat_button.pack(side = "left")
        self.next_jahr_button = ttk.Button(             self.frame_oben,
                                                        width = 3,
                                                        text = u"\u2192",
                                                        command = lambda:self.show_next_year(self.angez_monat_string.get(), self.angez_jahr_string.get())
                                                        )
        self.next_jahr_button.pack(side = "right")
        self.angez_jahr_label = ttk.Label(              self.frame_oben,
                                                        width = 6,
                                                        anchor = "center",
                                                        textvariable = self.angez_jahr_string
                                                        )
        self.angez_jahr_label.pack(side = "right")
        self.prev_jahr_button = ttk.Button(             self.frame_oben,
                                                        width = 3,
                                                        text = u"\u2190",
                                                        command = lambda:self.show_prev_year(self.angez_monat_string.get(), self.angez_jahr_string.get())
                                                        )
        self.prev_jahr_button.pack(side = "right")
      
    def destroy_calender(self):
        for self.zaehler in range(42):
            self.date_button[self.zaehler].destroy()
        self.gew_datum_liste = [None, None, None]
        self.tag = None
        self.monat = None
        self.jahr = None            
       
    def show_prev_monat(self, monat, jahr):
        self.destroy_calender()
        
        self.jahr = int(jahr)
        self.monat = self.MONATE.index(monat) - 1
        if self.monat < 1:
            self.monat = 12
            self.jahr -= 1
        self.angez_monat_string.set(self.MONATE[self.monat])
        self.angez_jahr_string.set(str(self.jahr))

        self.make_calender(self.jahr, self.monat)
       
    def show_next_monat(self, monat, jahr):
        self.destroy_calender()
        
        self.jahr = int(jahr)
        self.monat = self.MONATE.index(monat) + 1
        if self.monat > 12:
            self.monat = 1
            self.jahr += 1
        self.angez_monat_string.set(self.MONATE[self.monat])
        self.angez_jahr_string.set(str(self.jahr))

        self.make_calender(self.jahr, self.monat)
       
    def show_prev_year(self, monat, jahr):
        self.destroy_calender()
        
        self.jahr = int(jahr) - 1
        self.monat = self.MONATE.index(monat)
        if self.jahr < datetime.MINYEAR:
            self.heute = datetime.datetime.now()
            self.jahr = self.heute.year
        self.angez_monat_string.set(self.MONATE[self.monat])
        self.angez_jahr_string.set(str(self.jahr))

        self.make_calender(self.jahr, self.monat)
       
    def show_next_year(self, monat, jahr):
        self.destroy_calender()
        
        self.jahr = int(jahr) + 1
        self.monat = self.MONATE.index(monat)
        if self.jahr > datetime.MAXYEAR:
            self.heute = datetime.datetime.now()
            self.jahr = self.heute.year
        self.angez_monat_string.set(self.MONATE[self.monat])
        self.angez_jahr_string.set(str(self.jahr))

        self.make_calender(self.jahr, self.monat)
    
    def kal_clicked(self, clicked = None):
        self.clicked_button = clicked.widget
        try:
            self.tag = int(self.clicked_button["text"])
            self.monat = self.MONATE.index(self.angez_monat_string.get())
            self.jahr = int(self.angez_jahr_string.get())
            self.gew_datum_liste[0] = self.tag
            self.gew_datum_liste[1] = self.monat
            self.gew_datum_liste[2] = self.jahr           
        except (ValueError, AttributeError):
            pass
      
    def get_date(self):
        return self.gew_datum_liste

class pincode(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        self.rueckgabewert = tk.IntVar()
        self.rueckgabewert.set(0)
        self.parent = parent
        self.HASH_NAME = "SHA256"
        self.ALGORITHM = hashes.SHA256()
        self.SALT_LENGTH = 32
        self.ITERATIONS = 1000000
        self.BACKEND = default_backend()
        self.JSONFILE = "todo.json"
        self.ZAHLENBUTTONSGROESSE = 36
        self.FONT = "TkDefaultFont", 12, "bold"
        self.pin = None
        
        self.make_widget()

    def hash_password(self, password):
        self.password = password
        self.salt = os.urandom(self.SALT_LENGTH)

        self.kdf = PBKDF2HMAC(
                            self.ALGORITHM,
                            self.SALT_LENGTH,
                            self.salt,
                            self.ITERATIONS,
                            self.BACKEND
                            )
        
        self.key = self.kdf.derive(self.password.encode("utf8"))

        return ':'.join([self.HASH_NAME, 
            binascii.hexlify(self.salt).decode("ascii"),
            binascii.hexlify(self.key).decode("ascii"),
            str(self.ITERATIONS)])

    def check_hash(self, hashstring, eingabe):
        self.hashstring = hashstring
        self.eingabe = eingabe
        self.hash_name, self.salt, self.hash, self.iterations = self.hashstring.split(":")
        self.kdf = PBKDF2HMAC(
            self.ALGORITHM,
            self.SALT_LENGTH,
            binascii.unhexlify(self.salt),
            int(self.iterations),
            self.BACKEND
            )
       
        try:
            self.kdf.verify(self.eingabe.encode("utf8"), binascii.unhexlify(self.hash))
            return True

        except (cryptography.exceptions.InvalidKey, cryptography.exceptions.AlreadyFinalized):
            return False

    def make_widget(self):
        self.label1_string = tk.StringVar()
        self.label1_string.set("")        
        style = ttk.Style()
        style.configure(                            "pincode.TLabel",
                                                    font = (self.FONT),
                                                    anchor="e",
                                                    pad = 0,
                                                    foreground = "white",
                                                    background = "purple",
                                                    weight = 0)        
        style.configure(                            "zahlenbutton.TButton",
                                                    pad = 0,
                                                    font=(self.FONT),
                                                    width = 1)

        self.grid_columnconfigure(     0,
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)       
        self.grid_columnconfigure(     1,
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)
        self.grid_columnconfigure(     2,
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)
        self.grid_rowconfigure(        1,  
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)
        self.grid_rowconfigure(        2,  
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)
        self.grid_rowconfigure(        3,  
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)
        self.grid_rowconfigure(        4,  
                                                    minsize = self.ZAHLENBUTTONSGROESSE,
                                                    weight=0)        
        self.label1 = ttk.Label(            self,
                                            style = "pincode.TLabel",
                                            textvariable = self.label1_string
                                            )
        self.label1.grid(                   row = 0,
                                            column = 0,
                                            columnspan = 3,
                                            sticky = "nesw"
                                            )
        self.zahlen_button = []
        self.zahlenindex = 0
        self.zahlen_button.append(ttk.Button(       self,
                                                    width = 3,
                                                    style="zahlenbutton.TButton", 
                                                    text = self.zahlenindex
                                                    ))
        self.zahlen_button[self.zahlenindex].grid(  row = 4,
                                                    column = 1,
                                                    sticky = "nesw"
                                                    )
        self.zahlen_button[self.zahlenindex].bind("<Button-1>", self.zahl_clicked)        
        self.zahlenindex += 1      
        for self.zaehler in range(3):
            for self.zaehler_2 in range(3):
                self.zahlen_button.append(ttk.Button(self,
                                                    width = 3,
                                                    style="zahlenbutton.TButton", 
                                                    text = self.zahlenindex
                                                    )
                                                    )
                self.zahlen_button[self.zahlenindex].bind("<Button-1>", self.zahl_clicked)
                
                self.zahlen_button[self.zahlenindex].grid( row = self.zaehler + 1,
                                                        column = self.zaehler_2,
                                                        sticky = "nesw"
                                                        )
                self.zahlenindex += 1

        self.zahlen_button.append(ttk.Button(       self,
                                                    width = 3,
                                                    style="zahlenbutton.TButton", 
                                                    text = "ok"
                                                    ))
        self.zahlen_button[self.zahlenindex].grid(  row = 4,
                                                    column = 0,
                                                    sticky = "nesw"
                                                    )
        self.zahlen_button[self.zahlenindex].bind("<Button-1>", self.zahl_clicked) 
        self.zahlenindex += 1                                                  
        self.zahlen_button.append(ttk.Button(       self,
                                                    width = 3,
                                                    style="zahlenbutton.TButton", 
                                                    text = "del"
                                                    ))
        self.zahlen_button[self.zahlenindex].grid(  row = 4,
                                                    column = 2,
                                                    sticky = "nesw"
                                                    )
        self.zahlen_button[self.zahlenindex].bind("<Button-1>", self.zahl_clicked)
        self.abbrechen_button = ttk.Button(         self,
                                                    style = "zahlenbutton.TButton",
                                                    text = "Abbrechen",
                                                    command = self.abbruch
                                                    )
        self.abbrechen_button.grid(                 row = 5,
                                                    column = 0,
                                                    columnspan = 3,
                                                    sticky = (tk.E + tk.W + tk.N + tk.S)
                                                    )

    def zahl_clicked(self, clicked=None):
        
        self.clicked_button = clicked.widget
        self.button_gewählt = self.clicked_button["text"]
        self.label_inhalt = self.label1_string.get()

        if self.button_gewählt == "ok" and not os.path.exists(self.JSONFILE):
            if len(self.label_inhalt) == 4:
                
                self.hashed_password = (self.hash_password(self.label_inhalt))
                self.json_string = {"password": self.hashed_password, "todo_liste" : []}
                with open(self.JSONFILE, "w") as json_file:
                    json.dump(self.json_string, json_file)
                self.parent.parent.status_label_string.set("PIN gesetzt")
                self.rueckgabewert.set(2)           #Login
                self.pin = self.label_inhalt
                return self.rueckgabewert               

            else:
                self.rueckgabewert.set(1)           #Passwortlänge falsch!
                self.pin = None
                return self.rueckgabewert

        elif self.button_gewählt == "ok":
            if len(self.label_inhalt) != 4:
                self.rueckgabewert.set(1)           #Passwortlänge falsch!
                self.pin = None
                return self.rueckgabewert
            else:
                with open(self.JSONFILE, "r") as json_file:
                    jsondata = json.load(json_file)

                self.hash = jsondata["password"]
                if self.check_hash(self.hash, self.label_inhalt):
                    self.rueckgabewert.set(2)           #Login
                    self.pin = self.label_inhalt
                    return self.rueckgabewert

                else:
                    self.rueckgabewert.set(4)           #Login verweigert!
                    self.pin = None
                    return self.rueckgabewert
                    # raise AssertionError("login failed")

            
        elif self.button_gewählt == "del":
            self.label1_string.set(self.label_inhalt[:-1])
            
        elif len(self.label_inhalt) < 4:    
            self.tempstring = "{}{}".format(self.label_inhalt, self.button_gewählt)
            self.label1_string.set(self.tempstring)
        else:
            self.rueckgabewert.set(0)               #Login verweigert!
            return self.rueckgabewert
            # raise AssertionError("login failed")

    def abbruch(self):
        self.rueckgabewert.set(3)                   #Abbruch
        return self.rueckgabewert

class hauptmenu_gui(ttk.Frame):
    """Hauptmenü erstellen"""
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.rowconfigure(                  3,
                                            minsize = 50,
                                            weight = 0
                                            )                
        self.datumsanzeige = datepicker(    self
                                            )
        self.datumsanzeige.grid(            row = 0,
                                            column = 0,
                                            columnspan = 2,
                                            padx = 10,
                                            pady = 10,
                                            sticky = "nesw"
                                            )
        self.neu_bt = ttk.Button(           self,
                                            style = "my1.TButton",
                                            text = "Neu",
                                            command = self.neu_eintrag
                                            )
        self.neu_bt.grid(                   row = 1,
                                            column = 0,
                                            padx = 10,
                                            pady = 10,                  
                                            sticky = "nesw"
                                            )
        self.save_button = ttk.Button(      self,
                                            style = "my1.TButton",
                                            text = "Speichern",
                                            command = self.speichern
                                            )
        self.save_button.grid(              row = 1,
                                            column = 1,
                                            padx = 10,
                                            pady = 10,
                                            sticky = "nesw"
                                            )
        self.end_button = ttk.Button(       self,
                                            style = "my2.TButton",
                                            text = "Ende",
                                            command = self.parent.ende
                                            )
        self.end_button.grid(               row = 2,
                                            column = 0,
                                            columnspan = 2,
                                            padx = 10,
                                            pady = 10,
                                            sticky = "nesw"
                                            )
        todo_dic = self.parent.frames[0].load_todo()
        self.todobox = todolist(self, todo_dic)
        self.todobox.grid(               
                                            row = 0,
                                            rowspan = 3,
                                            column = 2,
                                            padx = 10,
                                            pady = 10,
                                            sticky = "nesw"
                                            )
        self.distanz_frame_1 = ttk.Frame(   self,
                                            style = "my1.TFrame"
                                            )
        self.distanz_frame_1.grid(          row = 3, 
                                            column = 0,
                                            columnspan = 3,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)              
                                            )      

    def neu_eintrag(self):
        neu_datum = self.datumsanzeige.get_date()
        if neu_datum[0] != None:
            datum = "{0:02d}.{1:02d}.{2:02d}".format(neu_datum[0], neu_datum[1], neu_datum[2])
            self.parent.frames[2].eingabe_start(datum)
        else:
            return False

    def speichern(self):
        self.parent.frames[0].save_todo(self.todobox.todo_dic)

class pincode_gui(ttk.Frame):
    """Hauptmenü erstellen"""
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.TODOFILE = "todo.json"
        self.label_oben_string = tk.StringVar()
        self.label_oben_string.set("Bitte gib deinen PIN ein...")
        
        self.columnconfigure(
            0,
            minsize = 460,
            weight = 0
        )
        self.columnconfigure(
            2,
            minsize = 460,
            weight = 0
        )
        self.rowconfigure(
            2,
            minsize = 200,
            weight = 0
        )

        self.label_oben = ttk.Label(        self,
                                            style = "my1.TLabel",
                                            textvariable = self.label_oben_string
                                            )
        self.label_oben.grid(               row = 0,
                                            column = 0,
                                            columnspan = 3,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )
        self.distanz_frame_1 = ttk.Frame(   self,
                                            style = "my1.TFrame"
                                            )
        self.distanz_frame_1.grid(          row = 1, 
                                            column = 0,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            ) 
        self.distanz_frame_2 = ttk.Frame(   self,
                                            style = "my1.TFrame"
                                            )
        self.distanz_frame_2.grid(          row = 1, 
                                            column = 2,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )       
        self.pincodefeld = pincode(         self,
                                            )
        self.pincodefeld.grid(              row = 1,
                                            column = 1,
                                            sticky = "nesw"
                                            )
        self.distanz_frame_3 = ttk.Frame(   self,
                                            style = "my1.TFrame"
                                            )
        self.distanz_frame_3.grid(          row = 2, 
                                            column = 0,
                                            columnspan = 5,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )

    def load_todo(self):
        try:
            with open(self.TODOFILE, "r") as json_file:
                jsondata = json.load(json_file)
            pin = self.parent.frames[0].pincodefeld.pin    
            password = pin.encode('utf-8')
            todo_dic = {}
            todo_liste = jsondata["todo_liste"]

            self.hashed_password = jsondata["password"]

            for zaehler in todo_liste:
                salt, datums_key_token, datum_token, token = zaehler.split(":")

                kdf = PBKDF2HMAC(           algorithm = hashes.SHA256(),
                                            length = 32,
                                            salt = binascii.unhexlify(salt),
                                            iterations = 1000000,
                                            backend = default_backend()
                                            )

                key = base64.urlsafe_b64encode(kdf.derive(password))
                f = Fernet(key)
                datums_key_token = binascii.unhexlify(datums_key_token)
                datum_token = binascii.unhexlify(datum_token)
                token = binascii.unhexlify(token)
                datums_key = f.decrypt(datums_key_token).decode('utf-8')
                datum = f.decrypt(datum_token).decode('utf-8')
                todo_string = f.decrypt(token).decode('utf-8')

                todo_dic[datums_key] = [
                                                    salt, 
                                                    datum,
                                                    todo_string
                                                    ]
            return todo_dic
        except FileNotFoundError:
            return {}        

    def save_todo(self, todo_dic):
        pin = self.parent.frames[0].pincodefeld.pin
        password = pin.encode('utf-8')
        salt = os.urandom(32)
        kdf = PBKDF2HMAC(           algorithm = hashes.SHA256(),
                                    length = 32,
                                    salt = salt,
                                    iterations = 1000000,
                                    backend = default_backend()
                                    )
        key = base64.urlsafe_b64encode(kdf.derive(password))
        f = Fernet(key)
        if todo_dic == {}:
            jsondata = {"password": self.hashed_password, "todo_liste" : []}
        else:
            encoded_todo_list = []
            for zaehler in todo_dic.keys():
                datums_key_token = f.encrypt(zaehler.encode('utf-8'))
                datum_token = f.encrypt(todo_dic[zaehler][1].encode('utf-8'))
                token = f.encrypt(todo_dic[zaehler][2].encode('utf-8'))
                encoded_todo = ':'.join(
                    [binascii.hexlify(salt).decode("ascii"),
                    binascii.hexlify(datums_key_token).decode("ascii"),
                    binascii.hexlify(datum_token).decode("ascii"),
                    binascii.hexlify(token).decode("ascii")
                    ]
                    )
                encoded_todo_list.append(encoded_todo)
            jsondata = {"password": self.hashed_password, "todo_liste" : encoded_todo_list}
        try:
            with open(self.TODOFILE, "w") as json_file:
                json.dump(jsondata, json_file)
            if len(todo_dic.keys()) == 1:
                self.parent.status_label_string.set("{0:d} Eintrag gesichert".format(len(todo_dic.keys())))
            else:
                self.parent.status_label_string.set("{0:d} Einträge gesichert".format(len(todo_dic.keys())))
        except PermissionError:
            pass

class eingabe_gui(ttk.Frame):
    """EingabeGUI erstellen"""
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.label_oben_string = tk.StringVar()
        self.label_oben_string.set("")
        self.datum_label_string = tk.StringVar()
        self.datum_label_string.set("")
        self.eingabe_string = tk.StringVar()
        self.eingabe_string.set("")

        for zaehler in range(6):
            self.columnconfigure(           zaehler,
                                            minsize = 172,
                                            weight = 0
                                            )
        self.rowconfigure(                  2,
                                            minsize = 50,
                                            weight = 0
                                            )        

        self.label_oben = ttk.Label(        self,
                                            style = "my2.TLabel",
                                            textvariable = self.label_oben_string
                                            )
        self.label_oben.grid(               row = 0,
                                            column = 0,
                                            columnspan = 6,
                                            padx=10,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )

        self.datum_label = ttk.Label(       self,
                                            style = "my3.TLabel",
                                            textvariable = self.datum_label_string
                                            )
        self.datum_label.grid(              row = 1,
                                            column = 0,
                                            padx=10,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )

        self.eingabe = ttk.Entry(           self,
                                            font=("TkDefaultFont", 12, "bold"),
                                            justify="left",            
                                            textvariable = self.eingabe_string
                                            )
        self.eingabe.grid(                  row = 1,
                                            column = 1,
                                            columnspan = 5,
                                            padx=10,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )
        self.eingabe.bind(                  "<Key-Return>",
                                            self.uebernehmen)        
        self.distanz_frame_1 = ttk.Frame(   self,
                                            style = "my1.TFrame"
                                            )
        self.distanz_frame_1.grid(          row = 2, 
                                            column = 0,
                                            columnspan = 6,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)              
                                            )
        self.uebernehmen_bt = ttk.Button(   self,
                                            style = "my1.TButton",
                                            text = "Übernehmen",
                                            command = self.uebernehmen
                                            )
        self.uebernehmen_bt.grid(           row = 3,
                                            column = 0,
                                            columnspan = 3,
                                            padx=10,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )        
        self.abbrechen_bt = ttk.Button(     self,
                                            style = "my1.TButton",
                                            text = "Abbrechen",
                                            command = self.abbrechen
                                            )
        self.abbrechen_bt.grid(             row = 3,
                                            column = 3,
                                            columnspan = 3,
                                            padx=10,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )

    def eingabe_start(self, datum, todo_string = None, datums_key = None):
        if todo_string == None and datums_key == None:
            self.datum_label_string.set(datum)
            self.datums_key = datums_key
            self.eingabe.focus()
            self.parent.show_frame(2)
        else:
            self.datum_label_string.set(datum)
            self.eingabe_string.set(todo_string)
            self.datums_key = datums_key
            self.eingabe.focus()
            self.parent.show_frame(2)

    def uebernehmen(self, *event):# """*event wegen RETURN-Taste"""
        datum = self.datum_label_string.get()
        todo_string = self.eingabe_string.get()
        self.parent.frames[1].todobox.add_label(    datum,
                                                    todo_string,
                                                    self.datums_key
                                                    )
        self.datum_label_string.set("")
        self.eingabe_string.set("")
        self.parent.show_frame(1)

    def abbrechen(self):
        self.datum_label_string.set("")
        self.eingabe_string.set("")
        self.parent.show_frame(1)

class gui(ttk.Frame):
    """gui erstellen"""

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.parent = parent
        self.parent.title("Todolist")
        self.parent.resizable(width=False, height=False)
        self.parent.protocol("WM_DELETE_WINDOW", self.ende)
        self.backcolor = '#%02x%02x%02x' % (128, 0, 128)
        self.entry_back = '#%02x%02x%02x' % (255, 244, 222)
        self.status_label_string = tk.StringVar()
        self.status_label_string.set("")

        style = ttk.Style()
        style.configure(                    "my1.TFrame",
                                            pad = 0,
                                            weight = 0,
                                            foreground = self.backcolor,
                                            background = self.backcolor
                                            )
        style.configure(                    "my1.TButton",
                                            font = ("TkDefaultFont", 10, "bold"),
                                            background = "black",
                                            pad = 0,
                                            width = 1,
                                            wraplength = 150
                                            )
        style.configure(                    "my2.TButton",
                                            pad = 0,
                                            font = ("TkDefaultFont", 10, "bold"),
                                            background = "black",
                                            foreground = "red",
                                            width = 1,
                                            wraplength = 150
                                            )
        style.configure(                    "my1.TLabel",
                                            font = ("TkDefaultFont", 10, "bold"),
                                            foreground = "white",
                                            background = self.backcolor,
                                            anchor = "center",
                                            pad = 0,
                                            weight = 0
                                            )
        style.configure(                    "my2.TLabel",
                                            font = ("TkDefaultFont", 12, "bold"),
                                            foreground = "white",
                                            background = self.backcolor,
                                            anchor = "w",
                                            pad = 0,
                                            weight = 0
                                            )
        style.configure(                    "my3.TLabel",
                                            font = ("TkDefaultFont", 12, "bold"),
                                            anchor = "w",
                                            pad = 0,
                                            weight = 0
                                            )
        style.configure(                    "my4.TLabel",
                                            font = ("TkDefaultFont", 10),
                                            foreground = "white",
                                            background = self.backcolor,
                                            anchor = "w",
                                            pad = 0,
                                            weight = 0
                                            )        
        self.frames = []
        self.frames.append(pincode_gui(     self,
                                            style="my1.TFrame"
                                            )
                                            )
        self.frames[0].grid(                row=0,
                                            column=0,
                                            sticky=(tk.E + tk.W + tk.N + tk.S),
                                            )
        self.status_frame = ttk.Frame(      self,
                                            style = "my1.TFrame"
                                            )
        self.status_frame.grid(             row = 2, 
                                            column = 0,
                                            sticky = (tk.E + tk.W + tk.N + tk.S)
                                            )        
        self.status_label = ttk.Label(      self.status_frame,
                                            textvariable = self.status_label_string,
                                            style = "my4.TLabel" 
                                            )
        self.status_label.grid(             row = 2, 
                                            column = 0,
                                            padx = 10, 
                                            sticky = (tk.W + tk.E)
                                            )
        self.check_pincode()
        self.show_frame(0)

    def show_frame(self, framenummer):
        """holt Frame nach vorne"""
        self.frames[framenummer].lift()
        return True

    def ende(self):
        try:
            self._root().destroy()
        except:
            self._root().destroy()

    def check_pincode(self):
        #   0       Login verweigert!
        #   1       Passwortlänge falsch!
        #   2       Login
        #   3       Abbruch
        #   4       Passwort falsch!
        self.after(500, self.check_pincode)
        if self.frames[0].pincodefeld.rueckgabewert.get() == 1:
            self.frames[0].pincodefeld.rueckgabewert.set(0)
            self.frames[0].label_oben_string.set("Passwortlänge falsch!")
        elif self.frames[0].pincodefeld.rueckgabewert.get() == 2:
            self.frames[0].pincodefeld.rueckgabewert.set(0)
            self.frames.append(hauptmenu_gui(   self,
                                                style="my1.TFrame"
                                                )
                                                )
            self.frames[1].grid(                row=0,
                                                column=0,
                                                sticky=(tk.E + tk.W + tk.N + tk.S),
                                                )
            self.frames.append(eingabe_gui(     self,
                                                style="my1.TFrame"
                                                )
                                                )
            self.frames[2].grid(                row=0,
                                                column=0,
                                                sticky=(tk.E + tk.W + tk.N + tk.S),
                                                )            
            self.show_frame(1)

        elif self.frames[0].pincodefeld.rueckgabewert.get() == 3:
            self.frames[0].pincodefeld.rueckgabewert.set(0)
            self.ende()
        elif self.frames[0].pincodefeld.rueckgabewert.get() == 4:
            self.frames[0].pincodefeld.rueckgabewert.set(0)
            self.frames[0].label_oben_string.set("Passwort falsch!")
        else:
            self.frames[0].pincodefeld.rueckgabewert.set(0)

def main():
    root = tk.Tk()
    app = gui(root)
    app.pack()
    app.mainloop()


if __name__ == "__main__":
    main()
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Klassen schreibt man mit großem Anfangsbuchstaben: TodoLabel. So wie es jetzt ist, ist es furchtbar verwirrend.
In fuelle_liste parst Du erst das Datum, um es dann wieder in einen String zu verwandeln um es dann wieder zu parsen? Warum???
Speichere die Zeit immer als datetime-Objekt. Dann reduziert sich die Funktion auf das hier:

Code: Alles auswählen

    def fuelle_liste(self):
        current_date = datetime.datetime.now()
        for row, (date, label) in enumerate(sorted(self.labels.items())):
            color = (255, 65, 65) if date < current_date else (255, 244, 222)
            label['background'] = '#%02x%02x%02x' % color
            label.grid(row=row, column=0, sticky="nesw")
Da TodoLabel aber gar kein Label ist, sondern ein Frame, der ein Label enthält, sollte wohl klar sein, dass die Hintergrundfarbe des Frames vom Label überdeckt wird.

An etlichen anderen Stellen benutzt Du auch `keys` wo eigentlich `items` gebraucht wird.
Konstanten werden auf Klassenebene definiert nicht in `__init__`.
Nicht alles muß man an eine Attribut binden. `monat_str` in `get_weeklist` und erst recht nicht `templist`, wobei ich mich hier wieder fragen muß, welcher Tempel oder welche Temperatur, es geht doch um einen Kalender? Der Index einer for-Schleife ist NIE ein Attribut.
`zaehler` für einen String ist falsch.
Mit der richtigen Methode aus Calendar (statt einen String wieder auseinanderzunehmen), sind das wieder nur zwei Zeilen:

Code: Alles auswählen

    def get_weeklist(self, jahr, monat):
        days = list(self.kalender.itermonthdays(jahr, monat))
        days.extend([0] * (42 - len(days)))
        return ['' if d == 0 else str(d) for d in days]
Dass die Parameterliste erst in Spalte 57 macht das Lesen nicht gerade einfach.
onkelhamu
User
Beiträge: 20
Registriert: Freitag 20. Oktober 2017, 21:07

Hey Danke !!!

Ich arbeite das alles mal in Ruhe ab...
"temp" kam von temporär aber Tempel ist auch nicht schlecht :lol:

Und ja, irgendwann hab ich selber den Überblick verloren, aber ich lern ja gerne dazu...
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@onkelhamu: Was IMHO dringend dokumentiert oder gar besser abgeschafft gehört ist das in den `datetime`-Objekten ein Zahlenwert mal als Sekunden und mal als Minuten gespeichert wird der keine Minuten oder Sekunden darstellt. Das ist ein hässlicher unerwarteter Hack.

Die ganzen `parent`-Attribute sind redundant. Tk speichert diese Information bereits selbst als Attribut unter dem Namen `master`. Weder `parent` noch `master` sollte man dazu benutzen auf das übergeordnete Widget zuzugreifen, schon gar nicht über mehrere Ebenen. `master` bringt das ganz gut zum Ausdruck: der Lehrling pfuscht dem Meister oder gar dessen Meister nicht in den inneren Angelegenheiten herum.

Magische Indexwerte sind auch so ein Thema. So ein Todo-Eintrag sollte nicht einfach eine Liste sein wo der Leser an jeder Stelle wissen muss was denn ein Zugriff auch Index 2 oder so bedeuten mag. So ein Eintrag sollte einen eigenen Typ mit Attributen haben.

Die Programmlogik ist auch überhaupt nicht von der GUI getrennt.

Was ist denn die Idee hinter diesem Konstrukt?

Code: Alles auswählen

   def ende(self):
        try:
            self._root().destroy()
        except:
            self._root().destroy()
Auf `_root()` solltest Du ausserdem nicht zugreifen, denn der führende Unterstrich sagt dass das Interna von der Elternklasse ist. Und das ist nicht dokumentiert, also kann man sich auch nicht darauf verlassen dass es diese Methode gibt. An der Stelle möchtest Du wohl `self.winfo_toplevel()` oder besser gar nicht irgendein Widget zerstören, sondern einfach `self.quit()` aufrufen um die GUI-Hauptschleife zu verlassen.

`check_pincode()` das alle halbe Sekunde tief an anderen Stellen der GUI über magische Zahlen gesteuert Dinge tut ist auch sehr umständlich und undurchsichtig.

``tk.E + tk.W + tk.N + tk.S`` ist einfach ``tk.NSEW``. Es gibt alle sinnvollen Kombinationen als fertige Konstante.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
onkelhamu
User
Beiträge: 20
Registriert: Freitag 20. Oktober 2017, 21:07

Weder `parent` noch `master` sollte man dazu benutzen auf das übergeordnete Widget zuzugreifen, schon gar nicht über mehrere Ebenen. `master` bringt das ganz gut zum Ausdruck: der Lehrling pfuscht dem Meister oder gar dessen Meister nicht in den inneren Angelegenheiten herum.
Aber wie kann ich sonst auf Methoden des übergeordnete Widgets zugreifen?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Warum solltest du das tun? Du kannst bei Bedarf notwendige Abhängigkeiten explizit mitgeben. Es via der Widget Hierarchie zu tun, ist ein verlässlicher Weg in die Hölle. Ich spreche da aus Erfahrung.
Antworten