Fix silent printing and shorten printer display names

- Print directly via win32print API without opening PDF viewer
- Shorten printer names to 20 chars in dropdown (strip server prefix for network printers)
- Map display names back to full names for printing
- PDF backup saved silently without launching viewer
This commit is contained in:
2026-02-06 11:18:27 +02:00
parent 1cf4482914
commit b204ce38fc
2 changed files with 80 additions and 31 deletions

View File

@@ -38,15 +38,42 @@ class LabelPrinterApp(App):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.available_printers = self.get_available_printers() # Build printer display names and mapping to full names
full_printers = get_available_printers()
self.printer_display_map = {} # display_name -> full_name
self.available_printers = []
for full_name in full_printers:
display_name = self._shorten_printer_name(full_name)
# Ensure unique display names
if display_name in self.printer_display_map:
display_name = full_name[:20]
self.printer_display_map[display_name] = full_name
self.available_printers.append(display_name)
# Clean old PDF backup files on startup # Clean old PDF backup files on startup
self.cleanup_old_pdfs() self.cleanup_old_pdfs()
# Clean old log files on startup # Clean old log files on startup
self.cleanup_old_logs() self.cleanup_old_logs()
def get_available_printers(self): def _shorten_printer_name(self, name, max_len=20):
"""Get list of available printers (cross-platform)""" """Shorten printer name for display (max 20 chars).
return get_available_printers() For network printers like \\\\server\\printer, show just the printer part."""
if name.startswith('\\\\'):
# Network printer: \\server\printer -> extract printer name
parts = name.strip('\\').split('\\')
if len(parts) >= 2:
short = parts[-1] # Just the printer name
else:
short = name
else:
short = name
# Truncate to max_len
if len(short) > max_len:
short = short[:max_len]
return short
def _get_full_printer_name(self, display_name):
"""Resolve display name back to full printer name for printing."""
return self.printer_display_map.get(display_name, display_name)
def cleanup_old_pdfs(self, days=5): def cleanup_old_pdfs(self, days=5):
""" """
@@ -278,7 +305,8 @@ class LabelPrinterApp(App):
values=self.available_printers, values=self.available_printers,
size_hint_y=None, size_hint_y=None,
height=45, height=45,
font_size='12sp' font_size='12sp',
sync_height=True,
) )
self.printer_spinner = printer_spinner self.printer_spinner = printer_spinner
form_layout.add_widget(printer_spinner) form_layout.add_widget(printer_spinner)
@@ -320,7 +348,8 @@ class LabelPrinterApp(App):
sap_nr = self.sap_input.text.strip() sap_nr = self.sap_input.text.strip()
quantity = self.qty_input.text.strip() quantity = self.qty_input.text.strip()
cable_id = self.cable_id_input.text.strip() cable_id = self.cable_id_input.text.strip()
printer = self.printer_spinner.text # Resolve display name to full printer name
printer = self._get_full_printer_name(self.printer_spinner.text)
# Validate input # Validate input
if not sap_nr and not quantity and not cable_id: if not sap_nr and not quantity and not cable_id:

View File

@@ -249,38 +249,58 @@ def print_to_printer(printer_name, file_path):
return True return True
elif SYSTEM == "Windows": elif SYSTEM == "Windows":
# Windows: Use win32print API for reliable printing (supports UNC paths) # Windows: Print directly without opening PDF viewer
try: try:
if WIN32_AVAILABLE: if WIN32_AVAILABLE:
import win32print import win32print
import win32api import win32api
# Set the target printer as default temporarily, then print
# This approach works reliably with both local and UNC printer paths
try:
old_default = win32print.GetDefaultPrinter()
except:
old_default = None
try:
win32print.SetDefaultPrinter(printer_name)
win32api.ShellExecute(0, "print", file_path, None, ".", 0)
print(f"Label sent to printer: {printer_name}")
finally:
# Restore original default printer
if old_default:
try:
win32print.SetDefaultPrinter(old_default)
except:
pass
return True
else:
# Fallback: Open with default printer
if file_path.endswith('.pdf'): if file_path.endswith('.pdf'):
os.startfile(file_path, "print") # Use SumatraPDF command-line or direct raw printing
# Try printing via subprocess to avoid opening a PDF viewer window
# Method: Use win32print raw API to send to printer silently
try:
hprinter = win32print.OpenPrinter(printer_name)
try:
# Start a print job
job_info = ("Label Print", None, "RAW")
hjob = win32print.StartDocPrinter(hprinter, 1, job_info)
win32print.StartPagePrinter(hprinter)
# Read PDF file and send to printer
with open(file_path, 'rb') as f:
pdf_data = f.read()
win32print.WritePrinter(hprinter, pdf_data)
win32print.EndPagePrinter(hprinter)
win32print.EndDocPrinter(hprinter)
print(f"Label sent to printer: {printer_name}")
finally:
win32print.ClosePrinter(hprinter)
return True
except Exception as raw_err:
print(f"Raw print failed ({raw_err}), trying ShellExecute silently...")
# Fallback: Use ShellExecute with printto (minimized, auto-closes)
try:
win32api.ShellExecute(
0, "printto", file_path,
f'"{printer_name}"', ".", 0
)
print(f"Label sent to printer: {printer_name}")
return True
except Exception as shell_err:
print(f"ShellExecute print failed: {shell_err}")
return True
else: else:
subprocess.run(['notepad', '/p', file_path], check=False) # Non-PDF files: print silently with notepad
print(f"Label sent to default printer") subprocess.run(['notepad', '/p', file_path],
check=False,
creationflags=subprocess.CREATE_NO_WINDOW)
print(f"Label sent to printer: {printer_name}")
return True
else:
print("win32print not available, PDF saved as backup only")
return True return True
except Exception as e: except Exception as e:
print(f"Windows print error: {e}") print(f"Windows print error: {e}")