如何在Tkinter中实现不同输入设备分别向多显示器的指定Entry控件输入数据?
You can definitely route input from different sources (COM ports, keyboard) to specific Tkinter Entry fields across multiple monitors. Here's a step-by-step breakdown with working code to make it happen:
1. Set Up Tkinter Windows on Multiple Monitors
First, we’ll create two windows and place each on a separate monitor. Using the screeninfo library (install with pip install screeninfo), we can get precise coordinates for each display to position our windows correctly.
import tkinter as tk from screeninfo import get_monitors # Get info about connected monitors monitors = get_monitors() # Create a hidden main root window (Tkinter requires one main instance) root = tk.Tk() root.withdraw() # Window for Monitor 1 win1 = tk.Toplevel(root) win1.title("Monitor 1 (COM3 Input)") win1.geometry(f"400x200+{monitors[0].x}+{monitors[0].y}") entry1 = tk.Entry(win1, font=('Arial', 16)) entry1.pack(pady=20, padx=20, fill=tk.X) # Window for Monitor 2 win2 = tk.Toplevel(root) win2.title("Monitor 2 (COM4 Input)") win2.geometry(f"400x200+{monitors[1].x}+{monitors[1].y}") entry2 = tk.Entry(win2, font=('Arial', 16)) entry2.pack(pady=20, padx=20, fill=tk.X)
2. Handle Serial (COM Port) Input
To read data from COM3 and COM4, we’ll use the pyserial library (install with pip install pyserial). Since serial reads can block the GUI, we’ll run each reader in a separate thread and use a queue to safely pass data to the Tkinter main loop (Tkinter isn’t thread-safe for direct widget updates).
import serial import threading from queue import Queue # Queue to safely transfer serial data to the GUI serial_queue = Queue() def read_serial(port, target_entry): """Read data from a serial port and send it to the queue with its target Entry""" try: # Adjust these settings to match your barcode scanner's configuration ser = serial.Serial( port=port, baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_1, bytesize=serial.EIGHTBITS, timeout=1 ) print(f"Connected to {port} successfully") while True: # Read data (barcode scanners usually send data with a newline terminator) data = ser.readline().decode('utf-8').strip() if data: serial_queue.put((target_entry, data)) except serial.SerialException as e: print(f"Failed to connect to {port}: {str(e)}") finally: if 'ser' in locals() and ser.is_open: ser.close() print(f"Disconnected from {port}") # Start daemon threads for each COM port (they exit when the main program closes) threading.Thread(target=read_serial, args=('COM3', entry1), daemon=True).start() threading.Thread(target=read_serial, args=('COM4', entry2), daemon=True).start()
3. Route Serial Data to Correct Entry Fields
We’ll use Tkinter’s after() method to periodically check the queue and update the corresponding Entry field with incoming serial data:
def process_serial_queue(): """Process incoming serial data and update the target Entry""" while not serial_queue.empty(): target_entry, data = serial_queue.get() # Insert data (uncomment the line below to replace existing text instead of appending) # target_entry.delete(0, tk.END) target_entry.insert(tk.END, data + " ") # Add space between scans for readability # Schedule next check in 100ms root.after(100, process_serial_queue) # Start processing the queue process_serial_queue()
4. Handle Keyboard Input
For keyboard input, Tkinter’s default behavior works perfectly: just click on the Entry field on your desired monitor, and any keyboard input will go directly into it. No extra code is needed for this part!
Full Working Code
Putting it all together, here’s the complete script:
import tkinter as tk from screeninfo import get_monitors import serial import threading from queue import Queue # Get monitor coordinates monitors = get_monitors() # Create hidden main root window root = tk.Tk() root.withdraw() # Monitor 1 window and entry win1 = tk.Toplevel(root) win1.title("Monitor 1 (COM3 Input)") win1.geometry(f"400x200+{monitors[0].x}+{monitors[0].y}") entry1 = tk.Entry(win1, font=('Arial', 16)) entry1.pack(pady=20, padx=20, fill=tk.X) # Monitor 2 window and entry win2 = tk.Toplevel(root) win2.title("Monitor 2 (COM4 Input)") win2.geometry(f"400x200+{monitors[1].x}+{monitors[1].y}") entry2 = tk.Entry(win2, font=('Arial', 16)) entry2.pack(pady=20, padx=20, fill=tk.X) # Serial data queue serial_queue = Queue() def read_serial(port, target_entry): try: ser = serial.Serial( port=port, baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_1, bytesize=serial.EIGHTBITS, timeout=1 ) print(f"Connected to {port}") while True: data = ser.readline().decode('utf-8').strip() if data: serial_queue.put((target_entry, data)) except serial.SerialException as e: print(f"Error with {port}: {str(e)}") finally: if 'ser' in locals() and ser.is_open: ser.close() # Start serial reader threads threading.Thread(target=read_serial, args=('COM3', entry1), daemon=True).start() threading.Thread(target=read_serial, args=('COM4', entry2), daemon=True).start() def process_queue(): while not serial_queue.empty(): entry, data = serial_queue.get() entry.insert(tk.END, data + " ") root.after(100, process_queue) process_queue() # Run the main GUI loop root.mainloop()
Key Notes:
- Serial Settings: Double-check your barcode scanner’s manual to match the baud rate, parity, and other serial parameters—incorrect settings will cause failed reads.
- Thread Safety: Using a queue ensures we don’t update Tkinter widgets directly from threads, which can cause crashes or unexpected behavior.
- Keyboard Focus: Clicking an Entry field gives it focus, so keyboard input will go to that field automatically.
内容的提问来源于stack exchange,提问作者evanmars

