35 Commits

Author SHA1 Message Date
bcb4bb90d5 moved compile script out of source and optimized it 2025-04-22 12:23:21 +02:00
00a1e00c86 desktop file is already in deb package, removed from source 2025-04-22 12:14:42 +02:00
3d3a833d4f moved labes file out of source 2025-04-22 12:13:47 +02:00
70b5fe5ef7 not using the icon here 2025-04-22 12:08:44 +02:00
325f9214c7 version # 2025-04-22 12:06:47 +02:00
b50e0df01b no need to add deb package to git 2025-04-22 01:37:44 +02:00
8c5cb753cf creating single file binary and deb package 2025-04-22 01:37:17 +02:00
cca474b4c8 don't upload binaries 2025-04-22 01:36:45 +02:00
bd1564540d clean up 2025-04-22 01:36:16 +02:00
ca14ecea76 moved config.ini into ~/.config/brovski-adress-etiketten 2025-04-22 01:27:53 +02:00
748519f45f files for gnome desktop install via apt deb package 2025-04-22 01:20:16 +02:00
1ee64f5d95 ignore binaries for deb package 2025-04-22 01:19:32 +02:00
32eb0ee6c1 Merge pull request 'rearange_insert-edit_dialog' (#4) from rearange_insert-edit_dialog into main
Reviewed-on: #4
2025-04-20 23:41:28 +02:00
26e1d1f2da fixed enter key not working, after inserting a new record 2025-04-20 23:39:08 +02:00
dc86d8ce01 refactored entry mask to own window, split windows and config from main app file 2025-04-20 23:34:41 +02:00
7ef1fca873 WIP: moved the widgets 2025-04-19 14:23:46 +02:00
e3d8b94bd6 update compile script for removed config.ini 2025-04-19 14:15:38 +02:00
889ec19c7a clean up insert function 2025-04-19 14:14:43 +02:00
d9ae7153a5 updated config.ini path 2025-04-19 14:06:38 +02:00
043cb0a626 removed config file, will be auto created 2025-04-19 14:06:22 +02:00
d9fee6dc57 bugfix: app would start even with empty config params 2025-04-19 14:03:52 +02:00
aae762ba28 removed unneeded csv file 2025-04-19 14:01:49 +02:00
72b4614d4d refactored child windows into Window class 2025-04-19 14:01:33 +02:00
bb31a52934 instead of hiding main window, force settings on top 2025-04-19 13:38:20 +02:00
5e071503d0 refactored error message dialog 2025-04-19 13:31:10 +02:00
2f30baeed2 bugfix can't cancel settings dialog if no path defined 2025-04-19 13:11:38 +02:00
d23408ab47 bugfix can't cancel dir find in config 2025-04-19 13:08:38 +02:00
e3c7daddd3 decreased initial window height 2025-04-19 12:59:17 +02:00
974fce8a26 removes tree selection after deleting a record 2025-04-19 12:58:34 +02:00
9c6669f349 bugfix #1 2025-04-19 12:54:32 +02:00
139b951087 refactoring 2025-04-19 12:53:03 +02:00
05599acd56 refactoring 2025-04-19 12:46:30 +02:00
7cf3f6cc1f multi line toggle active 2025-04-18 12:27:08 +02:00
62e8bb728b adds inc and dec sort for table header 2025-04-18 12:13:51 +02:00
5f568d3850 vertical scrollbar for table 2025-04-18 12:03:20 +02:00
12 changed files with 339 additions and 221 deletions

4
.gitignore vendored
View File

@@ -166,3 +166,7 @@ cython_debug/
/.idea/modules.xml
/.idea/inspectionProfiles/profiles_settings.xml
/.idea/inspectionProfiles/Project_Default.xml
/deb-package/brovski-adressetiketten/usr/local/bin/brovski-adress-etiketten-verwaltung
/deb-package/brovski-adressetiketten/usr/local/bin/brovski-adressetiketten
/brovski-adressetiketten.deb

10
compile.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/env bash
if [ $VIRTUAL_ENV=="" ]
then
source venv/bin/activate
fi
pyinstaller --clean --onefile src/brovski-adress-etiketten-verwaltung.py
cp dist/brovski-adress-etiketten-verwaltung deb-package/brovski-adressetiketten/usr/local/bin/brovski-adressetiketten
dpkg-deb --build deb-package/brovski-adressetiketten
mv deb-package/brovski-adressetiketten.deb ./

View File

@@ -0,0 +1,5 @@
Package: brovski-adressetiketten
Version: 0.4a
Maintainer: Ovski
Architecture: all
Description: manage csv files for glables address labels

View File

@@ -1,8 +1,8 @@
[Desktop Entry]
Name=Brovski Adress Etiketten
GenericName=Brovski Adress Etiketten
Icon=/home/sroth/app/brovski-adress-etiketten-verwaltung/icon.svg
Exec=/home/sroth/app/brovski-adress-etiketten-verwaltung/brovski-adress-etiketten-verwaltung
Icon=/usr/share/icons/hicolor/512x512/apps/brovski-adressetiketten.svg
Exec=/usr/local/bin/brovski-adressetiketten
Terminal=false
Type=Application
Categories=Utility

View File

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

View File

@@ -1,3 +0,0 @@
alpha muster-firma,otti,tottistrasse,1234 daheim
c3000,erich roth,zentralstrasse 120,5430 wettingen
muster-firma,Peter Muster,Peter-Musterstrasse 1,1234 Ort
1 alpha muster-firma otti tottistrasse 1234 daheim
2 c3000 erich roth zentralstrasse 120 5430 wettingen
3 muster-firma Peter Muster Peter-Musterstrasse 1 1234 Ort

View File

@@ -2,145 +2,35 @@ import csv
import os
import sys
import tkinter as tk
from tkinter import font, filedialog
from configparser import NoSectionError, NoOptionError
from configparser import ConfigParser
from tkinter import messagebox
from tkinter import ttk
import json
class SettingsWindow(tk.Toplevel):
def __init__(self, root: tk.Tk):
super().__init__()
self.root = root
self.protocol("WM_DELETE_WINDOW", self.close_window)
self.geometry(f"500x330+{self.root.winfo_x()+20}+{self.root.winfo_y()+20}")
self.config = Config()
self.json_file = tk.StringVar()
self.csv_file = tk.StringVar()
title = font.Font(family='Ubuntu Mono', size=20, weight=font.BOLD)
tk.Label(self, text="Einstellungen", font=title).pack(pady=20)
path_frame = tk.Frame(self)
path_frame.pack(pady=(10, 40))
tk.Label(path_frame, text="Datenpfad JSON Datei").grid(row=0, column=0)
tk.Entry(path_frame, textvariable=self.json_file, width=50).grid(row=1, column=0)
tk.Button(path_frame, text="Pfad", command=self.set_json_path).grid(row=1, column=1)
tk.Label(path_frame, text="Datenpfad CSV Export Datei").grid(row=2, column=0)
tk.Entry(path_frame, textvariable=self.csv_file, width=50).grid(row=3, column=0)
tk.Button(path_frame, text="Pfad", command=self.set_csv_path).grid(row=3, column=1)
bottom_frame = tk.Frame(self)
bottom_frame.pack()
tk.Button(bottom_frame, text="Ok", command=self.ok).pack(side=tk.LEFT)
tk.Button(bottom_frame, text="Abbrechen", command=self.cancel).pack(side=tk.LEFT)
self.load_config()
def set_json_path(self):
self.json_file.set(filedialog.askdirectory(initialdir="~/", title="Datenpfad JSON Datei"))
def set_csv_path(self):
self.csv_file.set(filedialog.askdirectory(initialdir="~/", title="Datenpfad CSV Datei"))
def load_config(self):
try:
self.json_file.set(self.config.get("json", "path"))
except NoSectionError:
self.config.add_section("json")
self.config.set("json", "path", "")
except NoOptionError:
self.config.set("json", "path", "")
try:
self.csv_file.set(self.config.get("csv", "path"))
except NoSectionError:
self.config.add_section("csv")
self.config.set("csv", "path", "")
except NoOptionError:
self.config.set("csv", "path", "")
def ok(self):
self.config.set("json", "path", self.json_file.get())
self.config.set("csv", "path", self.csv_file.get())
self.close_window()
def cancel(self):
self.close_window()
def close_window(self):
if self.json_file.get() == "" or self.csv_file.get() == "":
messagebox.showwarning(title="Fehlerhafte Konfiguration", message="Pfad für JSON oder CSV Datei fehlt")
return
self.destroy_window()
def destroy_window(self):
self.root.update()
self.root.deiconify()
self.destroy()
class Config:
parser: ConfigParser
def __init__(self):
"""
Config parser reading config.ini
Attributes:
self.parser: ConfigParser holding list of sections and options
self.__filename: Path and name to the config file
"""
self.parser = ConfigParser()
self.config_file_name = "files/config.ini"
self.root_path = os.path.dirname(os.path.abspath(__file__))
self.config_file = os.path.join(self.root_path, self.config_file_name)
self._load()
def _save(self):
with open(self.config_file, 'w') as outfile:
self.parser.write(outfile)
def _load(self):
self.parser.read(self.config_file)
def add_section(self, section):
self._load()
self.parser.add_section(section)
self._save()
def set(self, section: str, option: str, value: str):
self._load()
self.parser.set(section, option, value)
self._save()
def get(self, section: str, option: str):
self._load()
return self.parser.get(section, option)
from config import Config
from windows import SettingsWindow, EditRecord, Window, show_error
class Application:
def __init__(self):
# tkinter settings
x_offset = 700
y_offset = 400
y_offset = 200
width = 1050
height = 700
title = "Brovski Adress-Etiketten Verwaltung"
self.root = tk.Tk(className="BrovskiAdressEtiketten")
self.root.title(title)
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
self.root.geometry(f"+{x_offset}+{y_offset}")
self.root.geometry(f"{width}x{height}+{x_offset}+{y_offset}")
self.config = Config()
self.config_good = False
# variables
self.address_list = []
self.current_record: int | None = None
self.sort_order = False
# init paths to json and csv file
self.json_file_name = "brovski-adress-etiketten-verwaltung.json"
@@ -153,8 +43,10 @@ class Application:
# leave application if settings are bad
if not self.config_good:
self.show_error("Fehler Konfiguration",
"Die Konfiguration ist fehlerhaft, bitte prüfe deine config.ini")
show_error(message_title="Fehler Konfiguration",
message="Die Konfiguration ist fehlerhaft, bitte prüfe deine config.ini",
parent=self.root
)
sys.exit()
top_frame = tk.Frame(self.root)
@@ -163,46 +55,29 @@ class Application:
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)
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.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)
self.aktiv = tk.StringVar()
self.firma = tk.StringVar()
self.name = tk.StringVar()
self.strasse = tk.StringVar()
self.plz_ort = tk.StringVar()
edit_frame = tk.Frame(self.root)
edit_frame.pack(side=tk.TOP, fill=tk.X)
tk.Label(edit_frame, text="Aktiv").grid(row=0, column=0)
tk.Label(edit_frame, text="Firma").grid(row=0, column=1)
tk.Label(edit_frame, text="Name").grid(row=0, column=2)
tk.Label(edit_frame, text="Strasse").grid(row=0, column=3)
tk.Label(edit_frame, text="Plz/Ort").grid(row=0, column=4)
edit_aktiv = tk.Checkbutton(edit_frame, variable=self.aktiv, onvalue="x", offvalue="")
edit_aktiv.grid(row=1, column=0)
edit_firma = tk.Entry(edit_frame, textvariable=self.firma)
edit_firma.grid(row=1, column=1)
edit_name = tk.Entry(edit_frame, textvariable=self.name)
edit_name.grid(row=1, column=2)
edit_strasse = tk.Entry(edit_frame, textvariable=self.strasse)
edit_strasse.grid(row=1, column=3)
edit_plz_ort = tk.Entry(edit_frame, textvariable=self.plz_ort)
edit_plz_ort.grid(row=1, column=4)
tk.Button(edit_frame, text="Update", command=self.update_record).grid(row=1, column=5)
data_frame = tk.Frame(self.root, bg="teal")
data_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
self.table = ttk.Treeview(data_frame, columns=("0", "1", "2", "3", "4"), show="headings")
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")
scrollbar.config(command=self.table.yview)
self.table.heading('0', text="Aktiv")
self.table.column('0', anchor=tk.CENTER, width=0)
self.table.heading('1', text="Firma")
self.table.heading('2', text="Name")
self.table.heading('3', text="Strasse")
self.table.heading('4', text="Plz/Ort")
self.table.pack()
self.table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.LEFT, fill=tk.Y)
self.table.bind("<ButtonRelease-1>", self.mouse_click)
self.table.bind("<Return>", self.mouse_click_double)
self.table.bind("<Double-1>", self.mouse_click_double)
self._load_json_file()
@@ -212,6 +87,8 @@ class Application:
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 == "":
raise ValueError("Empty JSON or CSV path")
self.config_good = True
except NoSectionError:
self.show_config_error()
@@ -219,25 +96,23 @@ class Application:
except NoOptionError:
self.show_config_error()
self.show_settings()
except ValueError:
self.show_config_error()
self.show_settings()
def show_config_error(self):
if self.show_error("Fehlerhafte Konfiguration",
"Konnte benötigte Parameter in config.ini nicht finden"):
print("Fehlerhafte Konfiguration")
show_error(message_title="Fehlerhafte Konfiguration",
message="Konnte benötigte Parameter in config.ini nicht finden",
parent=self.root)
def on_close(self):
self.root.destroy()
def show_settings(self):
self.root.withdraw()
settings = SettingsWindow(self.root)
settings = self.open_window_settings()
settings.wait_window()
def insert_record(self):
if self.current_record is not None:
self.clear_entry_fields()
children = self.table.get_children()
values = [
"x",
"Firma",
@@ -245,8 +120,11 @@ class Application:
"Strasse",
"Plz/Ort",
]
self.table.insert('', 'end', values=values)
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()
self.deselect_tree()
def delete_record(self):
if self.current_record is None:
@@ -257,72 +135,89 @@ class Application:
"Willst du diesen Eintrag wirklich löschen?\nDies kann nicht rückgängig gemacht werden"):
self.table.delete(self.current_record)
self.clear_entry_fields()
self.deselect_tree()
self._save_json_file()
def clear_entry_fields(self):
entry_var_list = [self.aktiv, self.firma, self.name, self.strasse, self.plz_ort]
for entry in entry_var_list:
entry.set("")
self.current_record = None
def mouse_click(self, event):
region = self.table.identify("region", event.x, event.y)
if region == "heading":
column = self.table.identify_column(event.x)
match column:
case "#1":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#2":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#3":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#4":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case "#5":
self.address_list.sort(key=lambda x: x[int(column[-1]) - 1])
self.populate_table()
case _:
print(column)
if region == "cell":
self.current_record = self.table.focus()
values = self.table.item(self.current_record, "values")
entry_var_list = [self.aktiv, self.firma, self.name, self.strasse, self.plz_ort]
for i in range(len(values)):
entry_var_list[i].set(values[i])
def update_record(self):
def update_record(self, data: list):
if self.current_record is None:
return
values = {
0: self.aktiv.get(),
1: self.firma.get(),
2: self.name.get(),
3: self.strasse.get(),
4: self.plz_ort.get(),
}
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.clear_entry_fields()
self._save_json_file()
def toggle_active(self):
items = self.table.selection()
if len(items) == 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)
self._save_json_file()
def deselect_tree(self):
while len(self.table.selection()) > 0:
self.table.selection_remove(self.table.selection()[0])
self.current_record = None
def mouse_click(self, event):
self.current_record = self.table.focus()
region = self.table.identify("region", event.x, event.y)
match region:
case "heading":
self.click_on_header(event)
def mouse_click_double(self, event):
region = self.table.identify("region", event.x, event.y)
match region:
case "cell":
self.click_on_cell()
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
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)
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:
self.show_error(
show_error(
message_title="Datei nicht gefunden",
message=f"{self.json_file_name} nicht gefunden, erstelle leere Datei unter {self.json_path}"
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:
@@ -335,8 +230,10 @@ class Application:
with open(self.json_file, "w", encoding="utf-8") as f:
json.dump(self.address_list, f, indent=4, sort_keys=True)
except FileNotFoundError:
self.show_error(
message_title="Unexpected Error: File not found?!", message=f"{self.json_file_name} not found"
show_error(
message_title="Unexpected Error: File not found?!",
message=f"{self.json_file_name} not found",
parent=self.root
)
def export_csv(self):
@@ -351,7 +248,10 @@ class Application:
del address[0]
writer.writerow(address)
except FileNotFoundError:
self.show_error("Unexpected error", f"Could not write file {self.csv_file}")
show_error(message_title="Unexpected error",
message=f"Could not write file {self.csv_file}",
parent=self.root
)
def populate_table(self):
self.delete_all_table_items()
@@ -369,9 +269,20 @@ class Application:
for item in self.table.get_children():
self.table.delete(item)
@staticmethod
def show_error(message_title: str, message: str):
messagebox.showwarning(title=message_title, message=message)
def open_window_settings(self):
window = SettingsWindow(self, self.root)
window.wm_transient(self.root)
window.wait_visibility()
window.grab_set()
return window
def open_window_edit_records(self, data):
window = EditRecord(self, self.root, data)
window.wm_transient(self.root)
window.wait_visibility()
window.grab_set()
if __name__ == '__main__':

View File

@@ -1,2 +0,0 @@
#!/usr/bin/env bash
pyinstaller --clean --add-data=files/config.ini:files brovski-adress-etiketten-verwaltung.py

45
src/config.py Normal file
View File

@@ -0,0 +1,45 @@
import os
from configparser import ConfigParser
class Config:
parser: ConfigParser
def __init__(self):
"""
Config parser reading config.ini
Attributes:
self.parser: ConfigParser holding list of sections and options
self.__filename: Path and name to the config file
"""
self.parser = ConfigParser()
home_path = os.environ["HOME"]
full_path = os.path.join(home_path, ".config", "brovski-adress-etiketten" )
if not os.path.exists(full_path):
os.makedirs(full_path)
self.config_file = os.path.join(full_path, "config.ini")
self._load()
def _save(self):
with open(self.config_file, 'w') as outfile:
self.parser.write(outfile)
def _load(self):
self.parser.read(self.config_file)
def add_section(self, section):
self._load()
self.parser.add_section(section)
self._save()
def set(self, section: str, option: str, value: str):
self._load()
self.parser.set(section, option, value)
self._save()
def get(self, section: str, option: str):
self._load()
return self.parser.get(section, option)

View File

148
src/windows.py Normal file
View File

@@ -0,0 +1,148 @@
import tkinter as tk
from configparser import NoSectionError, NoOptionError
from tkinter import font, filedialog, messagebox
from config import Config
def show_error(message_title: str, message: str, parent: tk.Tk | tk.Toplevel):
messagebox.showwarning(
title=message_title,
message=message,
parent=parent
)
class Window(tk.Toplevel):
def __init__(self, parent, root: tk.Tk):
super().__init__(root)
self.parent = parent
self.root = root
self.protocol("WM_DELETE_WINDOW", self.close_window)
self.bind("<Escape>", self.close_window)
def close_window(self, event = None):
self._destroy_window()
def _destroy_window(self):
self.root.update()
self.destroy()
class EditRecord(Window):
def __init__(self, parent, root: tk.Tk, data: tuple):
super().__init__(parent, root)
self.bind("<Return>", self._update)
self.data = data
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)
edit_frame = tk.Frame(self)
edit_frame.pack(side=tk.TOP, fill=tk.X, pady=20, padx=20)
tk.Label(edit_frame, text="Aktiv", anchor=tk.W).grid(row=0, column=0)
tk.Label(edit_frame, text="Firma").grid(row=0, column=1)
tk.Label(edit_frame, text="Name").grid(row=0, column=2)
tk.Label(edit_frame, text="Strasse").grid(row=0, column=3)
tk.Label(edit_frame, text="Plz/Ort").grid(row=0, column=4)
edit_aktiv = tk.Checkbutton(edit_frame, variable=self.aktiv, onvalue="x", offvalue="")
edit_aktiv.grid(row=1, column=0)
edit_firma = tk.Entry(edit_frame, textvariable=self.firma)
edit_firma.grid(row=1, column=1)
edit_name = tk.Entry(edit_frame, textvariable=self.name)
edit_name.grid(row=1, column=2)
edit_strasse = tk.Entry(edit_frame, textvariable=self.strasse)
edit_strasse.grid(row=1, column=3)
edit_plz_ort = tk.Entry(edit_frame, textvariable=self.plz_ort)
edit_plz_ort.grid(row=1, column=4)
button_frame = tk.Frame(self)
button_frame.pack(side=tk.TOP, pady=10)
tk.Button(button_frame, text="Save", command=self._update, width=button_width).pack(side=tk.LEFT)
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)
self.close_window()
class SettingsWindow(Window):
def __init__(self, parent, root: tk.Tk):
super().__init__(parent, root)
self.geometry(f"500x330+{self.root.winfo_x() + 20}+{self.root.winfo_y() + 20}")
self.config = Config()
self.json_file = tk.StringVar()
self.csv_file = tk.StringVar()
title = font.Font(family='Ubuntu Mono', size=20, weight=font.BOLD)
tk.Label(self, text="Einstellungen", font=title).pack(pady=20)
path_frame = tk.Frame(self)
path_frame.pack(pady=(10, 40))
tk.Label(path_frame, text="Datenpfad JSON Datei").grid(row=0, column=0)
tk.Entry(path_frame, textvariable=self.json_file, width=50).grid(row=1, column=0)
tk.Button(path_frame, text="Pfad", command=lambda: self.set_json_path(self.json_file.get())).grid(row=1,
column=1)
tk.Label(path_frame, text="Datenpfad CSV Export Datei").grid(row=2, column=0)
tk.Entry(path_frame, textvariable=self.csv_file, width=50).grid(row=3, column=0)
tk.Button(path_frame, text="Pfad", command=lambda: self.set_csv_path(self.csv_file.get())).grid(row=3, column=1)
bottom_frame = tk.Frame(self)
bottom_frame.pack()
tk.Button(bottom_frame, text="Ok", command=self.ok).pack(side=tk.LEFT)
tk.Button(bottom_frame, text="Abbrechen", command=self.cancel).pack(side=tk.LEFT)
self.load_config()
def set_json_path(self, initial_dir: str = ""):
initial_dir = "~/" if initial_dir == "" else initial_dir
new_path = filedialog.askdirectory(initialdir=initial_dir, title="Datenpfad JSON Datei")
new_path = initial_dir if len(new_path) == 0 else new_path
self.json_file.set(new_path)
def set_csv_path(self, initial_dir: str = ""):
initial_dir = "~/" if initial_dir == "" else initial_dir
new_path = filedialog.askdirectory(initialdir=initial_dir, title="Datenpfad CSV Datei")
new_path = initial_dir if len(new_path) == 0 else new_path
self.csv_file.set(new_path)
def load_config(self):
try:
self.json_file.set(self.config.get("json", "path"))
except NoSectionError:
self.config.add_section("json")
self.config.set("json", "path", "")
except NoOptionError:
self.config.set("json", "path", "")
try:
self.csv_file.set(self.config.get("csv", "path"))
except NoSectionError:
self.config.add_section("csv")
self.config.set("csv", "path", "")
except NoOptionError:
self.config.set("csv", "path", "")
def ok(self):
if self.json_file.get() == "" or self.csv_file.get() == "":
show_error(message_title="Fehlerhafte Konfiguration",
message="Pfad für JSON oder CSV Datei fehlt",
parent=self)
return
self.config.set("json", "path", self.json_file.get())
self.config.set("csv", "path", self.csv_file.get())
self.close_window()
def cancel(self):
self.close_window()