Как использовать несколько Radiobutton в python tkinter? - PullRequest
0 голосов
/ 30 мая 2020

Я достаточно долго здесь боролся. Мне нужно какое-то направление.

Я пытаюсь сделать генератор байтов GUI. 95% работает нормально, но я не могу включать / выключать переключатели после того, как щелкаю их.

Я создал 64 кнопки в al oop, присвоил значения переменной и создал функцию обратного вызова.

В функции обратного вызова, когда я нажимаю кнопку, она затем вызывает update_array, который обновляет список и массив текстовых байтов. Значения переключаются от 0 до 1 - вперед и назад. Работает нормально, но кнопки не горят / не подсвечиваются. Я даже не уверен, следует ли мне использовать другой тип кнопки.

Конечным результатом является массив кнопок, и массив байтов должен показывать тот же шаблон.

Я также пытаюсь чтобы узнать идентичность кнопки, которую я нажимаю. (Btn_XY) Я знаю, когда нажимаю Btn_44, но как мне узнать это с помощью tkinter?

Запуск python3 .8 на MacBook Pro версии 10.15.5

GUI Вкладка 1 показывает кнопки и карту байтов.

Функция обратного вызова - def btnCall (self)

Кнопки создаются в строках с 280 по 293. Функции def btnCall и def update_array, похоже, работают нормально. Даже если они неполные - та часть, которая там есть, работает. Я могу сохранить список позже в глобальный список.

Распечатать операторы во время процесса шоу и отладки.

Пожалуйста, предложения ???? Заранее спасибо!

import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import messagebox as msg


class CHAR_GEN():
def __init__(self):         # Initializer method
    # Create instance
    self.win = tk.Tk()   

    # Add a title       
    self.win.title("Character Generator GUI")      
    self.create_widgets()

    #create the byte array for the byte map
    self.create_byte_array()

# Modified Button Click Function
def click_me(self): 
    self.action.configure(text='Hello ' + self.name.get() + ' ' + 
                     self.number_chosen.get())


# GUI Callback  
def checkCallback(self, *ignored_args):
    # only enable one checkbutton
    if self.chVarUn.get(): self.check3.configure(state='disabled')
    else:                  self.check3.configure(state='normal')
    if self.chVarEn.get(): self.check2.configure(state='disabled')
    else:                  self.check2.configure(state='normal') 

def create_byte_array(self):
    print('Create the array')
    self.byte_array = []
    for row in range(8):
        self.byte_array.append([])
        for col in range(8):
            self.byte_array[row].append(0)

    #############
    self.byte_box.insert(tk.END, '\n\n byte_array = { \n')
    print(self.byte_array)
    for row  in range(8):
        #self.byte_array[row].append(0)
        print(''.join(map(str, self.byte_array[row])))
        msg = ''.join(map(str, self.byte_array[row]))

        #############
        self.byte_box.insert(tk.END, '     ')
        self.byte_box.insert(tk.END, msg)
        self.byte_box.insert(tk.END, '\n')
    self.byte_box.insert(tk.END, '              }\n')

    #############
    #############
    return self.byte_array

########################################################
#   The byte_array is just a structure. We will print a 
#   text representation of it in the text box and 
#   refresh it every time the update or create fuction is called
########################################################

def update_array(self,row,col):
    print('in update array row and col passed == {} {}'.format(row,col))

    print('the variable self.byte_array[row][col] == {}'.format(self.byte_array[row][col]))

    print('in update_array this is where we toggle the bit in the list') 

    if self.byte_array[row][col] == 0:
        self.byte_array[row][col] = 1
    else:
        self.byte_array[row][col] = 0

    #############
    #############
    #############
    print('ready to print to text box')
    print(self.byte_array)
    # delete the text in the box
    self.byte_box.delete('1.0',tk.END)
    #redraw
    self.byte_box.insert(tk.END, '\n\n byte_array = { \n')

    for row  in range(8):
        print(''.join(map(str, self.byte_array[row])))
        msg = ''.join(map(str, self.byte_array[row]))

        #############
        self.byte_box.insert(tk.END, '     ')
        self.byte_box.insert(tk.END, msg)
        self.byte_box.insert(tk.END, '\n')
    self.byte_box.insert(tk.END, '              }\n')
    #############
    #############
    #############
    #############

#####################################
#####################################
#    Build a list for all the radVars
#####################################
# Radiobutton Callback
def btnCall(self):
    print('entered btnCall')
    print('this is where we clicked the button')
    btnVar = self.radVar.get()


    print('in btnCall btnVar == {}'.format(btnVar))
    ###
    s = str(btnVar)
    #print(s)
    if len(s) == 1:
        xpos = str(0)
        ypos = s
    else:
        xpos = s[-2]
        ypos = s[-1]
    print('in btnCall xpos,ypos == {}{}'.format(xpos,ypos))

    print('leaving btnCall() and calling self.update_array')
    self.update_array(int(xpos),int(ypos))

#####################################
#####################################
#####################################
# reset the pixel map
def reset_map(self):
    #delete map
    #turn off all the radio buttons
    #create map
    pass

def invert_map(self):
    #delete map
    #toggle the bits in the map
    #create map
    pass



# Exit GUI cleanly
def _quit(self):
    self.win.quit()
    self.win.destroy()
    exit() 

#####################################################################################       
def create_widgets(self):    
    tabControl = ttk.Notebook(self.win)          # Create Tab Control

    tab1 = ttk.Frame(tabControl)            # Add a second tab
    tabControl.add(tab1, text='Tab 1')      # Make second tab visible
    tab2 = ttk.Frame(tabControl)            # Create a tab 
    tabControl.add(tab2, text='Tab 2')      # Add the tab

    tabControl.pack(expand=1, fill="both")  # Pack to make visible



    # Top of Tab Control 2 -------------------------------------------

    # We are creating a container frame to hold all other widgets -- Tab2
    self.pixmap = ttk.LabelFrame(tab1, text=' Pixels')
    self.pixmap.grid(column=0, row=0, padx=8, pady=4)


    self.map_frame = ttk.LabelFrame(self.pixmap, text=' Pixel Map ')
    self.map_frame.grid(column=0, row=2, sticky='W', columnspan=2)        

    ## Add a textbox frame to hold the character array
    self.byte_frame = ttk.LabelFrame(tab1, text=' Bytes  ')
    self.byte_frame.grid(column=1, row=0, sticky='W', columnspan=2)        

    # Creating three checkbuttons
    self.chVarDis = tk.IntVar()
    self.check1 = tk.Checkbutton(self.pixmap, text="Disabled", variable=self.chVarDis, state='disabled')
    self.check1.select()
    self.check1.grid(column=0, row=0, sticky=tk.W)                   
   # 
    self.chVarUn = tk.IntVar()
    self.check2 = tk.Checkbutton(self.pixmap, text="Junk", variable=self.chVarUn)
    self.check2.deselect()
    self.check2.grid(column=1, row=0, sticky=tk.W)                   
   # 
    self.chVarEn = tk.IntVar()
    self.check3 = tk.Checkbutton(self.pixmap, text="Save", variable=self.chVarEn)
    self.check3.deselect()
    self.check3.grid(column=2, row=0, sticky=tk.W)                     

    # trace the state of the two checkbuttons
    self.chVarUn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())    
    print('self.chVarUn == {}'.format(self.chVarUn))
    self.chVarEn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())   
    #print('self.chVarEn == {}'.format(self.chVarEn))

    #####################################################################
    #
    #         create a text box to hold the bytes
    #
    #####################################################################

    self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
    self.byte_box.grid(column=0, row=0, sticky=tk.E)
    #self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
    #self.byte_box.insert(tk.END, '\n\n byte_array = { \n')

    # First, we change our Radiobutton global variables into a list

    # create three Radiobuttons using one variable
    self.radVar = tk.IntVar()

    # Next we are selecting a non-existing index value for radVar
    self.radVar.set(99)                                 

    # Now we are creating all three Radiobutton widgets within one loop
    # create a temp dictionary to build the radio buttones ????????



    ##########################
    #          build a function to create 64 of these radio buttons.
    #          later !!!
    ##########################

    #####################################################################
    #
    #         create a text box to hold the bytes
    #
    #####################################################################

    self. byte_box = tk.Text(self.byte_frame, height=12, width=20)
    self.byte_box.grid(column=0, row=0, sticky=tk.E)
    #self.byte_box.insert(tk.END, "Just a text Widget\nin two lines\n")
    #self.byte_box.insert(tk.END, '\n\n byte_array = { \n')



    # create 64 Radiobuttons using one variable
    self.radVar = tk.IntVar()

    # Next we are selecting a non-existing index value for radVar
    self.radVar.set(99)                                 

    # Now we are creating all three Radiobutton widgets within one loop
    # create a temp dictionary to build the radio buttones



    ##########################
    #          build a function to create 64 of these radio buttons.
    #          later !!!
    ##########################
    ##########################
    # here are all the radio buttons
    ##########################
    ##########################
    ##########################
    '''
         Here we will use a double loop to greate the radio buttons
         and later the variables. The numbers in the loop will
         be appended to Btn_XY where XY is the row and column.

         Also use the numbers for naming radVar for each button
         Also use the numbers for naming row and column
    '''
    ##########################
    ##########################
    bname = "Btn_"
    for x in range(8):
        for y in range(8):
            #print(x,y)
            #print(bname + str(x) + str(y))
            cr_name = bname + str(x) + str(y)

            print('in creation loop cr_name == {}'.format(cr_name))
            ######
            # need to create a simple SMALL box above eache of these 
            # to toggle on and off

            self.cr_name = tk.Radiobutton(self.map_frame, variable=self.radVar, val = int(str(x)+str(y)), command=self.btnCall)
            self.cr_name.grid(column=y+1, row=x+1, sticky=tk.W)
    ##########################

   #  create another frame container
    ###############################################################
    ###############################################################


    # Create a container to hold misc buttons
    misc_buttons_frame = ttk.LabelFrame(self.pixmap, text=' Modify ')
    misc_buttons_frame.grid(column=0, row=3, sticky='W', columnspan=2)        

    # create another frame container
    ###############################################################
    ###############################################################
    ###############################################################
    # Add Buttons for reset and invert commands
    ttk.Button(misc_buttons_frame, text=" Reset Map", command=self.reset_map).grid(column=0, row=0, sticky='W')  
    ttk.Button(misc_buttons_frame, text=" Invert Map  ", command=self.invert_map).grid(column=1, row=0, sticky='W')  
    # 
    for child in misc_buttons_frame.winfo_children():  
        child.grid_configure(padx=2, pady=2) 
    # 
    for child in self.pixmap.winfo_children():  
        child.grid_configure(padx=8, pady=2) 


    # Creating a Menu Bar
    menu_bar = Menu(self.win)
    self.win.config(menu=menu_bar)

    # Add menu items
    file_menu = Menu(menu_bar, tearoff=0)
    file_menu.add_command(label="New")
    file_menu.add_separator()
    file_menu.add_command(label="Exit", command=self._quit)
    menu_bar.add_cascade(label="File", menu=file_menu)

    # Display a Message Box

    # Add another Menu to the Menu Bar and an item
    help_menu = Menu(menu_bar, tearoff=0)
    menu_bar.add_cascade(label="Help", menu=help_menu)

    # Change the main windows icon
    # self.win.iconbitmap('pyc.ico')


    self.check3.focus()     


# Start GUI

oop = CHAR_GEN()
oop.win.mainloop(

)

Ответы [ 2 ]

0 голосов
/ 05 июня 2020

Я закончил создание переменной для каждой кнопки проверки в списке точно так же, как кнопки проверки. Слишком много кода, чтобы показать, но предложение, предложенное Нико выше, привело меня на правильный путь.

Спасибо всем, кто помог.

Извините, если отступы ниже не работают. Я не публикую много сообщений.

==================================== ==========

    for i in range(len(blst)):
        print(i)
        self.vars.append(tk.IntVar())
        #print text by referencing itself from the list where buttons are stored
               self.btn.append(tk.Checkbutton(self.map_frame,text=blst[i],variable=lambda c=i:self.vars[i],command=lambda c=i: self.press(self.btn[c].cget("text"),self.vars[i])))
        self.btn[i].grid(column=int(blst[i][1]), row =int(blst[i][0]),sticky=tk.W)
0 голосов
/ 30 мая 2020

Цель Radiobutton состоит в том, чтобы в группе был выбран только один. Для вашей программы вы должны использовать Checkbutton.

В вашей программе вы никогда не используете cr_name, содержащий X / Y, для идентификации кнопки.

Пример того, как вы можете сохранить CheckButtons, а затем получить доступ к их значению позже:

from tkinter import *

root = Tk()

bits = [] 
btn = [] 

for i in range(10): #Populates a list as a replacement for your actual inputs
    bits.append("btn"+str(i))

for i in range(len(bits)):
    #print text by referencing itself from the list where buttons are stored
    btn.append(Checkbutton(root, text=bits[i], command=lambda c=i: print(btn[c].cget("text"))))
    btn[i].pack() #pack the buttons

root.mainloop()
...