2
\$\begingroup\$

I've been coding Python for little over 6 months now. I am self taught and I would like to ask for some help for myself and also for others in my position who's been wondering if they're going about this the right way.

I am looking to see:

  1. if my code can be cleaned up in any way
  2. if my code is easily read by others
  3. if my code is structured correctly

In the code, I use print statements as a debugging method to make sure that my code is not only working but flows the way I expect it to. Whenever I want to test or learn some new code I step out of my main app and create a test file to build and test my theories and to keep the code clean and simple, once working I then take what I have learned and go back to the main app add the new code. I kind of build my code from the bottom => up.

Here is some test code that I have written. I want the button to be disabled till the check-box was checked, then return to its original state once the button was pushed.

# The fix should be that after the button has been push it returns to it's original state.
# TODO(Josh)=> Found Bug: it will not go greyed out agained after being selected once.
import tkinter as tk

class mainApp(tk.Frame):

def __init__(self, root):
    """Constructor"""
    tk.Frame.__init__(self, root)

    dataVar1 = tk.IntVar()
    print(dataVar1)

    chkBoxVar = dataVar1.get()
    print(chkBoxVar)

    def greyBtnOut():
        """Test the if Statement function will it greyout my button!!!
            This is the if Statement:
            - if 1 = True then chkBox is checked, ungrey the button.
            - if not 1 = False then greyout the button give warning to check the box."""

        if chkBoxVar == 1:
            testBtn.config(state='disabled')

        else:
            testBtn.config(state='normal')


    def doSomething():
        """Do Something Function"""
        print("This worked, good job Dummy!!")
        greyBtnOut()

    def testBtn():
        """Push Button"""
        print("Button Pushed do something!!")
        doSomething()
        resetTestBtn()

    def resetTestBtn():
        """Clear and Reset button back to its starting state"""
        # would like to do this with a callback function(not sure how to work this)
        # this works in its place!!
        print("checkbutton cleared")
        chkBox.deselect()

        if chkBoxVar == 0:
            testBtn.config(state='disabled')
        else:
            doSomething()


    chkBox = tk.Checkbutton(self, variable=dataVar1, text="Place Ckeckmark    in box to work", command=doSomething)  
    chkBox.grid(column=0, row=0, padx=10, pady=10, sticky='n,e,s,w')

    testBtn = tk.Button(self, text="Test", bg=('#8CFA48'), state=    ('disabled'), font=('Calibri Bold', 12), command=testBtn)
    testBtn.grid(column=0, row=1, padx=75, pady=10, ipadx=45, ipady=6,     sticky='w')        



if __name__ == '__main__':
    root = tk.Tk()
    mainApp(root).pack(fill="both", expand=True)
    root.title("Test If Function")
    root.resizable(width=False, height=False)
    root.geometry('275x150')

    root.mainloop()    

Ok, So I have updated the code and rearranged some of it in order to incorporate the suggestions made below, but also to get the code somewhat working. Now I am getting an error, please see below.

import tkinter as tk
from tkinter import font

class mainApp(tk.Frame):
    """"""

    def __init__(self, root):
            """Constructor"""
            tk.Frame.__init__(self, root)

            self.dataVar1 = tk.IntVar()
            print(self.dataVar1)

            self.checkButtonBox = tk.Checkbutton(self, variable=self.dataVar1, text="Place Checkmark in box to work",font=checkButtonFont, command=self.doSomething)
            self.checkButtonBox.grid(column=0, row=0, padx=10, pady=10, sticky='nesw')

            self.testGreyButton = tk.Button(self, text="Reset", bg='#8CFA48', state='disabled',font=widgetFont, command=self.resetButton)
            self.testGreyButton.grid(column=0, row=1, padx=95, pady=10, ipadx=45, ipady=6, sticky='w')


    def greyButtonOut(self):
            """Test the if Statement function will it greyout my button!!!
            This is the if Statement:
            - if 1 = True then checkBox is checked ungrey the button.
            - if not 1 = False then greyout the button give warning to check the box."""

            if self.dataVar1.get() == 1:
                    self.resetButton.configure(state=DISABLED)
            else:
                    self.resetButton.configure(state=NORMAL)


    def doSomething(self):
            """Do Something Function"""
            print("This worked, good job Dummy!!")
            self.greyButtonOut()


    def resetButtonTest(self):
            """Clear and Reset button back to its starting state"""
            # would like to do this with a callback function(not sure how to work this)
            # this works in its place!!
            print(self.dataVar1)
            print("checkbutton cleared")
            checkButtonBox.deselect()

            if self.dataVar1.get() == 0:
                    self.testButton.configure(state=DISABLED)
            else:
                    self.doSomething()


    def resetButton(self):
            """Push Button"""
            print("Button Pushed, Reset Everything!!")
            self.doSomething()
            self.resetButtonTest()


if __name__ == '__main__':
    root = tk.Tk()
    widgetFont = font.Font(family="Calibri", size=16, weight="bold")
    checkButtonFont = font.Font(root, family="Calibri", size=14, slant="italic")
    mainApp(root).pack(fill="both", expand=True)
    root.title("Test If Function")
    root.geometry('350x150')

    root.mainloop()    

Here is the error code I get, I understand what its saying. I just don't know why i'm getting it or how to fix it.

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Python 3.5\lib\tkinter\__init__.py", line 1549, in     __call__
return self.func(*args)
File "d:\vcsRepository\test_ProjectFiles\testFiles\rgp_Event_Test01.py", line 41, in doSomething
self.greyButtonOut()
File "d:\vcsRepository\test_ProjectFiles\testFiles\rgp_Event_Test01.py", line 33, in greyButtonOut
self.resetButton.configure(state=DISABLED)
AttributeError: 'function' object has no attribute 'configure'
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$
dataVar1 = tk.IntVar()

In the above, dataVar1 should be self.dataVar1 so that you can reference it in other parts of your class.


chkBoxVar = dataVar1.get()
print(chkBoxVar)

The above code is useless. You call it immediately after creating the variable but before the user has a chance to interact with the program.


def __init__(self, root): ...
    def greyBtnOut(): ... 
    def doSomething(): ...
    def testBtn(): ...
    def resetTestBtn(): ...

In the above code, the extra indentation needs to be removed from the four functions -- they should not be nested inside of __init__. Also, their first argument needs to be self. Perhaps your intent is for them to share the scope of __init__ but that is unconventional and unnecessary.

Also, don't use Btn. Your code will be more readable if you use whl wrds nstd of abbrevs: greyButtonOut, testButton, resetTestButton.


    if chkBoxVar == 1:

In the above code, chkBoxVar will always have a static value. It doesn't automatically pick up new values from dataVar1. The proper way to do this is to fetch the value from the variable exactly when you need it. For example, if self.dataVar1.get() == 1.


def doSomething():
    """Do Something Function"""
    print("This worked, good job Dummy!!")
    greyBtnOut()

If you take my advice and change the indentation, the above needs to call self.greyBtnOut.


def testBtn():
    """Push Button"""
    print("Button Pushed do something!!")
    doSomething()
    resetTestBtn()

As in the previous block, change these to self.doSomething() and self.resetTestButton.


if chkBoxVar == 0:

Again, don't rely on chkBoxVar. Instead, fetch the checkbox value when you need it: if dataVar1.get() == 0


chkBox.grid(column=0, row=0, padx=10, pady=10, sticky='n,e,s,w')

In the above, you can't use commas in the sticky attribute. It should be 'nesw'.


testBtn = tk.Button(self, text="Test", bg=('#8CFA48'), state=('disabled'), font=('Calibri Bold', 12), command=testBtn)

First, you don't need the parenthesis for bg and state.

Second, don't hard-code a font like this. If you embed font information directly in the widgets, when you later decide to change the font it will be a hassle to track down all of the widgets that have custom fonts.

Tkinter has a fantasic feature called "named fonts". You can create font objects, and you use these objects in all of your widgets. If you later want to change the font, you change it in one place and all the widgets will pick up the change. Start by reading here: http://effbot.org/tkinterbook/tkinter-widget-styling.htm#font-names


root.resizable(width=False, height=False)

Making a window non-resizable is rarely a good idea. Don't take control away from the user. They may have a need to change the window size, even if it looks bad. My advice is to never set the resizable bit to False because all it really says is "I, as the programmer, know more about your needs than you do".

\$\endgroup\$
2
  • \$\begingroup\$ @holroy: I don't agree with the changes you made. Is there a specific reason why you made these changes, or is this just your personal preferences? I don't see how your changes add any value to the question. Do you mind if I roll back to my original version? \$\endgroup\$ Commented Feb 23, 2016 at 20:03
  • \$\begingroup\$ Nope (that is I don't mind, just tried to improve it, but if you disagree do roll back), it is just preferred to use the quote marking when you are quoting the original code, and leaving the plain code formatting for when you introduce new code. \$\endgroup\$
    – holroy
    Commented Feb 23, 2016 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.