import tkinter as tk from tkinter import ttk #from tkinter import messagebox #import logging #logger = logging.getLogger(__name__) class TreeView(): def __init__(self, frame): # a treeview # hier Anzahl der sichtbaren Zeilen des Baums angeben: self.tree = ttk.Treeview(frame, height=40) # TODO hier anstatt root die Statistik rein schreiben. self.tree.heading('#0', text='root', anchor=tk.W) # add a scrollbar scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=self.tree.yview) self.tree.configure(yscroll=scrollbar.set) scrollbar.grid(row=0, column=1, sticky='ns') self.tree.bind('<>', self.item_selected) def clear(self): self.tree.delete() def create(self, parent_children_mapping, red_ids): # adding data of first column after root pool = set() for parent,children in parent_children_mapping.items(): if parent not in pool: self.tree.insert('', tk.END, text=parent, iid=parent, open=True) pool.add(parent) cn = children # sortiere die Zahlen im Baum immer aufsteigend cn.sort(reverse=True) for child_id in cn: if child_id not in pool: pool.add(child_id) if child_id not in red_ids: rowtags = ('good') else: rowtags = ('missing') self.tree.insert('', tk.END, text=child_id, iid=child_id, tags=rowtags, open=True) #self.tree.move(child_id, parent, 0) # einmal über alles gehen und alle keys an die richtige Stelle schieben for parent,children in parent_children_mapping.items(): for child_id in children: self.tree.move(child_id, parent, 0) # https://www.askpython.com/python-modules/tkinter/tkinter-colors #self.tree.tag_configure('good', background='LawnGreen') self.tree.tag_configure('good', background='white') self.tree.tag_configure('missing', background='red') def item_selected(self, event): """callback if an item in the tree has been selected """ id = self.tree.selection()[0] # for selected_item in self.tree.selection(): # item = self.tree.item(selected_item) # record = item['values'] # messagebox.showinfo(title='Information', message=','.join(record)) def get_handle(self): return self.tree class RightFramePDM(): def __init__(self, frame, controller): self.controller = controller self.frame = frame self.build_gui() def build_gui(self): frame = self.frame rownum = 0 col_left = 0 # pdmkategorie pdmkategorie_label = ttk.Label(frame, text="PDM-Kategorie:" ) pdmkategorie_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.pdm_category = tk.StringVar() pdmkategorie_combo = ttk.Combobox(frame, textvariable=self.pdm_category) pdmkategorie_combo['values'] = ["Baugruppe", "Einzelteil", "Kaufteil", "NichtSivas", "Normteil", "Schweissbaugruppe"] pdmkategorie_combo['state'] = 'readonly' pdmkategorie_combo.bind('<>', self.combo_callbacks) # falls nötig pdmkategorie_combo.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # Neuaufbau neuaufbau_label = ttk.Label(frame, text="Neuaufbau:") neuaufbau_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.neuaufbau = None neuaufbau_checkbutton = ttk.Checkbutton(frame, text='ja', variable=self.neuaufbau, onvalue=True, offvalue=False) neuaufbau_checkbutton.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # Lebenszyklusstatus lebenszyklusstatus_label = ttk.Label(frame, text="Lebenszyklusstatus:") lebenszyklusstatus_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.lebenszyklus_status_neu = tk.StringVar() lebenszyklusstatus_combo = ttk.Combobox(frame, textvariable=self.lebenszyklus_status_neu) lebenszyklusstatus_combo['values'] = ["Serie", "Prototyp"] lebenszyklusstatus_combo['state'] = 'readonly' lebenszyklusstatus_combo.bind('<>', self.combo_callbacks) lebenszyklusstatus_combo.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # aus Halbzeug halbzeug_label = ttk.Label(frame, text="aus Halbzeug:") halbzeug_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.aus_halbzeug_neu = None aushalbzeug_checkbuttonr = ttk.Checkbutton(frame, text='neu', variable=self.aus_halbzeug_neu, onvalue=True, offvalue=False) aushalbzeug_checkbuttonr.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # Zusatzinformationen zusatzinfos_label = ttk.Label(frame, text="Zusatzinformationen:") zusatzinfos_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.zusatzinfos_text = tk.StringVar() zusatzinfos_entry = ttk.Entry(frame, textvariable=self.zusatzinfos_text) zusatzinfos_entry.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 return rownum def get_data(self): return { "pdm_kategorie_neu": self.pdm_category.get(), "neuaufbau": self.neuaufbau, "lebenszyklusstatus_neu": self.lebenszyklus_status_neu.get(), "aus_halbzeug_neu": self.aus_halbzeug_neu, "zusatzinfos_txt_neu": self.zusatzinfos_text.get(), } def to_model(self): data = self.get_data() self.controller.set_data(data) def from_model(self): data = self.controller.get_data() self.aus_halbzeug_neu = data["aus_halbzeug_neu"] self.neuaufbau = data["neuaufbau"] self.zusatzinfos_text.set(data["neuaufbau"]) def combo_callbacks(self, event): """ handle the changed event """ # TODO falls nötig pass class App(): def __init__(self, root, controller): self.root = root self.controller = controller # configure the grid # die erste Spalte mit Baum sollte unbeweglich bleiben bei Vergräßerung des Fensters. # self.root.columnconfigure(0, weight=2) self.root.columnconfigure(1, weight=1) #self.root.geometry('800x800') # Create left and right frames left_frame = ttk.Frame(self.root, width=200, height=800) left_frame.grid(row=0, column=0, padx=10, pady=5) right_frame = ttk.Frame(self.root, width=650, height=800) right_frame.grid(row=0, column=1, padx=10, pady=5) style = ttk.Style(self.root) style.theme_use('classic') current_id = self.controller.get_current_asm_id() self.controller.get_parent_children() self.controller.get_red_ids() self.tv = TreeView(left_frame) self.tv.create(parent_children_mapping, red_ids) gridhdl = self.tv.get_handle() gridhdl.grid(row=0, column=0, sticky=tk.NSEW) self.rf1 = RightFramePDM(right_frame, controller) #self.create_widgets(right_frame) def create_widgets(self, frame): rownum = 0 col_left = 0 # pdmkategorie pdmkategorie_label = ttk.Label(frame, text="PDM-Kategorie:" ) pdmkategorie_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) pdmkategorie_entry = ttk.Entry(frame) pdmkategorie_entry.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # Neuaufbau neuaufbau_label = ttk.Label(frame, text="Neuaufbau:") neuaufbau_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.neuaufbau = None neuaufbau_checkbutton = ttk.Checkbutton(frame, text='ja', command=self.var_changed("neuaufbau"), variable=self.neuaufbau, onvalue=True, offvalue=False) neuaufbau_checkbutton.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 # Lebenszyklusstatus lebenszyklusstatus_label = ttk.Label(frame, text="Lebenszyklusstatus:") lebenszyklusstatus_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) lebenszyklusstatus_entry = ttk.Entry(frame, show="*") lebenszyklusstatus_entry.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 halbzeug_label = ttk.Label(frame, text="Halbzeug:") halbzeug_label.grid(column=col_left, row=rownum, sticky=tk.W, padx=5, pady=5) self.aus_halbzeug_sivas = None aushalbzeug_checkbutton_sivas = ttk.Checkbutton(frame, text='aus Sivas', command=self.var_changed("aus_halbzeug_sivas"), variable=self.aus_halbzeug_sivas, onvalue=True, offvalue=False) aushalbzeug_checkbutton_sivas.grid(column=col_left+1, row=rownum, sticky=tk.W, padx=5, pady=5) self.aus_halbzeug_neu = None aushalbzeug_checkbuttonr = ttk.Checkbutton(frame, text='neu', command=self.var_changed("aus_halbzeug_neu"), variable=self.aus_halbzeug_neu, onvalue=True, offvalue=False) aushalbzeug_checkbuttonr.grid(column=col_left+2, row=rownum, sticky=tk.W, padx=5, pady=5) rownum += 1 def mainloop(self): self.root.mainloop() # class Navbar(tk.Frame): ... # class Toolbar(tk.Frame): ... # class Statusbar(tk.Frame): ... # class Main(tk.Frame): ... # class MainApp(tk.Frame): # def __init__(self, parent, *args, **kwargs): # tk.Frame.__init__(self, parent, *args, **kwargs) # self.statusbar = Statusbar(self, ...) # self.toolbar = Toolbar(self, ...) # self.navbar = Navbar(self, ...) # self.main = Main(self, ...) # self.statusbar.pack(side="bottom", fill="x") # self.toolbar.pack(side="top", fill="x") # self.navbar.pack(side="left", fill="y") # self.main.pack(side="right", fill="both", expand=True) if __name__ == "__main__": """ using the Model-View-Controller (MVC) Pattern - The MODEL is responsible for managing the data of the application. It receives user input from the CONTROLLER - The VIEW renders presentation of the model in a particular format. - The CONTROLLER responds to the user input and performs interactions on the data model objects. The CONTROLLER receives the input, optionally validates it and then passes the input to the model. MODEL <-updates- ^--manipulates-- VIEW CONTROLLER --sees --> -- uses --> USER """ class CadItem(): """ This item contains all data for writing all necessary data to the solid edg cad file """ # diese Daten bilden dann die Impfdaten data_keys = [ "Author", "Teilenummer", "StartRevision", "Bezeichnung1", "Bezeichnung2", "Bezeichnung4", "KategorieNE", "BeschaffungsartNE", "TOS-Gruppe_ERP", "Dispogruppe", "Dispolaufgruppe", "WerkstofftypNE", "WerkstoffNE", "Oberflaechenbehandlung", "Farbe", "KalkulationsartNE", "RuestcodeAusw", "Fertigungsart", "Allgemeintoleranz", "HalbzeugInternAngabe", "Halbzeug", "HalbzeugOhneSaegeliste", "EinheitNE", "FOS-GruppeNE", "Hersteller", "HerstellerTeilenummer", "Serien-Status", "Kantennorm", "Oberflaechennorm", "Massnorm", "Tolerierungsnorm", "TOS-Gruppe", "TOS_Schoenenberger_Produkt", "TOS_Automation", "TOS_Maschinenelement", "TOS_Schoenenberger_Komponenten", "TOS_Pneumatik", "TOS_Konfig", "TOS_ILS", "TOS_MAS", "TOS_Spinnereikomponente", "TOS_Betriebsmittel", "TOS_Geruest", "TOS_FremdTransport", "TOS_MAS_Konfig", "TOS_Schaltschrank", "TOS_Schalt_Einbau", "TOS_Dezentral", "TOS_Automation_Sensorik", "TOS_Kabel", "TOS_Installation", "TOS_Automation_Sonstiges", "TOS_Verbindungselement", "TOS_Lager", "TOS_Kraft_Drehmoment", "TOS_Sicherungselement", "TOS_Bedienungselement", "TOS_ILS_2", "TOS_ILS_Foerderer", "TOS_MAS_Fahrstecke", "TOS_Trolley", "TOS_Trolley_Projekte", "TOS_Trolley_Omniflo", "TOS_Trolley_Spinnerei", "TOS_Trolley_ILS", "Änderungsbeschreibung", "Freigabevermerk", "ZusaetzlicheInformationen"] def __init__(self, asm_id): """ is initalized with its unique id""" self.set_asm_id(asm_id) self.red_ids = {} self.parent_children_mapping = {} self.data = {} self.gui_data = {} def set_asm_id(self, asm_id): self.asm_id = asm_id def get_current_asm_id(self): return self.asm_id def get_current_part_id(self): return self.prt_id def set_part_id(self, prt_id): self.prt_id = prt_id def set_parent_children(self, parent_children_mapping): """ contains all id relations below, data of subassemblies etc. in a dict of the kind parent-children """ self.parent_children_mapping = parent_children_mapping def get_parent_children(self): return self.parent_children_mapping def set_red_ids(self, red_ids): """ these ids are not yet known by the PDM""" self.red_ids = red_ids def get_red_ids(self): return self.red_ids def set_data(self, data:dict): for k,v in data: self.set_data(k,v) def set_data(self, key, val): if key not in self.data_keys: raise Exception("this data can not be set") else: self.data[key] = val def get_data(self, key): return self.data[key] def load(): pass def save(): pass class CadItemRepository: """ container class for all CadItems in the local folder also just managed by the controller """ def __init__(self): self.caditems = [] def add(self, caditem): self.caditems.append(caditem) def get(self, id): for caditem in self.caditems: if caditem.id == id: return caditem return None def get_all(self): return self.caditems def update(self, old_item, new_item): self.delete(old_item.id) self.add(new_item) raise Exception("CadItem not found") def delete(self, id): for p in self.caditems: if p.id == id: self.caditems.remove(p) return raise Exception("CadItem not found") class Controller(): """ Class for manipulating the model and returning data for the view """ def __init__(self, model): self.model = model def get_current_asm_id(self): self.model.get_current_asm_id() def set_current_asm_id(self, asm_id): self.model.set_current_asm_id(asm_id) def set_red_ids(self, red_ids): self.model.set_red_ids(red_ids) def get_red_ids(self): return self.model.get_red_ids() def set_parent_children(self, parent_children_mapping): self.model.set_parent_children(parent_children_mapping) def get_parent_children(self): return self.model.get_parent_children() def set_data(self, key, value): self.model.set_data(key, value) #logging.basicConfig(level=logging.DEBUG) model = CadItem("400102196") controller = Controller(model) controller.set_parent_children(parent_children_mapping) controller.set_red_ids(red_ids) root = tk.Tk() app = App(root, controller) app.mainloop()