| @@ -414,6 +414,62 @@ def send_image_to_label_printer(printer_name: str, pil_image: "Image.Image") -> | |||
| pass | |||
| def run_dataflex_continuous_print( | |||
| root: tk.Tk, | |||
| ip: str, | |||
| port: int, | |||
| zpl: str, | |||
| label_text: str, | |||
| set_status_message: Callable[[str, bool], None], | |||
| ) -> None: | |||
| """ | |||
| Run DataFlex continuous print (up to 100) in a background thread. | |||
| Shows a small window with "已列印: N" and a 停止 button; user can stop anytime. | |||
| """ | |||
| stop_event = threading.Event() | |||
| win = tk.Toplevel(root) | |||
| win.title("打袋機 連續列印") | |||
| win.geometry("320x140") | |||
| win.transient(root) | |||
| win.configure(bg=BG_TOP) | |||
| tk.Label(win, text="連續列印中,按「停止」結束", font=get_font(FONT_SIZE), bg=BG_TOP).pack(pady=(12, 4)) | |||
| count_lbl = tk.Label(win, text="已列印: 0", font=get_font(FONT_SIZE), bg=BG_TOP) | |||
| count_lbl.pack(pady=4) | |||
| def on_stop(): | |||
| stop_event.set() | |||
| ttk.Button(win, text="停止", command=on_stop, width=12).pack(pady=8) | |||
| win.protocol("WM_DELETE_WINDOW", lambda: (stop_event.set(), win.destroy())) | |||
| def worker(): | |||
| sent = 0 | |||
| try: | |||
| for _ in range(100): | |||
| if stop_event.is_set(): | |||
| break | |||
| send_zpl_to_dataflex(ip, port, zpl) | |||
| sent += 1 | |||
| root.after(0, lambda s=sent: count_lbl.configure(text=f"已列印: {s}")) | |||
| if stop_event.is_set(): | |||
| break | |||
| time.sleep(2) | |||
| except ConnectionRefusedError: | |||
| root.after(0, lambda: set_status_message(f"無法連線至 {ip}:{port},請確認印表機已開機且 IP 正確。", is_error=True)) | |||
| except socket.timeout: | |||
| root.after(0, lambda: set_status_message(f"連線逾時 ({ip}:{port}),請檢查網路與連接埠。", is_error=True)) | |||
| except OSError as err: | |||
| root.after(0, lambda e=err: set_status_message(f"列印失敗:{e}", is_error=True)) | |||
| else: | |||
| if stop_event.is_set(): | |||
| root.after(0, lambda: set_status_message(f"已送出列印:批次 {label_text} x {sent} 張 (已停止)", is_error=False)) | |||
| else: | |||
| root.after(0, lambda: set_status_message(f"已送出列印:批次 {label_text} x {sent} 張 (連續完成)", is_error=False)) | |||
| root.after(0, win.destroy) | |||
| threading.Thread(target=worker, daemon=True).start() | |||
| def send_zpl_to_dataflex(ip: str, port: int, zpl: str) -> None: | |||
| """Send ZPL to DataFlex printer via TCP. Raises on connection/send error.""" | |||
| sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |||
| @@ -1246,21 +1302,23 @@ def main() -> None: | |||
| stock_in_line_id=stock_in_line_id, | |||
| lot_no=lot_no, | |||
| ) | |||
| n = 100 if count == -1 else count | |||
| label_text = (lot_no or b).strip() | |||
| try: | |||
| for i in range(n): | |||
| send_zpl_to_dataflex(ip, port, zpl) | |||
| if i < n - 1: | |||
| time.sleep(2) | |||
| msg = f"已送出列印:批次 {label_text} x {n} 張" if count != -1 else f"已送出列印:批次 {label_text} x {n} 張 (連續)" | |||
| set_status_message(msg, is_error=False) | |||
| except ConnectionRefusedError: | |||
| set_status_message(f"無法連線至 {ip}:{port},請確認印表機已開機且 IP 正確。", is_error=True) | |||
| except socket.timeout: | |||
| set_status_message(f"連線逾時 ({ip}:{port}),請檢查網路與連接埠。", is_error=True) | |||
| except OSError as err: | |||
| set_status_message(f"列印失敗:{err}", is_error=True) | |||
| if count == -1: | |||
| run_dataflex_continuous_print(root, ip, port, zpl, label_text, set_status_message) | |||
| else: | |||
| n = count | |||
| try: | |||
| for i in range(n): | |||
| send_zpl_to_dataflex(ip, port, zpl) | |||
| if i < n - 1: | |||
| time.sleep(2) | |||
| set_status_message(f"已送出列印:批次 {label_text} x {n} 張", is_error=False) | |||
| except ConnectionRefusedError: | |||
| set_status_message(f"無法連線至 {ip}:{port},請確認印表機已開機且 IP 正確。", is_error=True) | |||
| except socket.timeout: | |||
| set_status_message(f"連線逾時 ({ip}:{port}),請檢查網路與連接埠。", is_error=True) | |||
| except OSError as err: | |||
| set_status_message(f"列印失敗:{err}", is_error=True) | |||
| elif printer_var.get() == "標簽機": | |||
| com = (settings.get("label_com") or "").strip() | |||
| if not com: | |||