bauen der widgets in eigene lib namens gui ausgelagert. Umbau von test_gui in richtung Applikation in CreoMigrateGui

This commit is contained in:
2024-01-17 12:03:58 +01:00
parent b9e69acca9
commit b4eda08674
5 changed files with 392 additions and 23 deletions
+14 -19
View File
@@ -97,6 +97,12 @@ class AllFrames():
def get_controller(self):
return self._controller
def callback(self, key):
controller = self.get_controller()
if controller:
controller.callback(key)
def data_to_model(self, controller):
data = self.get_data()
controller.set_gui_dict(data)
@@ -166,7 +172,7 @@ class RightFrameLabels(AllFrames):
self.teilenummer_text = tk.StringVar()
teilenummer_entry = ttk.Entry(frame, textvariable=self.teilenummer_text)
teilenummer_entry.grid(column=col_left+1, row=self.rownum, sticky=tk.W, padx=5, pady=5)
teilenummer_entry.bind('<<ComboboxSelected>>', self.combo_callback)
teilenummer_entry.bind('<<ComboboxSelected>>', lambda event:self.callback("teilenummer"))
self.rownum += 1
separator2 = ttk.Separator(frame, orient='horizontal')
separator2.grid(column=col_left, columnspan=3, row=self.rownum, sticky=tk.EW, padx=5, pady=5)
@@ -183,11 +189,6 @@ class RightFrameLabels(AllFrames):
if 'teilenummer' in data:
self.teilenummer_text.set(data["teilenummer"])
def combo_callback(self, event):
""" handle the changed event of TK"""
# TODO falls nötig
a = 6
pass
class RightFramePDM(AllFrames):
def __init__(self, frame, nrow=0):
@@ -206,7 +207,7 @@ class RightFramePDM(AllFrames):
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('<<ComboboxSelected>>', self.combo_callback) # falls nötig
pdmkategorie_combo.bind('<<ComboboxSelected>>', lambda event:self.callback('pdm_kategorie_neu'))
pdmkategorie_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
@@ -218,7 +219,7 @@ class RightFramePDM(AllFrames):
neuaufbau_checkbutton = ttk.Checkbutton(frame,
text='ja',
variable=self.neuaufbau,
command=self.checkbox_callback,
command=lambda: self.callback("neuaufbau"),
onvalue=True,
offvalue=False)
neuaufbau_checkbutton.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
@@ -231,7 +232,7 @@ class RightFramePDM(AllFrames):
lebenszyklusstatus_combo = ttk.Combobox(frame, textvariable=self.lebenszyklus_status_neu)
lebenszyklusstatus_combo['values'] = ["Serie", "Prototyp"]
lebenszyklusstatus_combo['state'] = 'readonly'
lebenszyklusstatus_combo.bind('<<ComboboxSelected>>', self.combo_callback)
lebenszyklusstatus_combo.bind('<<ComboboxSelected>>', lambda event:self.callback('lebenszyklus_status_neu'))
lebenszyklusstatus_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
@@ -242,7 +243,7 @@ class RightFramePDM(AllFrames):
aushalbzeug_checkbuttonr = ttk.Checkbutton(frame,
text='neu',
variable=self.aus_halbzeug_neu,
command=self.checkbox_callback,
command=lambda: self.callback("aus_halbzeug_neu"),
onvalue=True,
offvalue=False)
aushalbzeug_checkbuttonr.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
@@ -278,12 +279,6 @@ class RightFramePDM(AllFrames):
if 'zusatzinfos_text_neu' in data:
self.zusatzinfos_text.set(data["zusatzinfos_text_neu"])
def combo_callback(self, event):
pass
def checkbox_callback(self):
pass
class App():
@@ -310,7 +305,7 @@ class App():
self.lf1 = LeftFrameAsm(left_frame, 0)
nrows = self.lf1.get_rows()
self.tv = TreeView(left_frame, nrows)
self.lf2 = TreeView(left_frame, nrows)
self.rf0 = RightFrameLabels(right_frame, 0)
nrows = self.rf0.get_rows()
@@ -323,7 +318,7 @@ class App():
""" methode zum auslesen aller Daten der Oberfläche aus dem Modell
"""
self.lf1.data_from_model()
self.tv.data_from_model()
self.lf2.data_from_model()
self.rf0.data_from_model()
self.rf1.data_from_model()
@@ -333,7 +328,7 @@ class App():
self._controller = controller
self.lf1.set_controller(controller)
self.tv.set_controller(controller)
self.lf2.set_controller(controller)
self.rf0.set_controller(controller)
self.rf1.set_controller(controller)
+21
View File
@@ -9,6 +9,13 @@ class Controller():
def __init__(self, model, view):
self.set_model(model)
self.set_view(view)
self.logic = None
def add_logic(self, logic):
self.logic = logic
def remove_logic(self):
self.logic = None
def set_model(self, model):
self.model = model
@@ -63,5 +70,19 @@ class Controller():
def get_all_gui_data(self):
return self.model.get_all_gui_data()
def callback(self, key):
if self.logic:
self.logic.callback(key)
class GuiLogic():
"""
Class for business logic. implementing the dependencies between different user inputs
"""
def __init__(self):
pass
def callback(self, key):
a = key
if __name__ == "__main__":
pass
+354
View File
@@ -0,0 +1,354 @@
import tkinter as tk
from tkinter import ttk
from controller import Controller
from caditem import CadItem
#from tkinter import messagebox
#import logging
#logger = logging.getLogger(__name__)
class TreeView():
def __init__(self, frame, nrow=0):
# 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)
self.tree.grid(row=nrow, column=0, sticky=tk.NSEW)
# add a scrollbar
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscroll=scrollbar.set)
scrollbar.grid(row=nrow, column=1, sticky='ns')
#self.tree.bind('<<TreeviewSelect>>', self.item_selected) # Einfachklick
self.tree.bind('<Double-Button-1>', self.item_selected) # Doppelklick:
def set_controller(self, controller):
self.controller = controller
def refresh(self, parent_children_mapping, red_ids):
self.clear()
self.create(parent_children_mapping, red_ids)
def clear(self):
for c in self.tree.get_children():
self.tree.delete(c)
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 data_from_model(self):
parent_children_mapping = self.controller.get_parent_children()
red_ids = self.controller.get_red_ids()
self.refresh(parent_children_mapping, red_ids)
def item_selected(self, event):
"""callback of TK if an item in the tree has been selected
"""
cid = self.tree.selection()[0]
# trage die neue ID ins Modell ein
self.controller.set_gui_data('teilenummer', cid)
self.controller.refresh_gui()
class AllFrames():
""" enthält alle gleichen Methoden für die Widgets in der rechte Spalte
"""
def __init__(self, nrow=0):
self.set_start_rwo(nrow)
self._controller = None
def get_rows(self):
return self.rownum
def set_start_rwo(self, nrow):
if nrow < 0:
raise Exception("this row can not be set")
self.rownum = nrow
def set_controller(self, controller):
self._controller = controller
def get_controller(self):
return self._controller
def callback(self, key):
controller = self.get_controller()
if controller:
controller.callback(key)
def data_to_model(self, controller):
data = self.get_data()
controller.set_gui_dict(data)
def data_to_model(self, controller, key, value):
controller.set_gui_data(key, value)
class LeftFrameAsm(AllFrames):
def __init__(self, frame, nrow=0):
AllFrames.__init__(self, nrow)
self.frame = frame
self.build_widgets()
def build_widgets(self):
frame = self.frame
self.rownum = AllFrames.get_rows(self)
col_left = 0
# Baugruppennummer
asm_label = ttk.Label(frame, text="Baugruppennummer:" )
asm_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
self.asm_number = tk.StringVar()
asm_entry = ttk.Entry(frame, textvariable=self.asm_number, width=9)
asm_entry.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
def get_data(self):
return {
"asm_id": self.asm_number.get(),
}
def data_from_model(self):
data = self.get_controller().get_all_gui_data()
if 'asm_id' in data:
self.asm_number.set(data["asm_id"])
class RightFrameLabels(AllFrames):
def __init__(self, frame, nrow=0):
AllFrames.__init__(self, nrow)
self.frame = frame
self.build_widgets()
def build_widgets(self):
frame = self.frame
self.rownum = AllFrames.get_rows(self)
col_left = 0
# Feld, SIVAS-Werte, Überschriebene Werte
feld_label = ttk.Label(frame, text="Feld" )
feld_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5)
Sivas_label = ttk.Label(frame, text="SIVAS-Werte" )
Sivas_label.grid(column=col_left+1, row=self.rownum, sticky=tk.W, padx=5, pady=5)
transwritten_label = ttk.Label(frame, text="Überschriebene Werte" )
transwritten_label.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
feld_label.configure(font=("Helvetica", 16))
Sivas_label.configure(font=("Helvetica",16))
transwritten_label.configure(font=("Helvetica",16))
self.rownum += 1
separator = ttk.Separator(frame, orient='horizontal')
separator.grid(column=col_left, columnspan=3, row=self.rownum, sticky=tk.EW, padx=5, pady=5)
self.rownum += 1
# Teilenummer
teilenummer_label = ttk.Label(frame, text="Teilenummer:")
teilenummer_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.teilenummer_text = tk.StringVar()
teilenummer_entry = ttk.Entry(frame, textvariable=self.teilenummer_text)
teilenummer_entry.grid(column=col_left+1, row=self.rownum, sticky=tk.W, padx=5, pady=5)
teilenummer_entry.bind('<<ComboboxSelected>>', lambda event:self.callback("teilenummer"))
self.rownum += 1
separator2 = ttk.Separator(frame, orient='horizontal')
separator2.grid(column=col_left, columnspan=3, row=self.rownum, sticky=tk.EW, padx=5, pady=5)
self.rownum += 1
def get_data(self):
return {
"teilennummer": self.teilenummer_text.get(),
}
def data_from_model(self):
data = self.get_controller().get_all_gui_data()
if 'teilenummer' in data:
self.teilenummer_text.set(data["teilenummer"])
class RightFramePDM(AllFrames):
def __init__(self, frame, nrow=0):
AllFrames.__init__(self, nrow)
self.frame = frame
self.build_widgets()
def build_widgets(self):
frame = self.frame
self.rownum = AllFrames.get_rows(self)
col_left = 0
# pdmkategorie
pdmkategorie_label = ttk.Label(frame, text="PDM-Kategorie:" )
pdmkategorie_label.grid(column=col_left, row=self.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('<<ComboboxSelected>>', lambda event:self.callback('pdm_kategorie_neu'))
pdmkategorie_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
# Neuaufbau
neuaufbau_label = ttk.Label(frame, text="Neuaufbau:")
neuaufbau_label.grid(column=col_left, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.neuaufbau = None
neuaufbau_checkbutton = ttk.Checkbutton(frame,
text='ja',
variable=self.neuaufbau,
command=lambda: self.callback("neuaufbau"),
onvalue=True,
offvalue=False)
neuaufbau_checkbutton.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
# Lebenszyklusstatus
lebenszyklusstatus_label = ttk.Label(frame, text="Lebenszyklusstatus:")
lebenszyklusstatus_label.grid(column=col_left, row=self.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('<<ComboboxSelected>>', lambda event:self.callback('lebenszyklus_status_neu'))
lebenszyklusstatus_combo.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
# aus Halbzeug
halbzeug_label = ttk.Label(frame, text="aus Halbzeug:")
halbzeug_label.grid(column=col_left, row=self.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,
command=lambda: self.callback("aus_halbzeug_neu"),
onvalue=True,
offvalue=False)
aushalbzeug_checkbuttonr.grid(column=col_left+2, row=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
# Zusatzinformationen
zusatzinfos_label = ttk.Label(frame, text="Zusatzinformationen:")
zusatzinfos_label.grid(column=col_left, row=self.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=self.rownum, sticky=tk.W, padx=5, pady=5)
self.rownum += 1
def get_data(self):
return {
"pdm_kategorie_neu": self.pdm_category.get(),
"neuaufbau": self.neuaufbau,
"lebenszyklus_status_neu": self.lebenszyklus_status_neu.get(),
"aus_halbzeug_neu": self.aus_halbzeug_neu,
"zusatzinfos_txt_neu": self.zusatzinfos_text.get(),
}
def data_from_model(self):
data = self.get_controller().get_all_gui_data()
if 'pdm_kategorie_neu' in data:
self.pdm_category.set(data["pdm_kategorie_neu"])
if 'neuaufbau' in data:
self.neuaufbau = data["neuaufbau"]
if 'lebenszyklus_status_neu' in data:
self.lebenszyklus_status_neu.set(data["lebenszyklus_status_neu"])
if 'aus_halbzeug_neu' in data:
self.aus_halbzeug_neu= data["aus_halbzeug_neu"]
if 'zusatzinfos_text_neu' in data:
self.zusatzinfos_text.set(data["zusatzinfos_text_neu"])
class App():
def __init__(self, root):
"""Standardgui mit Baum zur Anwahl der Teile des Assemblies"""
self.root = root
# 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')
self.lf1 = LeftFrameAsm(left_frame, 0)
nrows = self.lf1.get_rows()
self.lf2 = TreeView(left_frame, nrows)
self.rf0 = RightFrameLabels(right_frame, 0)
nrows = self.rf0.get_rows()
self.rf1 = RightFramePDM(right_frame, nrows)
nrows = self.rf1.get_rows()
#self.rf2 = RightFramePDM(right_frame, nrows)
# TODO usw.
def data_from_model(self):
""" methode zum auslesen aller Daten der Oberfläche aus dem Modell
"""
self.lf1.data_from_model()
self.lf2.data_from_model()
self.rf0.data_from_model()
self.rf1.data_from_model()
def set_controller(self, controller):
# merken des Handels auf den Controller in jedem widget
self._controller = controller
self.lf1.set_controller(controller)
self.lf2.set_controller(controller)
self.rf0.set_controller(controller)
self.rf1.set_controller(controller)
def mainloop(self):
self.root.mainloop()
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.
<CONTROLLER>
<--fills gui -- --manipulates-->
--user input-> <--give model data--
<VIEW> <MODEL>
"""
-3
View File
@@ -273,6 +273,3 @@ class PfadConfig(IniBasedConfig):
"""hole alle möglichen Bezeichner """
return super().get_section_options("Zielpfade")
if __name__ == '__main__':
Kalkulationsart
+3 -1
View File
@@ -1,7 +1,7 @@
import tkinter as tk
from caditem import CadItem
from CreoMigrateGui import App
from controller import Controller
from controller import Controller, GuiLogic
json_str = """
{
@@ -69,6 +69,8 @@ model.from_json(json_str)
root = tk.Tk()
app = App(root)
controller = Controller(model, app)
logic = GuiLogic()
controller.add_logic(logic)
# um ohne Observer pattern auch Rückmeldungen geben zu können
app.set_controller(controller)
model.set_controller(controller)