mirror of
https://github.com/Ircama/epson_print_conf.git
synced 2024-10-18 09:10:36 -04:00
Add tree view to printer status UI
This commit is contained in:
parent
a4d08e0721
commit
1ed4e93553
1 changed files with 133 additions and 6 deletions
139
ui.py
139
ui.py
|
@ -1,11 +1,12 @@
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import ttk
|
from tkinter import ttk, Menu
|
||||||
from tkinter.scrolledtext import ScrolledText
|
from tkinter.scrolledtext import ScrolledText
|
||||||
import threading
|
import threading
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from epson_print_conf import EpsonPrinter
|
|
||||||
from find_printers import PrinterScanner
|
from find_printers import PrinterScanner
|
||||||
from pprint import pformat
|
from epson_print_conf import EpsonPrinter
|
||||||
|
import tkinter.font as tkfont
|
||||||
|
|
||||||
|
|
||||||
class EpsonPrinterUI(tk.Tk):
|
class EpsonPrinterUI(tk.Tk):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -64,10 +65,60 @@ class EpsonPrinterUI(tk.Tk):
|
||||||
status_frame.columnconfigure(0, weight=1)
|
status_frame.columnconfigure(0, weight=1)
|
||||||
status_frame.rowconfigure(0, weight=1)
|
status_frame.rowconfigure(0, weight=1)
|
||||||
|
|
||||||
|
# ScrolledText widget
|
||||||
self.status_text = ScrolledText(status_frame, height=10, width=50, wrap=tk.WORD)
|
self.status_text = ScrolledText(status_frame, height=10, width=50, wrap=tk.WORD)
|
||||||
self.status_text.grid(row=0, column=0, pady=5, padx=5, sticky=(tk.W, tk.E, tk.N, tk.S))
|
self.status_text.grid(row=0, column=0, pady=5, padx=5, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
|
|
||||||
|
# Style configuration
|
||||||
|
style = ttk.Style(self)
|
||||||
|
default_font = style.lookup("Treeview.Heading", "font")
|
||||||
|
|
||||||
|
# If the default_font is a tuple, split into components
|
||||||
|
if isinstance(default_font, tuple):
|
||||||
|
default_font_name, default_font_size = default_font[0], default_font[1]
|
||||||
|
else:
|
||||||
|
# If font is not a tuple, it might be a font string or other format.
|
||||||
|
default_font_name, default_font_size = tkfont.Font().actual('family'), tkfont.Font().actual('size')
|
||||||
|
|
||||||
|
style.configure("Treeview.Heading",
|
||||||
|
font=(default_font_name, default_font_size - 2, "bold"),
|
||||||
|
background="lightblue",
|
||||||
|
foreground="darkblue")
|
||||||
|
|
||||||
|
# Create and configure the Treeview widget
|
||||||
|
self.tree = ttk.Treeview(status_frame, style="Treeview")
|
||||||
|
self.tree.heading("#0", text="Status Information", anchor='w')
|
||||||
|
self.tree.grid(column=0, row=0, sticky=(tk.W, tk.E, tk.N, tk.S))
|
||||||
|
|
||||||
|
# Create a vertical scrollbar for the Treeview
|
||||||
|
tree_scrollbar = ttk.Scrollbar(status_frame, orient="vertical", command=self.tree.yview)
|
||||||
|
tree_scrollbar.grid(column=1, row=0, sticky=(tk.N, tk.S))
|
||||||
|
|
||||||
|
# Configure the Treeview to use the scrollbar
|
||||||
|
self.tree.configure(yscrollcommand=tree_scrollbar.set)
|
||||||
|
|
||||||
|
# Create a context menu
|
||||||
|
self.context_menu = Menu(self, tearoff=0)
|
||||||
|
self.context_menu.add_command(label="Copy", command=self.copy_selected_item)
|
||||||
|
|
||||||
|
# Bind the right-click event to the Treeview
|
||||||
|
self.tree.bind("<Button-3>", self.show_context_menu)
|
||||||
|
|
||||||
|
# Hide the grid view initially
|
||||||
|
self.tree.grid_remove()
|
||||||
|
|
||||||
|
def show_status_text_view(self):
|
||||||
|
"""Show the status frame and hide the Treeview."""
|
||||||
|
self.tree.grid_remove()
|
||||||
|
self.status_text.grid()
|
||||||
|
|
||||||
|
def show_treeview(self):
|
||||||
|
"""Show the Treeview and hide the status frame."""
|
||||||
|
self.status_text.grid_remove()
|
||||||
|
self.tree.grid()
|
||||||
|
|
||||||
def print_status(self):
|
def print_status(self):
|
||||||
|
self.show_status_text_view()
|
||||||
model = self.model_var.get()
|
model = self.model_var.get()
|
||||||
ip_address = self.ip_var.get()
|
ip_address = self.ip_var.get()
|
||||||
if not model or not self._is_valid_ip(ip_address):
|
if not model or not self._is_valid_ip(ip_address):
|
||||||
|
@ -76,11 +127,17 @@ class EpsonPrinterUI(tk.Tk):
|
||||||
printer = EpsonPrinter(model=model, hostname=ip_address)
|
printer = EpsonPrinter(model=model, hostname=ip_address)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.status_text.insert(tk.END, f"[INFO] {pformat(printer.stats())}\n")
|
self.show_treeview()
|
||||||
|
# Populate the Treeview
|
||||||
|
self.populate_treeview('', self.tree, printer.stats())
|
||||||
|
# Expand all nodes
|
||||||
|
self.expand_all(self.tree)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
self.show_status_text_view()
|
||||||
self.status_text.insert(tk.END, f"[ERROR] {e}\n")
|
self.status_text.insert(tk.END, f"[ERROR] {e}\n")
|
||||||
|
|
||||||
def reset_waste_ink(self):
|
def reset_waste_ink(self):
|
||||||
|
self.show_status_text_view()
|
||||||
model = self.model_var.get()
|
model = self.model_var.get()
|
||||||
ip_address = self.ip_var.get()
|
ip_address = self.ip_var.get()
|
||||||
if not model or not self._is_valid_ip(ip_address):
|
if not model or not self._is_valid_ip(ip_address):
|
||||||
|
@ -94,6 +151,7 @@ class EpsonPrinterUI(tk.Tk):
|
||||||
self.status_text.insert(tk.END, f"[ERROR] {e}\n")
|
self.status_text.insert(tk.END, f"[ERROR] {e}\n")
|
||||||
|
|
||||||
def start_detect_printers(self):
|
def start_detect_printers(self):
|
||||||
|
self.show_status_text_view()
|
||||||
self.status_text.insert(tk.END, "[INFO] Detecting printers... (this might take a while)\n")
|
self.status_text.insert(tk.END, "[INFO] Detecting printers... (this might take a while)\n")
|
||||||
self.detect_button.config(state=tk.DISABLED) # disable button while processing
|
self.detect_button.config(state=tk.DISABLED) # disable button while processing
|
||||||
|
|
||||||
|
@ -101,6 +159,7 @@ class EpsonPrinterUI(tk.Tk):
|
||||||
threading.Thread(target=self.detect_printers).start()
|
threading.Thread(target=self.detect_printers).start()
|
||||||
|
|
||||||
def detect_printers(self):
|
def detect_printers(self):
|
||||||
|
self.show_status_text_view()
|
||||||
printer_scanner=PrinterScanner()
|
printer_scanner=PrinterScanner()
|
||||||
try:
|
try:
|
||||||
printers = printer_scanner.get_all_printers()
|
printers = printer_scanner.get_all_printers()
|
||||||
|
@ -121,6 +180,74 @@ class EpsonPrinterUI(tk.Tk):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_simple_type(self, data):
|
||||||
|
return isinstance(data, (str, int, float, bool))
|
||||||
|
|
||||||
|
def contains_parentheses(self, data):
|
||||||
|
"""Check if a string representation contains parentheses."""
|
||||||
|
if isinstance(data, (list, tuple, set)):
|
||||||
|
for item in data:
|
||||||
|
if isinstance(item, (tuple, list, set)):
|
||||||
|
return True
|
||||||
|
if isinstance(item, str) and ('(' in item or ')' in item):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def populate_treeview(self, parent, treeview, data):
|
||||||
|
if isinstance(data, dict):
|
||||||
|
for key, value in data.items():
|
||||||
|
if isinstance(value, (dict, list, set, tuple)):
|
||||||
|
node = treeview.insert(parent, 'end', text=key)
|
||||||
|
self.populate_treeview(node, treeview, value)
|
||||||
|
else:
|
||||||
|
treeview.insert(parent, 'end', text=f"{key}: {value}")
|
||||||
|
elif isinstance(data, list):
|
||||||
|
if all(self.is_simple_type(item) for item in data) and not self.contains_parentheses(data):
|
||||||
|
treeview.insert(parent, 'end', text=', '.join(map(str, data)))
|
||||||
|
else:
|
||||||
|
for item in data:
|
||||||
|
if isinstance(item, (dict, list, set, tuple)):
|
||||||
|
self.populate_treeview(parent, treeview, item)
|
||||||
|
else:
|
||||||
|
treeview.insert(parent, 'end', text=str(item))
|
||||||
|
elif isinstance(data, set):
|
||||||
|
if not self.contains_parentheses(data):
|
||||||
|
treeview.insert(parent, 'end', text=', '.join(map(str, data)))
|
||||||
|
else:
|
||||||
|
for item in data:
|
||||||
|
treeview.insert(parent, 'end', text=str(item))
|
||||||
|
elif isinstance(data, tuple):
|
||||||
|
treeview.insert(parent, 'end', text=str(data))
|
||||||
|
else:
|
||||||
|
treeview.insert(parent, 'end', text=str(data))
|
||||||
|
|
||||||
|
def expand_all(self, treeview):
|
||||||
|
def recursive_expand(item):
|
||||||
|
treeview.item(item, open=True)
|
||||||
|
children = treeview.get_children(item)
|
||||||
|
for child in children:
|
||||||
|
recursive_expand(child)
|
||||||
|
|
||||||
|
root_children = treeview.get_children()
|
||||||
|
for child in root_children:
|
||||||
|
recursive_expand(child)
|
||||||
|
|
||||||
|
def show_context_menu(self, event):
|
||||||
|
"""Show the context menu."""
|
||||||
|
# Select the item under the cursor
|
||||||
|
item = self.tree.identify_row(event.y)
|
||||||
|
if item:
|
||||||
|
self.tree.selection_set(item)
|
||||||
|
self.context_menu.post(event.x_root, event.y_root)
|
||||||
|
|
||||||
|
def copy_selected_item(self):
|
||||||
|
"""Copy the selected Treeview item text to the clipboard."""
|
||||||
|
selected_item = self.tree.selection()
|
||||||
|
if selected_item:
|
||||||
|
item_text = self.tree.item(selected_item[0], "text")
|
||||||
|
self.clipboard_clear()
|
||||||
|
self.clipboard_append(item_text)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = EpsonPrinterUI()
|
app = EpsonPrinterUI()
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|
Loading…
Reference in a new issue