From d16aefe20fb2281d1bd182f22f4df17247366e05 Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 00:21:12 +0200 Subject: [PATCH 01/11] refactoring --- src/brovski-adress-etiketten-verwaltung.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 3f1feae..937afd6 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -50,8 +50,13 @@ class Application: ) sys.exit() + # frames top_frame = tk.Frame(self.root) top_frame.pack(side=tk.TOP, fill=tk.X) + data_frame = tk.Frame(self.root, bg="teal") + data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + + # top buttons button_width = 8 tk.Button(top_frame, text="Insert", command=self.insert_record, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT) @@ -60,9 +65,7 @@ class Application: tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT) tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT) - data_frame = tk.Frame(self.root, bg="teal") - data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) - + # table content scrollbar = ttk.Scrollbar(data_frame, orient=tk.VERTICAL) self.table = ttk.Treeview(data_frame, yscrollcommand=scrollbar.set, columns=("0", "1", "2", "3", "4"), show="headings") From aec7770e7476829f2af7684c926a4c9525efafab Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 00:24:30 +0200 Subject: [PATCH 02/11] added statusbar with stringvar --- src/brovski-adress-etiketten-verwaltung.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 937afd6..6c5c086 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -42,6 +42,9 @@ class Application: self.json_file = os.path.join(self.json_path, self.json_file_name) self.csv_file = os.path.join(self.csv_path, self.csv_file_name) + # status bar content + self.statusbar = tk.StringVar() + # leave application if settings are bad if not self.config_good: show_error(message_title="Fehler Konfiguration", @@ -55,6 +58,8 @@ class Application: top_frame.pack(side=tk.TOP, fill=tk.X) data_frame = tk.Frame(self.root, bg="teal") data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + bottom_frame = tk.Frame(self.root) + bottom_frame.pack(side=tk.BOTTOM, fill=tk.X) # top buttons button_width = 8 @@ -83,6 +88,9 @@ class Application: self.table.bind("", self.mouse_click_double) self.table.bind("", self.mouse_click_double) + # bottom status bar + tk.Label(bottom_frame, textvariable=self.statusbar).pack(side=tk.LEFT) + self._load_json_file() self.root.mainloop() From 3fd0147158d8720a849b34f482d32c06f98dadb5 Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 00:33:10 +0200 Subject: [PATCH 03/11] implemented status bar covering #8 --- src/brovski-adress-etiketten-verwaltung.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 6c5c086..4d979cc 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -44,6 +44,8 @@ class Application: # status bar content self.statusbar = tk.StringVar() + self.length_address_list = None + self.length_address_list_active = None # leave application if settings are bad if not self.config_good: @@ -269,6 +271,7 @@ class Application: self.delete_all_table_items() for index, item in enumerate(self.address_list): self.table.insert('', 'end', iid=index, values=item) + self.update_status_bar() def export_table_to_address_list(self): self.address_list.clear() @@ -276,6 +279,7 @@ class Application: self.address_list.append([]) for value in self.table.item(child)['values']: self.address_list[-1].append(value) + self.update_status_bar() def delete_all_table_items(self): for item in self.table.get_children(): @@ -294,6 +298,18 @@ class Application: window.wait_visibility() window.grab_set() + def update_status_bar(self): + self._count_address_records() + self.statusbar.set(f"Adressen: {self.length_address_list} | Aktive Adressen: {self.length_address_list_active}") + + def _count_address_records(self): + self.length_address_list = len(self.address_list) + count = 0 + for address in self.address_list: + if address[0] == "x": + count += 1 + self.length_address_list_active = count + From ad66988e09443afa153a01fa0e365dc8fc3be2a5 Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 11:54:32 +0200 Subject: [PATCH 04/11] sorting of columns was not nice, should be better now --- src/brovski-adress-etiketten-verwaltung.py | 37 ++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 4d979cc..a3a2e10 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -32,6 +32,7 @@ class Application: self.address_list = [] self.current_record: int | None = None self.sort_order = False + self.last_sort_field = "#3" # init paths to json and csv file self.json_file_name = "brovski-adress-etiketten-verwaltung.json" @@ -95,6 +96,8 @@ class Application: self._load_json_file() + self.first_sort_after_start() + self.root.mainloop() def load_config(self): @@ -197,25 +200,17 @@ class Application: def click_on_header(self, event): column = self.table.identify_column(event.x) - match column: - case "#1": - self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order) - self.populate_table() - case "#2": - self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order) - self.populate_table() - case "#3": - self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order) - self.populate_table() - case "#4": - self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order) - self.populate_table() - case "#5": - self.address_list.sort(key=lambda x: x[int(column[-1]) - 1], reverse=self.sort_order) - self.populate_table() - case _: - print(column) - self.sort_order = not self.sort_order + if self.last_sort_field == column: + self.sort_order = False if self.sort_order else True + else: + self.sort_order = False + self.last_sort_field = column + self.address_list.sort(key=lambda x: (x[int(column[-1]) - 1]), reverse=self.sort_order) + + # special case company sort + if column == "#2": + self.address_list.sort(key=lambda x: (x[1], x[2]), reverse=self.sort_order) + self.populate_table() def click_on_cell(self): self.current_record = self.table.focus() @@ -310,7 +305,9 @@ class Application: count += 1 self.length_address_list_active = count - + def first_sort_after_start(self): + self.address_list.sort(key=lambda x: (x[1], x[2])) + self.populate_table() if __name__ == '__main__': From bbdbaadb9207cf17507dddf704c16ee040a15a9c Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 12:22:25 +0200 Subject: [PATCH 05/11] filtering inactive records --- src/brovski-adress-etiketten-verwaltung.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index a3a2e10..3754d98 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -33,6 +33,7 @@ class Application: self.current_record: int | None = None self.sort_order = False self.last_sort_field = "#3" + self.filter_active = tk.BooleanVar(value=False) # init paths to json and csv file self.json_file_name = "brovski-adress-etiketten-verwaltung.json" @@ -70,6 +71,7 @@ class Application: tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Toggle Aktiv", command=self.toggle_active, width=button_width).pack(side=tk.LEFT) + tk.Checkbutton(top_frame, text="Filter aktive", variable=self.filter_active, command=self.populate_table).pack(side=tk.LEFT) tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT) tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT) @@ -265,6 +267,9 @@ class Application: def populate_table(self): self.delete_all_table_items() for index, item in enumerate(self.address_list): + # skip inactive records if filter is true + if self.filter_active.get() and item[0] != "x": + continue self.table.insert('', 'end', iid=index, values=item) self.update_status_bar() From dc27197129c7857dbfeb7edf05852f171366102b Mon Sep 17 00:00:00 2001 From: sroth Date: Sun, 27 Apr 2025 22:56:14 +0200 Subject: [PATCH 06/11] handles data storage --- src/connector.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/connector.py diff --git a/src/connector.py b/src/connector.py new file mode 100644 index 0000000..2a9352a --- /dev/null +++ b/src/connector.py @@ -0,0 +1,77 @@ +import json +import os +from abc import ABC, abstractmethod + +import config + + +class Connector(ABC): + def __init__(self): + pass + + @abstractmethod + def get_all(self) -> list: + pass + + @abstractmethod + def get_by_id(self, record_id: int) -> dict: + pass + + @abstractmethod + def delete_by_id(self, record_id: int): + pass + + @abstractmethod + def update_record(self, updated_record: dict): + pass + + @abstractmethod + def create_new(self, values: dict) -> int: + pass + + +class JSONConnector(Connector): + def __init__(self): + super().__init__() + self.config = config.Config() + self.json_path = self.config.get("json", "path") + self.json_file = os.path.join(self.json_path, "brovski-adress-etiketten-verwaltung.json") + + def get_all(self) -> list: + with open(self.json_file, "r") as f: + return json.load(f) + + def get_by_id(self, record_id: int) -> dict: + data = self.get_all() + for record in data: + if record["record_id"] == record_id: + return record + + def delete_by_id(self, record_id: int): + data = self.get_all() + for idx, record in enumerate(data): + if record["record_id"] == record_id: + del data[idx] + self._write_to_file(data) + + def update_record(self, new_record: dict): + data = self.get_all() + for idx, record in enumerate(data): + if record["record_id"] == new_record["record_id"]: + data[idx] = new_record + self._write_to_file(data) + + def create_new(self, record: dict) -> int: + data = self.get_all() + if len(data) == 0: + next_id = 0 + else: + next_id = max(data, key=lambda x: x["record_id"])["record_id"] + 1 + record["record_id"] = next_id + data.append(record) + self._write_to_file(data) + return next_id + + def _write_to_file(self, data): + with open(self.json_file, "w") as f: + json.dump(data, f, indent=4) From 9ea44933a618af23555882e94c779b52df156996 Mon Sep 17 00:00:00 2001 From: sroth Date: Mon, 28 Apr 2025 00:18:22 +0200 Subject: [PATCH 07/11] recreated json file handling as connector model, fixing #10 and introducing #8 and #7 --- src/brovski-adress-etiketten-verwaltung.py | 172 ++++++++++----------- src/connector.py | 5 + src/windows.py | 34 ++-- 3 files changed, 113 insertions(+), 98 deletions(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 3754d98..e25a539 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -8,6 +8,7 @@ from tkinter import ttk import json from config import Config +from connector import JSONConnector from windows import SettingsWindow, EditRecord, Window, show_error @@ -35,13 +36,14 @@ class Application: self.last_sort_field = "#3" self.filter_active = tk.BooleanVar(value=False) + # model connector + self.model = JSONConnector() + # init paths to json and csv file self.json_file_name = "brovski-adress-etiketten-verwaltung.json" self.csv_file_name = "brovski-adress-etiketten.csv" - self.json_path = "" self.csv_path = "" self.load_config() - self.json_file = os.path.join(self.json_path, self.json_file_name) self.csv_file = os.path.join(self.csv_path, self.csv_file_name) # status bar content @@ -71,7 +73,8 @@ class Application: tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Toggle Aktiv", command=self.toggle_active, width=button_width).pack(side=tk.LEFT) - tk.Checkbutton(top_frame, text="Filter aktive", variable=self.filter_active, command=self.populate_table).pack(side=tk.LEFT) + tk.Checkbutton(top_frame, text="Filter aktive", variable=self.filter_active, command=self.populate_table).pack( + side=tk.LEFT) tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT) tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT) @@ -96,17 +99,14 @@ class Application: # bottom status bar tk.Label(bottom_frame, textvariable=self.statusbar).pack(side=tk.LEFT) - self._load_json_file() - self.first_sort_after_start() self.root.mainloop() def load_config(self): try: - self.json_path = self.config.get("json", "path") self.csv_path = self.config.get("csv", "path") - if self.json_path == "" or self.csv_path == "": + if self.csv_path == "": raise ValueError("Empty JSON or CSV path") self.config_good = True except NoSectionError: @@ -132,55 +132,56 @@ class Application: settings.wait_window() def insert_record(self): - values = [ - "x", - "Firma", - "Name", - "Strasse", - "Plz/Ort", - ] - last_iid = self.table.get_children()[-1] - next_iid = int(last_iid) + 1 - self.table.insert('', 'end', iid=next_iid, values=values) - self._save_json_file() + values = { + "aktiv": "x", + "firma": "Firma", + "name": "Name", + "strasse": "Strasse", + "plzort": "Plz/Ort" + } + self.model.create_new(values) + self.populate_table() self.deselect_tree() def delete_record(self): if self.current_record is None: return + if len(self.table.selection()) > 1: + show_error(message_title="Mehrere Adressen ausgewählt", + message="Es können nur einzelne Adressen gelöscht werden", + parent=self.root) + return + if messagebox.askyesno( "Eintrag löschen?", "Willst du diesen Eintrag wirklich löschen?\nDies kann nicht rückgängig gemacht werden"): - self.table.delete(self.current_record) + print(type(self.current_record)) + self.model.delete_by_id(self.current_record) self.deselect_tree() - self._save_json_file() + self.populate_table() - def update_record(self, data: list): + def update_record(self, record: dict): if self.current_record is None: return - values = {} - for idx, value in enumerate(data): - values[str(idx)] = value.get() - - for key, value in values.items(): - self.table.set(self.current_record, key, value) - - self._save_json_file() + self.model.update_record(record) + self.populate_table() def toggle_active(self): - items = self.table.selection() - if len(items) == 0: + selection = self.table.selection() + if len(selection) == 0: return - for record_id in items: - values = self.table.item(record_id, "values") - active = values[0] - new_active = "x" if active == "" else "" - self.table.set(record_id, "0", new_active) + item_list = [int(x) for x in selection] + for address in self.address_list: + record_id = address.get("record_id") + if record_id in item_list: + address["aktiv"] = "x" if address["aktiv"] == "" else "" + self.model.update_record(address) + self.table.set(record_id, "0", address["aktiv"]) - self._save_json_file() + self.update_status_bar() def deselect_tree(self): while len(self.table.selection()) > 0: @@ -188,7 +189,11 @@ class Application: self.current_record = None def mouse_click(self, event): - self.current_record = self.table.focus() + id_string = self.table.focus() + if id_string is not None and id_string != "": + self.current_record = int(self.table.focus()) + else: + self.current_record = None region = self.table.identify("region", event.x, event.y) match region: case "heading": @@ -202,75 +207,70 @@ class Application: def click_on_header(self, event): column = self.table.identify_column(event.x) + print(f"col: {column}") if self.last_sort_field == column: self.sort_order = False if self.sort_order else True else: self.sort_order = False self.last_sort_field = column - self.address_list.sort(key=lambda x: (x[int(column[-1]) - 1]), reverse=self.sort_order) - # special case company sort - if column == "#2": - self.address_list.sort(key=lambda x: (x[1], x[2]), reverse=self.sort_order) - self.populate_table() + match column: + case "#1": + field = "aktiv" + case "#2": + field = "firma" + case "#3": + field = "name" + case "#4": + field = "strasse" + case "#5": + field = "plzort" + case _: + field = "name" + + self.address_list = self.model.get_all_sorted_by(field, self.sort_order) + self.populate_table(reload=False) def click_on_cell(self): - self.current_record = self.table.focus() - values = self.table.item(self.current_record, "values") - self.open_window_edit_records(values) + self.current_record = int(self.table.focus()) + self.open_window_edit_records(self.current_record) - def _load_json_file(self): - try: - with open(self.json_file, "r", encoding="utf-8") as f: - self.address_list = json.load(f) - self.address_list.sort(key=lambda x: (x[0], x[1])) - except FileNotFoundError: - show_error( - message_title="Datei nicht gefunden", - message=f"{self.json_file_name} nicht gefunden, erstelle leere Datei unter {self.json_path}", - parent=self.root - ) - self.address_list = [["", "firma", "name", "adresse", "plz/ort"]] - with open(self.json_file, "w", encoding="utf-8") as f: - json.dump(self.address_list, f) - self.populate_table() - - def _save_json_file(self): - self.export_table_to_address_list() - try: - with open(self.json_file, "w", encoding="utf-8") as f: - json.dump(self.address_list, f, indent=4, sort_keys=True) - except FileNotFoundError: - show_error( - message_title="Unexpected Error: File not found?!", - message=f"{self.json_file_name} not found", - parent=self.root - ) def export_csv(self): try: with open(self.csv_file, "w", encoding="utf-8") as f: writer = csv.writer(f, delimiter=",") for address in self.address_list: - if address[0] != "x": + if address["aktiv"] != "x": continue - if address[1] == "": - writer.writerow(address[2:]) - else: - writer.writerow(address[1:]) + line = [] + if address["firma"] != "": + line.append(address["firma"]) + line.append(address["name"]) + line.append(address["strasse"]) + line.append(address["plzort"]) + writer.writerow(line) except FileNotFoundError: show_error(message_title="Unexpected error", message=f"Could not write file {self.csv_file}", parent=self.root ) - def populate_table(self): + def populate_table(self, reload=True): + if reload: + self.address_list = self.model.get_all() + if len(self.address_list) == 0: + return self.delete_all_table_items() - for index, item in enumerate(self.address_list): + for address in self.address_list: # skip inactive records if filter is true - if self.filter_active.get() and item[0] != "x": + if self.filter_active.get() and address["aktiv"] != "x": continue - self.table.insert('', 'end', iid=index, values=item) + print(address) + self.table.insert('', 'end', iid=address["record_id"], + values=(address["aktiv"], address["firma"], address["name"], address["strasse"], + address["plzort"]) + ) self.update_status_bar() def export_table_to_address_list(self): @@ -292,8 +292,8 @@ class Application: window.grab_set() return window - def open_window_edit_records(self, data): - window = EditRecord(self, self.root, data) + def open_window_edit_records(self, record_id: int): + window = EditRecord(self, self.root, record_id) window.wm_transient(self.root) window.wait_visibility() window.grab_set() @@ -306,12 +306,12 @@ class Application: self.length_address_list = len(self.address_list) count = 0 for address in self.address_list: - if address[0] == "x": + if address["aktiv"] == "x": count += 1 self.length_address_list_active = count def first_sort_after_start(self): - self.address_list.sort(key=lambda x: (x[1], x[2])) + self.address_list.sort(key=lambda x: (x["firma"], x["name"])) self.populate_table() diff --git a/src/connector.py b/src/connector.py index 2a9352a..7d9ae24 100644 --- a/src/connector.py +++ b/src/connector.py @@ -41,6 +41,11 @@ class JSONConnector(Connector): with open(self.json_file, "r") as f: return json.load(f) + def get_all_sorted_by(self, field: str, reverse=False) -> list: + with open(self.json_file, "r") as f: + data = json.load(f) + return sorted(data, key=lambda k: k[field], reverse=reverse) + def get_by_id(self, record_id: int) -> dict: data = self.get_all() for record in data: diff --git a/src/windows.py b/src/windows.py index b244f06..77e980a 100644 --- a/src/windows.py +++ b/src/windows.py @@ -3,6 +3,7 @@ from configparser import NoSectionError, NoOptionError from tkinter import font, filedialog, messagebox from config import Config +from connector import JSONConnector def show_error(message_title: str, message: str, parent: tk.Tk | tk.Toplevel): @@ -25,27 +26,28 @@ class Window(tk.Toplevel): self._destroy_window() def _destroy_window(self): + self.parent.populate_table() self.root.update() self.destroy() class EditRecord(Window): - def __init__(self, parent, root: tk.Tk, data: tuple): + def __init__(self, parent, root: tk.Tk, record_id: int): super().__init__(parent, root) self.bind("", self._update) - self.data = data + self.model = JSONConnector() + + record = self.model.get_by_id(record_id) + button_width = 8 self.title("Adresse bearbeiten") - self.aktiv = tk.StringVar() - self.firma = tk.StringVar() - self.name = tk.StringVar() - self.strasse = tk.StringVar() - self.plz_ort = tk.StringVar() - - self.field_list = [self.aktiv, self.firma, self.name, self.strasse, self.plz_ort] - for argument, field in zip(self.data, self.field_list): - field.set(argument) + self.record_id = tk.IntVar(value=record_id) + self.aktiv = tk.StringVar(value=record.get("aktiv")) + self.firma = tk.StringVar(value=record.get("firma")) + self.name = tk.StringVar(value=record.get("name")) + self.strasse = tk.StringVar(value=record.get("strasse")) + self.plz_ort = tk.StringVar(value=record.get("plzort")) edit_frame = tk.Frame(self) edit_frame.pack(side=tk.TOP, fill=tk.X, pady=20, padx=20) @@ -71,7 +73,15 @@ class EditRecord(Window): tk.Button(button_frame, text="Abbrechen", command=self.close_window, width=button_width).pack(side=tk.LEFT) def _update(self, event = None): - self.parent.update_record(self.field_list) + new_record = { + "record_id": self.record_id.get(), + "aktiv": self.aktiv.get(), + "firma": self.firma.get(), + "name": self.name.get(), + "strasse": self.strasse.get(), + "plzort": self.plz_ort.get(), + } + self.model.update_record(new_record) self.close_window() From 95ed06df458b7361b077df4766459bcce3ef61fb Mon Sep 17 00:00:00 2001 From: sroth Date: Mon, 28 Apr 2025 00:23:19 +0200 Subject: [PATCH 08/11] typo in label --- src/brovski-adress-etiketten-verwaltung.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index e25a539..f4dccec 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -73,7 +73,7 @@ class Application: tk.Button(top_frame, text="Delete", command=self.delete_record, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Export CSV", command=self.export_csv, width=button_width).pack(side=tk.LEFT) tk.Button(top_frame, text="Toggle Aktiv", command=self.toggle_active, width=button_width).pack(side=tk.LEFT) - tk.Checkbutton(top_frame, text="Filter aktive", variable=self.filter_active, command=self.populate_table).pack( + tk.Checkbutton(top_frame, text="Filter aktiv", variable=self.filter_active, command=self.populate_table).pack( side=tk.LEFT) tk.Button(top_frame, text="Quit", command=self.on_close, width=button_width).pack(side=tk.RIGHT) tk.Button(top_frame, text="Settings", command=self.show_settings, width=button_width).pack(side=tk.RIGHT) From ec130fcee9ef3a0500d610abc5cad098cf0ac15c Mon Sep 17 00:00:00 2001 From: sroth Date: Mon, 28 Apr 2025 00:24:00 +0200 Subject: [PATCH 09/11] removed all "debug" print commands --- src/brovski-adress-etiketten-verwaltung.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index f4dccec..808c22c 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -156,7 +156,6 @@ class Application: if messagebox.askyesno( "Eintrag löschen?", "Willst du diesen Eintrag wirklich löschen?\nDies kann nicht rückgängig gemacht werden"): - print(type(self.current_record)) self.model.delete_by_id(self.current_record) self.deselect_tree() @@ -207,7 +206,6 @@ class Application: def click_on_header(self, event): column = self.table.identify_column(event.x) - print(f"col: {column}") if self.last_sort_field == column: self.sort_order = False if self.sort_order else True else: @@ -266,7 +264,6 @@ class Application: # skip inactive records if filter is true if self.filter_active.get() and address["aktiv"] != "x": continue - print(address) self.table.insert('', 'end', iid=address["record_id"], values=(address["aktiv"], address["firma"], address["name"], address["strasse"], address["plzort"]) From 96995f1e80e72b7068531ee7a7298f379fccc4b4 Mon Sep 17 00:00:00 2001 From: sroth Date: Wed, 30 Apr 2025 19:58:16 +0200 Subject: [PATCH 10/11] fixed keybindings, refactoring and table focus --- src/brovski-adress-etiketten-verwaltung.py | 26 +++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index 808c22c..ac07ace 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -5,11 +5,10 @@ import tkinter as tk from configparser import NoSectionError, NoOptionError from tkinter import messagebox from tkinter import ttk -import json from config import Config from connector import JSONConnector -from windows import SettingsWindow, EditRecord, Window, show_error +from windows import SettingsWindow, EditRecord, show_error class Application: @@ -93,8 +92,10 @@ class Application: scrollbar.pack(side=tk.LEFT, fill=tk.Y) self.table.bind("", self.mouse_click) - self.table.bind("", self.mouse_click_double) + self.table.bind("", self.enter_button) self.table.bind("", self.mouse_click_double) + self.root.bind("", self.focus_table) + self.root.bind("", self.focus_table) # bottom status bar tk.Label(bottom_frame, textvariable=self.statusbar).pack(side=tk.LEFT) @@ -202,7 +203,10 @@ class Application: region = self.table.identify("region", event.x, event.y) match region: case "cell": - self.click_on_cell() + self.edit_selected_record() + + def enter_button(self, event): + self.edit_selected_record() def click_on_header(self, event): column = self.table.identify_column(event.x) @@ -229,7 +233,9 @@ class Application: self.address_list = self.model.get_all_sorted_by(field, self.sort_order) self.populate_table(reload=False) - def click_on_cell(self): + def edit_selected_record(self): + if self.table.focus() is None or self.table.focus() == "": + return self.current_record = int(self.table.focus()) self.open_window_edit_records(self.current_record) @@ -311,6 +317,16 @@ class Application: self.address_list.sort(key=lambda x: (x["firma"], x["name"])) self.populate_table() + def focus_table(self, event): + first = self.table.get_children()[0] + last = self.table.get_children()[-1] + goto = last if event.keysym == "Up" else first + if self.table.focus() == "": + self.table.selection_set(goto) + self.table.focus(goto) + self.table.see(goto) + self.table.focus_force() + if __name__ == '__main__': Application() From 0ae2c7e559bbf3252162ac216f105b6d880e6913 Mon Sep 17 00:00:00 2001 From: sroth Date: Wed, 30 Apr 2025 20:00:20 +0200 Subject: [PATCH 11/11] new version 0.7a, and update json filename for new format --- deb-package/brovski-adressetiketten/DEBIAN/control | 2 +- src/brovski-adress-etiketten-verwaltung.py | 2 +- src/connector.py | 2 +- version.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deb-package/brovski-adressetiketten/DEBIAN/control b/deb-package/brovski-adressetiketten/DEBIAN/control index 2466ddd..0137034 100644 --- a/deb-package/brovski-adressetiketten/DEBIAN/control +++ b/deb-package/brovski-adressetiketten/DEBIAN/control @@ -1,5 +1,5 @@ Package: brovski-adressetiketten -Version: 0.6a +Version: 0.7a Maintainer: Ovski Architecture: all Description: manage csv files for glables address labels diff --git a/src/brovski-adress-etiketten-verwaltung.py b/src/brovski-adress-etiketten-verwaltung.py index ac07ace..71e1423 100644 --- a/src/brovski-adress-etiketten-verwaltung.py +++ b/src/brovski-adress-etiketten-verwaltung.py @@ -18,7 +18,7 @@ class Application: y_offset = 200 width = 1050 height = 700 - VERSION = '0.6a' + VERSION = '0.7a' title = f"Brovski Adress-Etiketten Verwaltung {VERSION}" self.root = tk.Tk(className="BrovskiAdressEtiketten") diff --git a/src/connector.py b/src/connector.py index 7d9ae24..436ea86 100644 --- a/src/connector.py +++ b/src/connector.py @@ -35,7 +35,7 @@ class JSONConnector(Connector): super().__init__() self.config = config.Config() self.json_path = self.config.get("json", "path") - self.json_file = os.path.join(self.json_path, "brovski-adress-etiketten-verwaltung.json") + self.json_file = os.path.join(self.json_path, "brovski-adress-etiketten-verwaltung-v7.json") def get_all(self) -> list: with open(self.json_file, "r") as f: diff --git a/version.txt b/version.txt index f99616b..d7e056a 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.6a +0.7a