Tkinter多用户托管程序按钮状态跨用户实时同步解决方案求助
Great question! The core issue here is that your current setup only checks the database state on startup and when the change value button is clicked—other users' instances have no way to automatically know when the database state changes. Let's fix this step by step:
First, Fix the Button Assignment Bug
Your current code has a critical issue: when you do button_1 = Button(...).pack(), the variable button_1 gets assigned the return value of pack() (which is None), not the actual Button widget. Later redefining button_1 creates a new Button but doesn't display it. Let's correct this:
# Create buttons first, then pack them separately button_1 = Button(frame1, text="Color change") button_1.pack() button_2 = Button(frame2, text="Generate text") button_2.pack() button_3 = Button(frame3, text="change value", command=changevalue) button_3.pack()
Add a Function to Refresh Button State from Database
Create a reusable function that fetches the latest var value from the database and updates the button states. This will be called whenever we need to sync the UI with the database:
def refresh_button_states(): global var # Fetch latest state from database c.execute("SELECT var FROM state WHERE id=1") var = c.fetchall()[0][0] # Update button states new_state = 'disabled' if var == 1 else 'normal' button_1['state'] = new_state button_2['state'] = new_state
Sync State When Tabs Are Changed
Add an event handler for the Notebook tab change event. This way, when any user switches to Mytab1 or Mytab2, the button states will immediately refresh from the database:
def on_tab_change(event): refresh_button_states() # Bind the tab change event tab.bind("<<NotebookTabChanged>>", on_tab_change)
Add a Periodic Refresh Timer
To ensure state updates are reflected even if the user doesn't switch tabs, add a recurring timer that calls refresh_button_states() at regular intervals (e.g., every 1000ms = 1 second):
def periodic_refresh(): refresh_button_states() # Schedule the next refresh after 1 second root.after(1000, periodic_refresh) # Start the periodic refresh when the app launches periodic_refresh()
Update the changevalue Function
Simplify the changevalue function to reuse the refresh_button_states() function instead of duplicating logic:
def changevalue(): # Toggle the value in the database c.execute("UPDATE state SET var = 1 - var WHERE id=1") conn.commit() # Refresh the UI to reflect the new state refresh_button_states()
Full Modified Code
Putting it all together, here's the complete working code:
from tkinter import * import tkinter as tk from tkinter import ttk from tkinter.ttk import * import sqlite3 root = Tk() conn = sqlite3.connect('/database') c = conn.cursor() # Ensure the state table exists (add this if not already created) c.execute("CREATE TABLE IF NOT EXISTS state (id INTEGER PRIMARY KEY, var INTEGER)") # Initialize the state if it doesn't exist c.execute("INSERT OR IGNORE INTO state (id, var) VALUES (1, 0)") conn.commit() tab = ttk.Notebook(root) tab.pack(expand=True, fill=tk.BOTH) def refresh_button_states(): global var c.execute("SELECT var FROM state WHERE id=1") var = c.fetchall()[0][0] new_state = 'disabled' if var == 1 else 'normal' button_1['state'] = new_state button_2['state'] = new_state def changevalue(): c.execute("UPDATE state SET var = 1 - var WHERE id=1") conn.commit() refresh_button_states() def on_tab_change(event): refresh_button_states() def periodic_refresh(): refresh_button_states() root.after(1000, periodic_refresh) # Create Frames for tabs frame1 = ttk.Frame(tab) frame1.pack(fill="both") frame2 = ttk.Frame(tab) frame2.pack(fill="both") frame3 = ttk.Frame(tab) frame3.pack(fill="both") # Add frames to notebook tab.add(frame1, text='Mytab1') tab.add(frame2, text='Mytab2') tab.add(frame3, text='Mytab3') # Create buttons correctly button_1 = Button(frame1, text="Color change") button_1.pack() button_2 = Button(frame2, text="Generate text") button_2.pack() button_3 = Button(frame3, text="change value", command=changevalue) button_3.pack() # Bind tab change event tab.bind("<<NotebookTabChanged>>", on_tab_change) # Initial state refresh and start periodic updates refresh_button_states() periodic_refresh() root.mainloop()
How This Works
- Tab Change Sync: When any user switches tabs, the app immediately pulls the latest state from the database and updates the buttons.
- Periodic Refresh: Even if the user stays on a single tab, the app checks the database every second to pick up changes made by other users.
- Reusable Logic: The
refresh_button_states()function ensures we don't duplicate code when updating states.
Now, when User A clicks "change value", their local UI updates immediately, and any other user will see the button state update either when they switch tabs or within 1 second (thanks to the periodic refresh). No restarts required!
内容的提问来源于stack exchange,提问作者Béa

