2

My problem is that I have a simultaneous reaction on clicking a check box or radio button in different objects. Once I click on a check box in object A and let's say check it, same check box in objects B,C and D will be checked as well.

I have a class that builds a set of widgets including some check boxes and radio buttons inside a tk.Frame. I create 4 objects of this class with slightly different parameters (position, background color, title label content). For each of those objects a parent is the same frame that is previously added to one of ttk.Notebook tabs. To be exact this is a parent only for the main tk.Frame in each object and rest of the wdgets use this main frame as a parent.

I have already tried experimenting with adding or removing "self." in different places but it all looks like if for tkinter library those widgets are one and the same even though they are instanced in different objects.

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from sync_tab import *


WINDOW_WIDTH = 1100
WINDOW_HEIGHT = 800
SYNC_TAB_BG0 = '#80c1ff'
SYNC_TAB_BG1 = '#60b1ff'
SYNC_TAB_BG2 = '#40a1ff'
SYNC_TAB_BG3 = '#2091ff'


class main_window():
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("ATOX CPRI tester")
        canvas = tk.Canvas(self.window, height=WINDOW_HEIGHT, width=WINDOW_WIDTH)
        canvas.pack()
        self.create_widgets()


        # - - - - - - - - - - - - - - - - - - - - -
        # Tabs
        tabs_pane = ttk.Notebook(self.window)
        #tabs_pane.grid(row=4, column=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=30, pady=4)
        tabs_pane.place(relx=0.05, rely=0.1, relwidth=0.9, relheight=0.8)

        tab1 = tk.Frame(tabs_pane)
        tab2 = tk.Frame(tabs_pane)
        tab3 = tk.Frame(tabs_pane)
        tab4 = tk.Frame(tabs_pane)
        tab5 = tk.Frame(tabs_pane)
        tab6 = tk.Frame(tabs_pane)

        tabs_pane.add(tab1, text=" Synchronisation ", compound=tk.TOP)
        tabs_pane.add(tab2, text=" RX capture ", compound=tk.TOP)
        tabs_pane.add(tab3, text=" CtrlW TX ", compound=tk.TOP)
        tabs_pane.add(tab4, text=" FBER ", compound=tk.TOP)
        tabs_pane.add(tab5, text=" Mask TX ", compound=tk.TOP)
        tabs_pane.add(tab6, text=" Alarms & Errors injection", compound=tk.TOP)

        self.sync_tab0 = SyncTab(tab1, SYNC_TAB_BG0, 0, 0, 'A')
        self.sync_tab1 = SyncTab(tab1, SYNC_TAB_BG1, 1, 0, 'B')
        self.sync_tab2 = SyncTab(tab1, SYNC_TAB_BG2, 0, 1, 'C')
        self.sync_tab3 = SyncTab(tab1, SYNC_TAB_BG3, 1, 1, 'D')

        # - - - - - - - - - - - - - - - - - - - - -


# Create full GUI 
program = main_window()

# Start the GUI in loop
program.window.mainloop()

Second file - sync_tab.py:

import tkinter as tk
from tkinter import ttk


class SyncTab:
    def __init__(self, parent, bg_color, xpos, ypos, ch_name):
        self.tab_frame = tk.Frame(parent, bg=bg_color)
        self.tab_frame.place(relx=xpos*0.5, rely=ypos*0.5, relwidth=0.5, relheight=0.5)

        channel_name_label = tk.Label(self.tab_frame, text="Channel "+ch_name, bg=bg_color)
        channel_name_label.place(x=20, y=5, width=60, height=17)

        # just one of the check boxes
        bfn_random = tk.Checkbutton(self.tab_frame, text="Start at random", bg=bg_color)
        bfn_random.deselect()
        bfn_random.place(x=145, y=195, width=120, height=20)


        # radio buttons
        self.master_slave = 0

        self.master_button = tk.Radiobutton(self.tab_frame, text="Master", bg=bg_color, variable=self.master_slave, value=0)
        self.master_button.select()
        self.master_button.place(x=220, y=255, width=60, height=20)

        self.slave_button = tk.Radiobutton(self.tab_frame, text="Slave", bg=bg_color, variable=self.master_slave, value=1)
        self.slave_button.deselect()
        self.slave_button.place(x=280, y=255, width=60, height=20)

Any ideas where I do not get how those things work? I was hoping I can easily get 4 separate control sets.

DStage
  • 33
  • 2

1 Answers1

1

If you want to control a checkbox and be able to get its value, you have to create a control variable and pass it as the parameter variable when you create the Checkbutton.

Control variables in Tkinter accept only Tkinter types, and not a python builtin bool. You can check this doc to see what types you can use for the different kind of widget.
Here we are using tk.IntVar() :

class SyncTab:
    def __init__(self, parent, bg_color, xpos, ypos, ch_name):
        self.tab_frame = tk.Frame(parent, bg=bg_color)
        self.tab_frame.place(relx=xpos*0.5, rely=ypos*0.5, relwidth=0.5, relheight=0.5)

        channel_name_label = tk.Label(self.tab_frame, text="Channel "+ch_name, bg=bg_color)
        channel_name_label.place(x=20, y=5, width=60, height=17)

        # just one of the check boxes
        self.check_var = tk.IntVar()
        bfn_random = tk.Checkbutton(self.tab_frame, variable=self.check_var , text="Start at random", bg=bg_color)

        bfn_random.deselect()
        bfn_random.place(x=145, y=195, width=120, height=20)

Then to get the value, you can simply call :

self.check_var.get()  # it returns 0 or 1, easily converted to a boolean
PRMoureu
  • 12,817
  • 6
  • 38
  • 48
  • 1
    Oh man, you're a genius :D If you look closely to my code you'll find that I did actually use a variable in radio buttons. This is still a work in progress and I was focused on a visual side rather than the functionality so I thought I will get to the variables and commands later. It did not work for radio buttons either as I did not realize this variable has to be of tk.IntVar() type! That solves the problem for both check boxes and radio buttons. Thanks again! – DStage Sep 01 '19 at 17:55
  • 1
    You might want to mention that the value given to the `variable` option must be an instance of a tkinter variable object (IntVar, StringVar, etc) and not a normal python variable – Bryan Oakley Sep 01 '19 at 19:16