Home > front end >  Tkinter - Cannot get radiobutton values after clicking a button which is not set by default
Tkinter - Cannot get radiobutton values after clicking a button which is not set by default

Time:12-10

I'm trying to read the content from a CSV file and create a setup window in which I can set new values in the radiobuttons and save them. For this, I've created a loop which creates N-1 rows from a CSV whose content is:

Row0;T
Row1;M
Row2;-
Row3;C
Row4;O

The problem is than when I try to get a new value by clicking a different radio button, I don't get that value. I've tried using the methods select, invoke, creating a function which prints what's selected, but nothing returns the correct value.

I think the problem is between lines 44 and 88

import pandas as pd
import os
from tkinter import * 
import tkinter as tk
from tkinter import ttk
import platform

class Application(ttk.Frame):
    def __init__(self):
        root = Tk()
        root.geometry("555x490")
        root.resizable(0,0)
        self.notebook = ttk.Notebook(root)
        self.notebook.grid(sticky='news')
        self.notebook.pressed_index = None
        self.container = Frame(self.notebook)
        self.container.grid(sticky='news')
        self.notebook.add(self.container)

        self.canvas = Canvas(self.container, width=530, height=470)
        self.scroll = Scrollbar(self.container, command=self.canvas.yview)
        self.canvas.config(yscrollcommand=self.scroll.set, scrollregion=(0,0,100,1000))
        self.canvas.grid(row=0, column=0, sticky="news")
        self.scroll.grid(row=0, column=1, sticky='ns')

        self.frame = Frame(self.canvas, width=555, height=1000)
        self.canvas_window = self.canvas.create_window(555, 500, window=self.frame)

        self.container.bind("<Configure>", self.onFrameConfigure)                       #bind an event whenever the size of the container frame changes.
        self.canvas.bind("<Configure>", self.onCanvasConfigure)                       #bind an event whenever the size of the canvas frame changes.
            
        self.container.bind('<Enter>', self.onEnter)                                 # bind wheel events when the cursor enters the control
        self.container.bind('<Leave>', self.onLeave)                                 # unbind wheel events when the cursorl leaves the control

        self.onFrameConfigure(None)                                                 #perform an initial stretch on render, otherwise the self.scroll region has a tiny border until the first resize

        archive = pd.read_csv(os.getcwd() "\\test.csv", sep=';', engine='python')
        y=0
        self.radioInbound = []
        self.radioInbound1 = []
        self.radioInbound2 = []
        self.radioInbound3 = []
        self.radioInbound4 = []
        for self.element in range(len(archive.index)):
            y =20
            # El nombre de cada fila
            self.label = tk.Label(self.frame, text=(str(self.element 1) ' - ' archive.iloc[self.element,0])).grid(column=20, row=y)

            # Radio buttons para seleccionar el valor
            self.radioInbound.append(tk.IntVar())
            #print(self.radioInbound)
            if archive.iloc[self.element,1] == 'M':
                self.radioInbound[self.element].set(1)
            elif archive.iloc[self.element,1] == 'C':
                self.radioInbound[self.element].set(2)
            elif archive.iloc[self.element,1] == 'O':
                self.radioInbound[self.element].set(3)
            else: 
                self.radioInbound[self.element].set(4)
        # Pinta los 4 radiobutton por cada self.elemento existente en el inbound
            self.radioInbound1.append(tk.Radiobutton(self.frame, text='M', variable=self.radioInbound[self.element], value=1, command=self.selected()))
            self.radioInbound1[self.element].grid(column=280,row=y)

            self.radioInbound2.append(tk.Radiobutton(self.frame, text='C', variable=self.radioInbound[self.element], value=2, command=self.selected()))
            self.radioInbound2[self.element].grid(column=310,row=y)

            self.radioInbound3.append(tk.Radiobutton(self.frame, text='O', variable=self.radioInbound[self.element], value=3, command=self.selected()))
            self.radioInbound3[self.element].grid(column=340,row=y)         

            self.radioInbound4.append(tk.Radiobutton(self.frame, text='-', variable=self.radioInbound[self.element], value=4, command=self.selected()))
            self.radioInbound4[self.element].grid(column=370,row=y)
            #print(self.radioInbound1)
            
        # Mira el valor de cada celda para invocar el radiobutton correspondiente
            #if archive.iloc[self.element,1] == 'M':
            #    self.radioInbound1[self.element].select() ##hay que invocar al que esté en cada momento en el archivo csv
            #elif archive.iloc[self.element,1] == 'C':
            #    self.radioInbound2[self.element].select() 
            #elif archive.iloc[self.element,1] == 'O':
            #    self.radioInbound3[self.element].select()
            #else: 
            #    self.radioInbound4[self.element].select()
    
        #print(self.radioInbound)

        root.mainloop()
    def selected(self):
        #print(self.radioInbound[self.element].get())
        pass
        
    def onFrameConfigure(self, event):                                              
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))                 #whenever the size of the frame changes, alter the self.scroll region respectively.

    def onCanvasConfigure(self, event):
        '''Reset the canvas window to encompass inner frame when required'''
        canvas_width = event.width
        self.canvas.itemconfig(self.canvas_window, width = canvas_width)            #whenever the size of the canvas changes alter the window region respectively.

    def onm ouseWheel(self, event):                                                  # cross platform self.scroll wheel event
        if platform.system() == 'Windows':
            self.canvas.yview_scroll(int(-1* (event.delta/120)), "units")
        elif platform.system() == 'Darwin':
            self.canvas.yview_scroll(int(-1 * event.delta), "units")
        else:
            if event.num == 4:
                self.canvas.yview_scroll( -1, "units" )
            elif event.num == 5:
                self.canvas.yview_scroll( 1, "units" )
    
    def onEnter(self, event):                                                       # bind wheel events when the cursor enters the control
        if platform.system() == 'Linux':
            self.canvas.bind_all("<Button-4>", self.onMouseWheel)
            self.canvas.bind_all("<Button-5>", self.onMouseWheel)
        else:
            self.canvas.bind_all("<MouseWheel>", self.onMouseWheel)

    def onLeave(self, event):                                                       # unbind wheel events when the cursorl leaves the control
        if platform.system() == 'Linux':
            self.canvas.unbind_all("<Button-4>")
            self.canvas.unbind_all("<Button-5>")
        else:
            self.canvas.unbind_all("<MouseWheel>")

app = Application()

CodePudding user response:

You have used same instance variable self.element in the for loop of creating those radiobuttons. So after the for loop, self.element will refer to the last item of self.radioInbound.

Actually the instance variable self.element is not necessary. And you need to pass the corresponding index to self.selected() for those radiobuttons using default value of lambda assigned to command option when creating those radiobuttons:

### actually don't need to inherited from ttk.Frame ###
#class Application(ttk.Frame):
class Application:
    def __init__(self):
        ...
        # just use a local variable instead of instance variable
        for idx in range(len(archive.index)):
            y =20
            # El nombre de cada fila
            self.label = tk.Label(self.frame, text=(str(idx 1) ' - ' archive.iloc[idx,0])).grid(column=20, row=y)

            # Radio buttons para seleccionar el valor
            self.radioInbound.append(tk.IntVar())
            #print(self.radioInbound)
            if archive.iloc[idx,1] == 'M':
                self.radioInbound[idx].set(1)
            elif archive.iloc[idx,1] == 'C':
                self.radioInbound[idx].set(2)
            elif archive.iloc[idx,1] == 'O':
                self.radioInbound[idx].set(3)
            else:
                self.radioInbound[idx].set(4)
            # Pinta los 4 radiobutton por cada idxo existente en el inbound
            ### used lambda with argument with default value ###
            self.radioInbound1.append(tk.Radiobutton(self.frame, text='M', variable=self.radioInbound[idx], value=1, command=lambda i=idx:self.selected(i)))
            self.radioInbound1[idx].grid(column=280,row=y)

            self.radioInbound2.append(tk.Radiobutton(self.frame, text='C', variable=self.radioInbound[idx], value=2, command=lambda i=idx:self.selected(i)))
            self.radioInbound2[idx].grid(column=310,row=y)

            self.radioInbound3.append(tk.Radiobutton(self.frame, text='O', variable=self.radioInbound[idx], value=3, command=lambda i=idx:self.selected(i)))
            self.radioInbound3[idx].grid(column=340,row=y)

            self.radioInbound4.append(tk.Radiobutton(self.frame, text='-', variable=self.radioInbound[idx], value=4, command=lambda i=idx:self.selected(i)))
            self.radioInbound4[idx].grid(column=370,row=y)
        ...

    ### added argument idx ###
    def selected(self, idx):
        print(idx, self.radioInbound[idx].get())

    ...
  • Related