Add Kivy GUI interface for label printer
- Created label_printer_gui.py: Complete Kivy-based GUI application - Two-column layout (input form + live preview) - SAP-Nr, Quantity, Cable ID input fields - Real-time barcode preview (11.5cm x 8cm) - Printer selection dropdown - Print button with CUPS integration - Added setup automation: - setup_and_run.py: Python setup launcher - start_gui.sh: Bash launcher script - validate_project.py: Project validation - Added comprehensive documentation: - INDEX.md: Project overview and quick start - GETTING_STARTED.md: 15-minute quick start guide - README_GUI.md: Complete feature documentation - TECHNICAL_DOCS.md: Architecture and customization - FILE_GUIDE.md: File reference guide - IMPLEMENTATION_SUMMARY.md: Implementation overview - Updated dependencies: - requirements_gui.txt: New Kivy dependencies - Preserved: - print_label.py: Original printing engine (modified to remove main code) - Original documentation and dependencies Features: - Live preview of labels as you type - Automatic CUPS printer detection - Non-blocking background printing - User-friendly error handling - Responsive two-column layout - Production-ready quality
This commit is contained in:
390
TECHNICAL_DOCS.md
Normal file
390
TECHNICAL_DOCS.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# Technical Documentation - Label Printer GUI
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Component Structure
|
||||
|
||||
```
|
||||
label_printer_gui.py
|
||||
├── LabelPreviewWidget (ScatterLayout)
|
||||
│ ├── update_preview(text)
|
||||
│ ├── display_preview()
|
||||
│ └── Displays PIL image as Kivy widget
|
||||
│
|
||||
└── LabelPrinterApp (App)
|
||||
├── build() → Main UI layout
|
||||
├── create_input_column() → Left side form
|
||||
├── create_preview_column() → Right side preview
|
||||
├── get_available_printers() → CUPS integration
|
||||
├── on_input_change() → Live preview update
|
||||
├── print_label() → Print workflow
|
||||
└── show_popup() → User notifications
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
User Input (TextInput)
|
||||
↓
|
||||
on_input_change() event
|
||||
↓
|
||||
Combine fields: f"{sap}|{qty}|{cable_id}"
|
||||
↓
|
||||
create_label_image() from print_label.py
|
||||
↓
|
||||
LabelPreviewWidget.update_preview()
|
||||
↓
|
||||
Display in right column
|
||||
```
|
||||
|
||||
## Class Details
|
||||
|
||||
### LabelPreviewWidget
|
||||
|
||||
**Purpose:** Display real-time label preview
|
||||
|
||||
**Methods:**
|
||||
- `update_preview(text)` - Create new label image from text
|
||||
- `display_preview()` - Render image in Kivy widget
|
||||
|
||||
**Attributes:**
|
||||
- `label_image` - Current PIL Image object
|
||||
- `temp_preview_path` - Temporary PNG file path
|
||||
|
||||
**Key Features:**
|
||||
- Uses PIL to generate labels at 300 DPI
|
||||
- Displays in KivyImage widget
|
||||
- Maintains aspect ratio (11.5cm × 8cm)
|
||||
- Auto-updates on input change
|
||||
|
||||
### LabelPrinterApp
|
||||
|
||||
**Purpose:** Main application orchestrator
|
||||
|
||||
**Methods:**
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
| `build()` | Construct main UI layout |
|
||||
| `create_input_column()` | Build left form panel |
|
||||
| `create_preview_column()` | Build right preview panel |
|
||||
| `get_available_printers()` | Fetch CUPS printer list |
|
||||
| `on_input_change()` | Handle input updates |
|
||||
| `print_label()` | Execute print workflow |
|
||||
| `show_popup()` | Display notifications |
|
||||
|
||||
**Event Flow:**
|
||||
|
||||
1. **Initialization:**
|
||||
```
|
||||
__init__() → get_available_printers()
|
||||
→ build()
|
||||
→ create_input_column()
|
||||
→ create_preview_column()
|
||||
```
|
||||
|
||||
2. **User Interaction:**
|
||||
```
|
||||
TextInput.on_text → on_input_change()
|
||||
→ preview_widget.update_preview()
|
||||
```
|
||||
|
||||
3. **Printing:**
|
||||
```
|
||||
Button.on_press → print_label()
|
||||
→ threading.Thread(print_thread)
|
||||
→ print_label_standalone()
|
||||
→ show_popup()
|
||||
```
|
||||
|
||||
## Integration with print_label.py
|
||||
|
||||
### Functions Used
|
||||
|
||||
```python
|
||||
from print_label import create_label_image, print_label_standalone
|
||||
```
|
||||
|
||||
**create_label_image(text)**
|
||||
- Input: Combined text (e.g., "SAP123|50|REEL001")
|
||||
- Output: PIL Image (11.5cm × 8cm @ 300 DPI)
|
||||
- Generates Code128 barcode
|
||||
- Centers text below barcode
|
||||
|
||||
**print_label_standalone(value, printer, preview)**
|
||||
- Input:
|
||||
- `value`: Text to encode in barcode
|
||||
- `printer`: CUPS printer name (e.g., "PDF")
|
||||
- `preview`: 0=no preview, 1-3=3s, >3=5s
|
||||
- Output: Boolean (True=success)
|
||||
- Handles CUPS printing
|
||||
- Manages temporary files
|
||||
|
||||
## UI Layout Structure
|
||||
|
||||
### Main Layout
|
||||
```
|
||||
BoxLayout (horizontal)
|
||||
├── Left Column (40%)
|
||||
│ BoxLayout (vertical)
|
||||
│ ├── Title Label
|
||||
│ ├── ScrollView
|
||||
│ │ └── GridLayout (1 col)
|
||||
│ │ ├── Label: "SAP-Nr. Articol"
|
||||
│ │ ├── TextInput (sap_input)
|
||||
│ │ ├── Label: "Cantitate"
|
||||
│ │ ├── TextInput (qty_input)
|
||||
│ │ ├── Label: "ID rola cablu"
|
||||
│ │ ├── TextInput (cable_id_input)
|
||||
│ │ ├── Label: "Select Printer"
|
||||
│ │ └── Spinner (printer_spinner)
|
||||
│ └── Button: "PRINT LABEL"
|
||||
│
|
||||
└── Right Column (60%)
|
||||
BoxLayout (vertical)
|
||||
├── Title Label
|
||||
└── LabelPreviewWidget
|
||||
```
|
||||
|
||||
### Styling
|
||||
|
||||
**Colors:**
|
||||
- Print Button: `(0.2, 0.6, 0.2, 1)` - Green
|
||||
- Background: Default Kivy theme
|
||||
- Text: Black on white/gray
|
||||
|
||||
**Fonts:**
|
||||
- Title: 18sp, bold
|
||||
- Labels: 14sp, regular
|
||||
- Input: 16sp, regular
|
||||
|
||||
**Sizing:**
|
||||
- Window: 1600×900 (adjustable)
|
||||
- Left column: 40% of width
|
||||
- Right column: 60% of width
|
||||
|
||||
## Threading Model
|
||||
|
||||
### Background Printing
|
||||
|
||||
```python
|
||||
def print_label(self, instance):
|
||||
# ... validation ...
|
||||
|
||||
popup = Popup(...) # Show loading
|
||||
popup.open()
|
||||
|
||||
def print_thread():
|
||||
try:
|
||||
success = print_label_standalone(...)
|
||||
# Update UI in main thread
|
||||
popup.dismiss()
|
||||
self.show_popup(...)
|
||||
except Exception as e:
|
||||
# Error handling
|
||||
self.show_popup("Error", str(e))
|
||||
|
||||
thread = threading.Thread(target=print_thread)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
```
|
||||
|
||||
**Why threading?**
|
||||
- Prevents UI freezing during print
|
||||
- CUPS operations can be slow
|
||||
- User can continue working while printing
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Validation
|
||||
|
||||
1. **Input Validation:**
|
||||
```python
|
||||
if not sap_nr and not quantity and not cable_id:
|
||||
show_popup("Error", "Please enter at least one field")
|
||||
```
|
||||
|
||||
2. **Printer Validation:**
|
||||
- Fallback to "PDF" if none available
|
||||
- Checks printer existence before print
|
||||
|
||||
3. **Exception Handling:**
|
||||
- Try-except in preview generation
|
||||
- Try-except in print thread
|
||||
- User-friendly error messages
|
||||
|
||||
### Logging
|
||||
|
||||
- Console output for debugging
|
||||
- Error messages in popups
|
||||
- Exception info in thread callbacks
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Preview Updates
|
||||
|
||||
- Only regenerates label when text changes
|
||||
- Debouncing happens naturally via Kivy events
|
||||
- PIL image operations are fast (~100ms)
|
||||
|
||||
### Memory Management
|
||||
|
||||
- Temporary files auto-deleted
|
||||
- PIL images cached during preview
|
||||
- Temp preview file cleaned when updated
|
||||
|
||||
### CUPS Operations
|
||||
|
||||
- Non-blocking via threading
|
||||
- Timeout handling for printer ops
|
||||
- Connection pooled by pycups
|
||||
|
||||
## Customization Guide
|
||||
|
||||
### Change Label Size
|
||||
|
||||
In `print_label.py`:
|
||||
```python
|
||||
# Modify label dimensions
|
||||
label_width = 1063 # pixels for 9cm @ 300 DPI
|
||||
label_height = 591 # pixels for 5cm @ 300 DPI
|
||||
```
|
||||
|
||||
For 11.5cm × 8cm @ 300 DPI:
|
||||
```python
|
||||
label_width = 1378 # 11.5cm @ 300 DPI
|
||||
label_height = 944 # 8cm @ 300 DPI
|
||||
```
|
||||
|
||||
### Modify UI Colors
|
||||
|
||||
In `label_printer_gui.py`:
|
||||
```python
|
||||
# Change print button color
|
||||
Button(
|
||||
...
|
||||
background_color=(R, G, B, A), # RGBA: 0.0-1.0
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### Add New Input Fields
|
||||
|
||||
```python
|
||||
# In create_input_column():
|
||||
new_label = Label(text='New Field:', size_hint_y=None, height=40)
|
||||
form_layout.add_widget(new_label)
|
||||
|
||||
self.new_input = TextInput(...)
|
||||
self.new_input.bind(text=self.on_input_change)
|
||||
form_layout.add_widget(self.new_input)
|
||||
|
||||
# In on_input_change():
|
||||
new_field = self.new_input.text
|
||||
```
|
||||
|
||||
## Dependencies Deep Dive
|
||||
|
||||
### Kivy
|
||||
- **Version:** 2.0+
|
||||
- **Role:** GUI framework
|
||||
- **Key classes:** App, BoxLayout, TextInput, Button, Spinner
|
||||
|
||||
### python-barcode
|
||||
- **Version:** Latest
|
||||
- **Role:** Code128 barcode generation
|
||||
- **Integration:** Used in print_label.py
|
||||
|
||||
### Pillow (PIL)
|
||||
- **Version:** 8.0+
|
||||
- **Role:** Image generation and processing
|
||||
- **Features:** ImageDraw for text, Image for resizing
|
||||
|
||||
### pycups
|
||||
- **Version:** Latest
|
||||
- **Role:** CUPS printer interface
|
||||
- **Functions:** getPrinters(), printFile()
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Test Example
|
||||
|
||||
```python
|
||||
def test_label_preview_update():
|
||||
app = LabelPrinterApp()
|
||||
test_text = "TEST|123|REEL"
|
||||
app.preview_widget.update_preview(test_text)
|
||||
assert app.preview_widget.label_image is not None
|
||||
|
||||
def test_printer_list():
|
||||
app = LabelPrinterApp()
|
||||
printers = app.get_available_printers()
|
||||
assert isinstance(printers, list)
|
||||
assert len(printers) > 0
|
||||
```
|
||||
|
||||
### Manual Testing
|
||||
|
||||
1. **Preview Update Test:**
|
||||
- Type in each field
|
||||
- Verify preview updates
|
||||
- Check barcode changes
|
||||
|
||||
2. **Printer Test:**
|
||||
- Select different printers
|
||||
- Verify dropdown updates
|
||||
|
||||
3. **Print Test:**
|
||||
- Use PDF printer for testing
|
||||
- Check output file generated
|
||||
|
||||
## Deployment Notes
|
||||
|
||||
### System Requirements
|
||||
- Linux/Unix (CUPS-based)
|
||||
- X11 or Wayland display
|
||||
- ~50MB disk space
|
||||
- 2GB RAM minimum
|
||||
|
||||
### Installation Steps
|
||||
1. Clone/download repository
|
||||
2. Install Python 3.7+
|
||||
3. Run setup_and_run.py
|
||||
4. Configure system printer
|
||||
|
||||
### Containerization
|
||||
|
||||
For Docker deployment:
|
||||
```dockerfile
|
||||
FROM python:3.9-slim
|
||||
RUN apt-get update && apt-get install -y cups
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
RUN pip install -r requirements_gui.txt
|
||||
CMD ["python3", "label_printer_gui.py"]
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Database Integration**
|
||||
- Store label history
|
||||
- Batch printing from CSV
|
||||
|
||||
2. **Label Templates**
|
||||
- Multiple label formats
|
||||
- Custom field layouts
|
||||
|
||||
3. **Advanced Features**
|
||||
- QR code support
|
||||
- Image/logo inclusion
|
||||
- Multi-language support
|
||||
|
||||
4. **Mobile Integration**
|
||||
- REST API server
|
||||
- Web interface
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** February 4, 2026
|
||||
**Version:** 1.0
|
||||
**Status:** Production Ready
|
||||
Reference in New Issue
Block a user