树莓派多菜单自动化程序整合可见倒计时计时器求助
Hey there! I see you've got your menu system all set up for your Raspberry Pi automation program—just need to nail that countdown timer that runs alongside your selected mode's infinite loop. Let's break down how to integrate this smoothly without blocking your Tkinter interface.
The main issue with your previous attempts (like while/for loops or separate timer windows) is that Tkinter relies on its main loop to update the UI. Blocking functions like time.sleep() or infinite loops will freeze your interface, and separate window classes don't play nicely with your existing main window setup. We'll use Tkinter's built-in after() method to handle the countdown and mode looping without blocking.
Here's your fully integrated code with the countdown timer working as expected:
import tkinter as tk import os # Set up display for Raspberry Pi (keep your existing logic) if os.environ.get('DISPLAY', '') == '': print('No display found. Using :0.0') os.environ['DISPLAY'] = ':0.0' # Global variables to track state running_mode = None remaining_time = 60 # Set your desired countdown duration here timer_label = None after_id = None # To track the ongoing after() task def mode1(): global running_mode, remaining_time, after_id # Cancel any existing timer if switching modes if after_id: master.after_cancel(after_id) running_mode = "mode1" remaining_time = 60 update_timer() def mode2(): global running_mode, remaining_time, after_id if after_id: master.after_cancel(after_id) running_mode = "mode2" remaining_time = 60 update_timer() def mode3(): global running_mode, remaining_time, after_id if after_id: master.after_cancel(after_id) running_mode = "mode3" remaining_time = 60 update_timer() def update_timer(): global remaining_time, after_id, running_mode if running_mode is None: # No mode selected, reset timer display timer_label.config(text="--") return # Update the timer display timer_label.config(text=f"{remaining_time}s") if remaining_time <= 0: # Execute the selected mode's actions if running_mode == "mode1": print("Executing Mode 1 actions...") # Add your Mode 1 logic here # Example: os.system('play -nq -t alsa synth {} sine {}'.format(0.5, 440)) elif running_mode == "mode2": print("Executing Mode 2 actions...") # Add your Mode 2 logic here elif running_mode == "mode3": print("Executing Mode 3 actions...") # Add your Mode 3 logic here # Reset countdown for next cycle remaining_time = 60 else: remaining_time -= 1 # Schedule the next update (1 second later) after_id = master.after(1000, update_timer) def quit_program(): global after_id # Cancel any ongoing timer task before quitting if after_id: master.after_cancel(after_id) master.destroy() # Set up the main window master = tk.Tk() master.attributes('-fullscreen', True) master.title("Automation Controller") master.geometry("800x480") # Menu label label1 = tk.Label(master, text='Choose Mode', font=('Arial', 30)) label1.pack(pady=20) # Mode selection frame switch_frame = tk.Frame(master) switch_frame.pack(pady=10) switch_variable = tk.StringVar() # Mode buttons m1_button = tk.Radiobutton( switch_frame, selectcolor="green", text="Mode 1", variable=switch_variable, indicatoron=False, value="m1", width=20, height=10, command=mode1 ) m2_button = tk.Radiobutton( switch_frame, selectcolor="green", text="Mode 2", variable=switch_variable, indicatoron=False, value="m2", width=20, height=10, command=mode2 ) m3_button = tk.Radiobutton( switch_frame, selectcolor="green", text="Mode 3", variable=switch_variable, indicatoron=False, value="m3", width=20, height=10, command=mode3 ) off_button = tk.Radiobutton( switch_frame, bg="red", text="Off", variable=switch_variable, indicatoron=False, value="off", width=20, command=quit_program ) # Arrange buttons m1_button.pack(side="left", padx=5) m2_button.pack(side="left", padx=5) m3_button.pack(side="left", padx=5) off_button.pack(side="bottom", pady=20) # Timer display timertext = tk.Label(master, text="Next execution in:", font=('Arial', 16)) timertext.place(x=10, y=150) timer_label = tk.Label(master, text="--", font=('Arial', 16)) timer_label.place(x=200, y=150) master.mainloop()
Key Changes & Explanations:
- Global State Tracking: We use
running_modeto track which mode is active,remaining_timefor the countdown, andafter_idto manage the ongoing timer task (so we can cancel it when switching modes or quitting). after()Method: Instead of blocking loops,master.after(1000, update_timer)schedules the timer to update every 1000ms (1 second). This lets Tkinter keep updating the UI while the timer runs.- Mode Switching: When you select a new mode, we cancel the existing timer task first to prevent multiple timers running at once, then initialize the new mode and restart the countdown.
- No Blocking Calls: We removed
time.sleep()because it freezes the UI. If you need delays in your mode actions, usemaster.after()instead ofsleep. - Clean Quit: The quit function cancels the timer task before closing the window to avoid leftover background processes.
This setup will keep your selected mode running in an infinite cycle (executing every 60 seconds) while displaying a live countdown on your main window. The UI stays responsive, and switching modes or quitting works smoothly.
内容的提问来源于stack exchange,提问作者John Boudouris

