Python Forum
[tkinter] not getting checkbutton value when clicked
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[tkinter] not getting checkbutton value when clicked
#1
I'm working on a larger program where I have a series of checkbuttons that will be used to determine which field to display in another frame in the window. I've got a button in one frame that is supposed to get the state of the checkbuttons in a different frame. To try to debug it I pulled everything out of the separate classes and am just trying to get my button to print the value from a single checkbutton.

import tkinter as tk
from tkinter import ttk

global currentdatabase
currentdatabase = "my_db.sqlite"

root = tk.Tk()
root.title("AnimalTrakker")
root.geometry("1024x768+0+0")
root.grid()

member_search_screen = tk.Toplevel(root)
member_search_screen.geometry("1024x768+0+0")
member_search_screen.title("Member Search")
member_search_screen.iconify()
member_search_screen.withdraw()


def DoNothing():
    tk.messagebox.showinfo(message='This is an info box that Does Nothing')
    print("testing do nothing dialog")


def GoHome():
    print("you clicked on the top home button")
    #	Add in all the other screens to hide them here
    member_search_screen.withdraw()
    # Bring up the main screen again for further input
    root.deiconify()
    root.update()

class MemberSearch:
    def __init__(self, currentdatabase):
        print("In class MemberSearch before create main frames")
        # leftsidebar section
        leftsidebar = tk.Frame(member_search_screen, borderwidth=2, relief="raised", width=40)
        leftsidebar.grid(row=0, column=0, rowspan=11, sticky=("NSEW"))
        self.gohome = ttk.Button(leftsidebar, text="Home", command=GoHome)
        self.gohome.grid(row=0, column=0)
        self.separatorbar = ttk.Separator(leftsidebar, orient="horizontal")
        self.separatorbar.grid(row=1, column=0, sticky="EW")

        self.display_options_label = tk.Label(leftsidebar, text='Display Options', anchor="w")
        self.display_options_label.grid(row=2, column=0)

        self.separatorbar = ttk.Separator(leftsidebar, orient="horizontal")
        self.separatorbar.grid(row=3, column=0, sticky="EW")

        self.display_name_val = tk.IntVar()
        self.display_name_val.set(0)
        self.display_member_name = tk.Checkbutton(leftsidebar, text="Member Name", var=self.display_name_val, width=15,
                                                  anchor="w")
        self.display_member_name.grid(row=4, column=0, sticky="W")
        centersearch = tk.Frame(member_search_screen, width=850)
        centersearch.grid(row=0, column=1, sticky="W")
        print("after gridding the top search option frame")
        select_all_value = tk.BooleanVar()
        select_all_value.set(False)
        select_all_checkbox = tk.Checkbutton(centersearch, text='Select All Members Shown', var=select_all_value)
        select_all_checkbox.grid(row=7, column=0, rowspan=2, columnspan=2, sticky="W")
        result = tk.BooleanVar()
        search_members_button = ttk.Button(centersearch, text="Search", command=lambda: self.get_display_options_selected(result), state='active')
        search_members_button.grid(row=7, column=5, columnspan=2, pady=15)

        print (f"Display Option Name is {result.get()}")

    def get_display_options_selected(self,result):
        self.result = result
        print("inside def before getting value", result.get())
        self.result = self.display_name_val.get()
        print("inside def after getting value", result.get())
        return (self.result)

    def show_membersearch(self, currentdatabase):
        root.withdraw()
        member_search_screen.update()
        print("after screen.update in show_membersearch")
        member_search_screen.deiconify()
        print("after deiconify in show_membersearch")

class MainScreen():
    def __init__(self, currentdatabase):
        print("In class main screen")
        #	Create the choose action sidebar that will go to specific screens
        leftsidebar = tk.Frame(root, borderwidth=2, relief="raised", height=768)
        leftsidebar.grid(row=0, column=0, rowspan=8, sticky=("NSEW"))

        #	Populate the side bar with the choices
        self.home_label = tk.Label(leftsidebar, text="AnimalTrakker Registry")
        self.home_label.grid(row=0, column=0)
        self.choose_action = ttk.Treeview(leftsidebar, height=20)
        self.choose_action.grid(row=1, column=0)
        self.choose_action.title = 'AnimalTrakker Home'
        self.choose_action.insert('', 0, 'animals', text='Animals', open='false')
        self.choose_action.insert('animals', 'end', 'animalsearch', text='Animal Search')
        self.choose_action.insert('animals', 'end', 'animaladd', text='Add/Edit Animal')
        self.choose_action.insert('animals', 'end', 'animalwebentry', text='Process Web Entries')
        self.choose_action.insert('animals', 'end', 'animalreports', text='Animal Reports')
        self.choose_action.insert('animals', 'end', 'animaldeaths', text='Animal Deaths')
        self.choose_action.insert('animals', 'end', 'animaltransfers', text='Animal Transfers')
        self.choose_action.insert('', 1, 'members', text='Members', open='true')
        self.choose_action.insert('members', 'end', 'membersearch', text='Member Search')
        self.choose_action.insert('members', 'end', 'memberadd', text='Add/Edit Member')
        self.choose_action.insert('members', 'end', 'memberreports', text='Member Reports')
        self.choose_action.insert('', 2, 'flockherdbook', text='Flock/Herd Book', open='false')
        self.choose_action.insert('flockherdbook', 'end', 'printregistrations', text='Print Registrations')
        self.choose_action.insert('flockherdbook', 'end', 'printtransfers', text='Print Transfers')
        self.choose_action.insert('flockherdbook', 'end', 'printmembers', text='Print Members')
        self.choose_action.insert('flockherdbook', 'end', 'printprefix', text='Print Prefixes')
        self.choose_action.insert('', 3, 'populationanalysis', text='Population Analysis', open='false')
        self.choose_action.insert('populationanalysis', 'end', 'definefounders', text='Define Founders')
        self.choose_action.insert('populationanalysis', 'end', 'calculateinbreeding', text='Calculate Inbreeding')
        self.choose_action.insert('populationanalysis', 'end', 'calculatebloodlines', text='Calculate Bloodlines')
        self.choose_action.insert('populationanalysis', 'end', 'popanalysis_item', text='Next Pop Analysis')
        self.choose_action.insert('', 4, 'registrysetup', text='Registry Setup', open='false')
        self.choose_action.insert('registrysetup', 'end', 'choosedatabase', text='Choose Database')
        self.choose_action.insert('registrysetup', 'end', 'general_setup', text='General Defaults')
        self.choose_action.insert('registrysetup', 'end', 'setup_item2', text='Next Setup2')
        # self.choose_action.config(height=25)
        self.choose_action.bind("<Double-1>", self.OnDoubleClick)


    def OnDoubleClick(self, event):
        item = self.choose_action.selection()[0]
        # print("In OnDoubleClick and you clicked on", self.choose_action.item(item, "text"))
        # print(item)
        # add all the options in here
        if item == "animalsearch":
            pass
        elif item == "membersearch":
            MemberSearch.show_membersearch(self, currentdatabase)
        elif item == "memberreports":
            pass
            # MemberReports.show_memberreports(self, currentdatabase)
        elif item == "choosedatabase":
            print("should handle change database here")
        elif item == "memberadd":
            pass
            # MemberAddEdit.show_memberaddedit(self, currentdatabase)
        else:
            print("fell out end of what to do loop")


lt_top = MainScreen(currentdatabase)
lt_member_search = MemberSearch(currentdatabase)

root.mainloop()
What I expect to happen is that I select member search by double clicking. I get the next top Window displayed. Then I click the search button without selecting the checkbutton for name in the leftsidebar. I should get printouts that say the display_name_var is false. Which I do.

Output:
In class main screen In class MemberSearch before create main frames after gridding the top search option frame Display Option Name is False after screen.update in show_membersearch after deiconify in show_membersearch after screen.update in show_membersearch after deiconify in show_membersearch inside def before getting value False inside def after getting value False you clicked on the top home button
Then if I do select the checkbutton it shows up checked in the left sidebar. I then go and click the search again and I expected to get a a False in the inside def print string (because it's before I dod the .get to get the value of the checkbutton) and a True in the after getting value print string but that is not what I get I get the same results as before. Always False.

Can anyone point me to an example that does this sort of task? Even better if the frames are in their own class as that is what I will need to do eventually.

Thanks
Reply
#2
I think you need to simplify your logic on paper, and then continue.
I got lost after clicking on search in second window.
Reply
#3
(Sep-20-2020, 02:47 AM)Larz60+ Wrote: I think you need to simplify your logic on paper, and then continue.
I got lost after clicking on search in second window.

The code doesn’t show what else happens after search because it wasn't relevant to the question. It also didn't show the rest of the center search section where the user defines what and where they are searching for the datan or does it show the reports that can be created from the data.

Pseudo code for the member search screen

User selects which fields to display via checkboxes in the left sidebar. The fields correspond to sets of fields in the database. Reason for selection is that the user does different reports on different sets and needs more flexibility than a fixed display will allow.

User selects criteria in the top center search section to limit how many result records are returned. These criteria include which registry the user is working in, the status of the member, type of membership, join date, renewal date, name, flock or herd ID, region etc. There are more things that can be used to limit the results. Reason is that reports are nearly always on a subset of current and previous members not on the entire population of the exiting member records. There are multiple registries in each database file each with its own set of members.

Once all selections are made the search button is clicked and the results of the query are displayed in a frame below the top center search section.

To further refine those results, if required, the user can select only individual records of the view to go into the report. reason is that sometimes the user has to create a custom report that give specific informaiton on only a few members of a larger group. For example the user may only want a contact list of memebrs with animals of a certain bloodline within a certain region. So this search gets the members in that region with animals but then it's the knowledge of the user who can say there 6 people have animals of that bloodline ut these 3 other ones do not and only report on the 6 that do.

There are far more subsets of options than it is possible to program in so I have to allow the user to do final selection based on their own knowledge of the individuals and animals contained in the database.

Reports are selected by choosing from among the options that are also on the left sidebar below the selection of what fields to display.

I run this basic workflow many times a month using a software program that is very difficult to use. My program will replace that package and has been designed for a much simpler interface even though it seems convoluted. To do the same thing in the current system requires several screens, selecting items, testing, then writing out the results to an Excel file for further processing into the report formats needed.

I've already tested by hand the query used to get the data and display it and it's much faster to do than it is to describe when I am actually working with the database. There are several of us who actually work with this data regularly and we all agreed on the format of the program I am working on and the UI I describe above as being much simpler to use than the existing system.

The advantage I have in doing this is I have the actual users of which I am one. I can test it in real life on our real data and see how it actually works in practice. I've been mirroring the existing system for the past 6 months but I do all the work to select what fields to displau, edit and create reports by running queries I write by hand directly on the database. Any time I find something I need to do that I haven't dealt with already in my functional spec for the program it's been added. I'm not sure I can make it more simple as it's already a lot simpler than the program I hope to replace and more intuitive to use. It does depend on the user understanding the underlying data, or at least what it contains, not necessarily the structure.
Reply
#4
The reason result.val() is always False is because you create the BooleanVar and never bind it to a control. result is used as an arg to the callback, but there is no control bound to result and no way to change the value of result.
        result = tk.BooleanVar()
        search_members_button = ttk.Button(centersearch, text="Search", command=lambda: self.get_display_options_selected(result), state='active')
        search_members_button.grid(row=7, column=5, columnspan=2, pady=15)
The reason your function always prints False is because you always print the value of the unbound BooleanVal result when what you really want is the value of the display_member_name Checkbutton IntVariable display_name_val.
    def get_display_options_selected(self,result):
        self.result = result
        print("inside def before getting value", result.get()) # Using input arg
        self.result = self.display_name_val.get()
        print("inside def after getting value", result.get()) # Still using input arg
        return (self.result)
Reply
#5
(Sep-20-2020, 02:24 PM)deanhystad Wrote: The reason result.val() is always False is because you create the BooleanVar and never bind it to a control.

Thank you.
Let me see if I understand. Since lambda only returns a single value I'll need a full set of get_display_options defs for each of the various checkboxes. There isn't a way to get all of them back at once easily. Doable, not as clean as I'd like it but I'll take working over elegant failure any day.

Here is a mockup of the screen with all the UI bits shown. The data are from a scrubbed test database but otherwise are real. I hard coded the query and the display and not tied the output section to any buttons. This was done as a proof of concept to show all the other users. I wanted to see what they thought of how it looked and would operate. This is about rev 5 as we fine tuned the displays and how the controls worked to meet all the user expectations.

[Image: view?usp=sharing]
Reply
#6
I would not use callbacks for the Checkbuttons at all. Checkbuttons have a value, so there is no reason to make another variable just to keep the checkbutton's value. The value of the Checkbutton is avialable through the tkinter variable you bound to the Checkbutton's var. Keep those in a list and use the list to get (or set) the values for all the Checkbuttons.

When you press the search button the callback would scan through all the checkbutton variables and add the associated name to the search when the checkbutton is pressed. Maybe it would be better to make the checkbuttons True/False and bind to a BooleanVar.
for index, checked in enumerate(checkbutton_vars):
    if checked.get():
        add_name_to_search(index)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] Button clicked not working catlessness 10 8,072 Oct-21-2021, 12:36 PM
Last Post: catlessness
  [Tkinter] Hide clicked buttons Rubberduck 6 3,444 Jun-02-2021, 12:44 PM
Last Post: Rubberduck
  Checkbutton writing selection to file blakefindlay 1 2,078 Jan-28-2021, 01:56 PM
Last Post: deanhystad
Question [Tkinter] Checkbutton clicks events does not update visually. nicolaask 1 2,919 Dec-20-2020, 06:11 PM
Last Post: nicolaask
  [Tkinter] How to insert 'Checkbutton' to 'Treeview' and associate each item? water 2 12,994 Dec-19-2020, 05:24 PM
Last Post: water
  Find Checkbutton State PEGylated_User 3 3,047 Oct-23-2020, 12:43 AM
Last Post: Larz60+
  [PyQt] Avoid clicked event from button when button is not physically selected and clicked mart79 2 2,309 May-05-2020, 12:54 PM
Last Post: mart79
  [Tkinter] ttk.Checkbutton set on/off ifigazsi 5 10,295 Apr-04-2020, 07:34 PM
Last Post: deanhystad
  [Tkinter] Displaying Data from a database and run a function when clicked? PythonNPC 1 2,022 Mar-11-2020, 08:16 PM
Last Post: Larz60+
  tkinter checkbutton if checked MC2020 2 5,924 Jan-21-2020, 07:08 PM
Last Post: joe_momma

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020