0

I created a program used by several users via a hosting system.

The purpose of this program is when a user A click on the button change value, the buttons Color change and Generate text change state ( normal to disable) instantly. The users B must see the changement when they click on the tab 1 without restarting the program. The users don't have to restart the program to see the change. But here, my code works but the users have to restart the program to see the change made by other users... I don't want that. Is there any solution?

Thank you

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()

query = "SELECT var FROM state WHERE id=1"
c.execute( query )
var = c.fetchall()[0][0]

tab = ttk.Notebook( root )  # create notebook
tab.pack( expand = True, fill = tk.BOTH )


def changevalue() :
    global var
    query = "SELECT var FROM state WHERE id=1"
    c.execute( query )
    var = c.fetchall()[0][0]

    if var == 1 :
        query = "UPDATE state SET var=0 WHERE id=1"
        conn.execute( query )
        conn.commit()
        button_1['state'] = 'normal'
        button_2['state'] = 'normal'

    if var == 0 :
        query = "UPDATE state SET var=1 WHERE id=1"
        conn.execute( query )
        conn.commit()
        button_1['state'] = 'disabled'
        button_2['state'] = 'disabled'


# create Frames for tab

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

tab.add( frame1, text = 'Mytab1' )
tab.add( frame2, text = 'Mytab2' )
tab.add( frame3, text = 'Mytab3' )

# Button in each tab
button_1 = Button( frame1, text = "Color change" ).pack()
button_2 = Button( frame2, text = "Generate text" ).pack()
button_3 = Button( frame3, text = "change value", command = changevalue ).pack()

if var == 1 :
    button_1 = Button( frame1, text = "Color change", state = 'disabled' )
    button_2 = Button( frame2, text = "Generate text", state = 'disabled' )
else :
    button_1 = Button( frame1, text = "Color change", state = 'normal' )
    button_2 = Button( frame2, text = "Generate text", state = 'normal' )
root.mainloop()
Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
Béa
  • 101
  • 2
  • 9
  • Create a function called `scheduler` and then inside it say `root.after(5000,changevalue)`. This will keep running the function every 5 second. Also make a initial call to the function. – Delrius Euphoria Aug 30 '21 at 10:14
  • Please read [PEP 8](https://www.python.org/dev/peps/pep-0008/). It isn't recommented that you have that many white spaces. – TheLizzard Aug 30 '21 at 10:27
  • Also why do you create 2 `button_1`s and 2 `nutton_2`s? [This](https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name) might also help – TheLizzard Aug 30 '21 at 10:28
  • @TheLizzard if you mention pep on whitespaces, could have also mentioned that importing everything especially in this case is a pretty horrible idea. for the OP: don't import everything from a module (don't use `*` when importing) it can and in this case it probably will cause issues because both modules have some similar class names, also you already `import tkinter as tk` and `from tkinter import ttk` so use those aliases accordingly as you for the majority of code already do – Matiiss Aug 30 '21 at 12:28
  • @Matiiss Most people don't follow the *don't import \** rule so I just gave up telling people. I still never use *from ... import \** but there are too many people that use it to try changing their behaviour. – TheLizzard Aug 30 '21 at 12:56

1 Answers1

1

Since you have used sqlite3 table to share the state across processes, you should check the table and update the state of the buttons periodically using after().

Below is a modified code:

import tkinter as tk
from tkinter import ttk
import sqlite3

conn = sqlite3.connect("/database")
c = conn.cursor()

def get_value():
    c.execute("SELECT var FROM state WHERE id = 1")
    return c.fetchone()[0]

def change_value():
    c.execute("UPDATE state SET var = 1 - var WHERE id = 1")
    conn.commit()

def check_value():
    state = 'disabled' if get_value() == 1 else 'normal'
    button_1.config(state=state)
    button_2.config(state=state)
    root.after(100, check_value)

root = tk.Tk()

tab = ttk.Notebook(root)
tab.pack(fill='both', expand=1)

frame1 = ttk.Frame(tab)
frame2 = ttk.Frame(tab)
frame3 = ttk.Frame(tab)

tab.add(frame1, text='Mytab1')
tab.add(frame2, text='Mytab2')
tab.add(frame3, text='Mytab3')

button_1 = ttk.Button(frame1, text='Color change')
button_1.pack()

button_2 = ttk.Button(frame2, text='Generate text')
button_2.pack()

ttk.Button(frame3, text='Change value', command=change_value).pack()

check_value() # check value and update state of buttons periodically
root.mainloop()

Note that:

  • better to avoid using from xxx import *
  • you don't need to call .pack() on those frames
  • you should split button_1 = Button(...).pack() into two lines, same applies on button_2
acw1668
  • 40,144
  • 5
  • 22
  • 34