4
\$\begingroup\$

I have a function that will .destroy() a custom scrollbar and then recreates the scrollbar with a new theme. My IDE (Eclipse) is telling me that my function contains Undefined Variables. The error is not stopping me from running my program and I know that if the variable is not there my try statement will run a different code to create the scrollbar variable. I also know I can use #@UndefinedVariable to tell my IDE to not worry about the undefined variable.

Keep 2 things in mind:

  1. My scrollbar is custom. It is not the tkinter scrollbar. I have this custom scrollbar so I can change the colors(theme) of the sliders, background, and arrows on the scrollbar as the tkinter scrollbar cannot do this on Windows or Mac machines.

  2. My custom scrollbar does not currently have a way to manipulate the colors once it has been initialized. Because of this I decided the best way to change the theme of my scrollbar was to create a try statement that would first try to destroy the scrollbars and recreate them with the new theme or on except create the scrollbars because there was none to begin with.

My question is this:

Is it a problem for me to manage my scrollbar this way? Should I be going about this a different way?

I just feel like I am using the try statement in a way it was not meant to be used. Maybe I am just over thinking this and it is fine but it's best to know for sure so I don't make a habit of doing things the wrong way.

Below is the chopped down version of how I create and manage my scrollbars:

from tkinter import *
import scrollBarClass #Custom scrollbar class

pyBgColor =  "#%02x%02x%02x" % (0, 34, 64)
pyFrameColor =  "#%02x%02x%02x" % (0, 23, 45)
root = Tk()
root.title("MINT:   Mobile Information & Note-taking Tool")
root.geometry("500x500")
root.config(bg = pyFrameColor)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
currentTextColor = 'orange'
def doNothing():
    print("Do lots of nothing?")
# ~~~~~~~~~~~~~~~~~< Theme >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
def MintThemeDefault(mainBG, textBG, txtColor):
    # Some theme configs
    # More theme configs
    # and so on...
    root.text.config(bg = textBG, fg = txtColor)
    try:
        vScrollBar.destroy() #@UndefinedVariable
        hScrollBar.destroy() #@UndefinedVariable
        makeScrollBars(textBG, txtColor, mainBG)
    except:
        makeScrollBars(textBG, txtColor, mainBG)

def makeScrollBars(textBG,txtColor,mainBG):

    vScrollBar = scrollBarClass.MyScrollbar(root, width=15, command=root.text.yview, troughcolor = textBG,
                                            buttontype = 'square', thumbcolor = txtColor, buttoncolor = mainBG)
    vScrollBar.grid(row = 0, column = 1, columnspan = 1, rowspan = 1, padx =0, pady =0, sticky = N+S+E)
    root.text.configure(yscrollcommand=vScrollBar.set)
    vScrollBar.config(background = mainBG)

    hScrollBar = scrollBarClass.MyScrollbar(root, height=15, command=root.text.xview, orient='horizontal', troughcolor = textBG,
                                            buttontype = 'square', thumbcolor = txtColor, buttoncolor = mainBG)
    hScrollBar.grid(row = 1 , column = 0, columnspan = 1, rowspan = 1, padx =0, pady =0, sticky = S+W+E)
    root.text.configure(xscrollcommand=hScrollBar.set)
    hScrollBar.config(background = mainBG)
# ~~~~~~~~~~~~~~~~~< THEMES >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   
def MintTheme1():
    mainBGcolor = "#%02x%02x%02x" % (64,89,82)
    textBGcolor = "#%02x%02x%02x" % (17,41,41)
    txtColor = "#%02x%02x%02x" % (175, 167, 157)
    MintThemeDefault(mainBGcolor,textBGcolor,txtColor)
def MintTheme2():
    global currentTextColor
    mainBGcolor = "#%02x%02x%02x" % (14, 51, 51)
    textBGcolor = "#%02x%02x%02x" % (4, 22, 22)
    txtColor = "#%02x%02x%02x" % (223, 171, 111)
    MintThemeDefault(mainBGcolor,textBGcolor,txtColor) 
# ~~~~~~~~~~~~~~~~~< Theme Menu >~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
def libraryMenu():
    menu = Menu(root)
    root.config(menu=menu)    
    prefMenu = Menu(menu, tearoff=0)
    menu.add_cascade(label="Preferences", menu=prefMenu)
    prefMenu.add_command(label = "Mint Theme 1", command = MintTheme1)
    prefMenu.add_command(label = "Mint Theme 2", command = MintTheme2)
libraryMenu()
# ~~~~~~~~~~~~~~~~~< FRAMES >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
root.text = Text(root, undo = True)
root.text.grid(row = 0, column = 0, rowspan = 1, columnspan = 1, padx =0, pady =0, sticky = N+S+E+W)
root.text.config(bg = pyFrameColor, fg = "white", font=('times', 16), insertbackground = "orange")
root.text.config(wrap=NONE)
# ~~~~~~~~~~~~~~~~~< Default Theme >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
MintThemeDefault("#%02x%02x%02x"%(64,89,82),"#%02x%02x%02x"%(0, 23, 45),"#%02x%02x%02x"%(175, 167, 157))

root.mainloop()

In order for you to test this code you will need the scrollBarClass.py file. Here is my Github Link for the file. Just put the scrollBarClass.py file in the same directory as the main.py file you are using to test the code with.

I am adding the complete code for review. Note that this program works fine without any major errors but does require a few files to function. See my GitHub for this project called MINT.

from tkinter import *
import time
import tkinter.messagebox
import tkinter.simpledialog
import json
from string import ascii_letters, digits
import os
import scrollBarClass
# Created on Mar 21, 2017
# @author: Michael A McDonnal
pyBgColor =  "#%02x%02x%02x" % (0, 34, 64)
pyFrameColor =  "#%02x%02x%02x" % (0, 23, 45)
root = Tk()
root.title("MINT:   Mobile Information & Note-taking Tool")
root.geometry("1050x900")
root.minsize(800,600)
root.config(bg = pyFrameColor)
root.columnconfigure(0, weight=0)
root.columnconfigure(1, weight=1)
root.rowconfigure(0, weight=0)
root.rowconfigure(1, weight=1)
#root.rowconfigure(2, weight=1)
#~~~~~~~~~~~~~~~~~~~< Windows stuff >~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# row0label = Label(root)
# row0label.grid(row = 0 , column = 0 )
# row0label.configure(text = "                                                                              ")
#~~~~~~~~~~~~~~~~~~~< Global Variables Being Uses >~~~~~~~~~~~~~~~~~~~~~~~~~~
path = "./NotesKeys/"
colorPath = "./Colors/"
notebook = dict()
currentWorkingLib = ""
currentWorkingKeys = ""
currentWorkingButtonColor = "orange"
selectedTextColor = "orange"
selectedBGColor = "#%02x%02x%02x"
postUpdate = False

#~~~~~~~~~~~~~~~~~~~< USE TO open all files in Directory >~~~~~~~~~~~~~~~~~~~
with open("%s%s"%(path,"list_of_all_filenames"), "r") as listall:
    list_of_all_filenames = json.load(listall)
def openAllFiles():
    global path
    for filename in os.listdir(path):
        with open(path+filename, "r") as f:
            notebook[filename] = json.load(f)
openAllFiles()
#~~~~~~~~~~~~~~~~~~~< Prompt For New Library >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
valid_filename = ""
def new_lib_prompt():
    global valid_filename, list_of_all_filenames, path
    a_name = tkinter.simpledialog.askstring("Create New Note Library", "Alphanumeric and '_' only", initialvalue = "Name_Here")
    VALID_CHARS = "-_.() {}{}".format(ascii_letters, digits)
    valid_filename = ("".join(c for c in a_name if c in VALID_CHARS)).replace(" ", "_").lower()
    if valid_filename != "" and valid_filename != "name_here":
        if valid_filename not in list_of_all_filenames:
            createNewNotesAndKeys(valid_filename)
            list_of_all_filenames.append(valid_filename)
            with open("%s%s"%(path,"list_of_all_filenames"), "r+" ) as f:
                    json.dump(list_of_all_filenames, f, indent = "")
            libraryMenu()
        else:
            print ("Library already exist")
    else:
        print ("No Name Given")
def createNewNotesAndKeys(name):
    global path, list_of_all_filenames
    nName = name+"_notes"
    kName = name+"_keys"
    with open("./NotesKeys/default_notes", "r") as defaultN:
        nBase = json.load(defaultN)
    with open("./NotesKeys/default_keys", "r") as defaultK:
        kBase = json.load(defaultK)
    with open("%s%s"%(path,nName), "w") as outNotes:
        json.dump(nBase, outNotes, indent = "")
    with open("%s%s"%(path,kName), "w") as outNotes:
        json.dump(kBase, outNotes, indent = "")
    openAllFiles()
#~~~~~~~~~~~~~~~~~~~< USE TO CLOSE PROGRAM >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def closeprogram():
    answer = tkinter.messagebox.askquestion("Leaving MINT?","Are you sure you want to leave MINT")
    if answer == "yes":
        root.destroy()
    else:
        tkinter.messagebox.showinfo("MINTy Fresh!","Welcome Back XD")
def doNothing():
    print("Do lots of nothing?")
#~~~~~~~~~~~~~~~~~~~< Message Box >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def ihnb():
    answer = tkinter.messagebox.askquestion("Do you want to be a Python Programmer?","Do you want to program?")
    if answer == "yes":
        a1 = "Then be prepared to spend countless hours hating life!"
        root.text.delete(1.0, "end-1c")
        root.text.insert("end-1c", a1)
        root.text.see("end-1c")
    else:
        a2= "Smart move. Now go away!"
        root.text.delete(1.0, "end-1c")
        root.text.insert("end-1c", a2)
        root.text.see("end-1c")
#~~~~~~~~~~~~~~~~~~~< UPDATE keyword display >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def update_kw_display():
    pass
    listToPass = ["chose a library","chose a library_keys","chose a library_notes",""]
    if currentWorkingKeys not in listToPass:
        keys_to_be_updated = notebook[currentWorkingKeys]
        root.textSideL.delete(1.0, "end-1c")
        root.textSideR.delete(1.0, "end-1c")
        contr = 0
        for item in keys_to_be_updated:
            if contr == 0:
                root.textSideL.insert("end-1c",item+"\n")
                root.textSideL.see("end-1c")
                contr += 1
            else:
                root.textSideR.insert("end-1c",item+"\n")
                root.textSideR.see("end-1c")
                contr = 0
    else:
        print("In the list to pass")
#~~~~~~~~~~~~~~~~~~~< Search for words and highlight >~~~~~~~~~~~~~~~~~~~~~~~~
def searchTextbox(event=None):
    root.text.tag_configure("search", background="green")
    root.text.tag_remove('found', '1.0', "end-1c")
    wordToSearch = searchEntry.get().lower()
    idx = '1.0'
    while idx:
        idx = root.text.search(wordToSearch, idx, nocase=1, stopindex="end-1c")
        if idx:
            lastidx = '%s+%dc' % (idx, len(wordToSearch))
            root.text.tag_add('found', idx, lastidx)
            idx = lastidx
    root.text.tag_config('found', font=("times", 16, "bold"), foreground ='orange')
#~~~~~~~~~~~~~~~~~~~< UPDATE selected_notes! >~~~~~~~~~~~~~~~~~~~
def append_notes():
    global currentWorkingLib, currentWorkingKeys, path
    e1Current = keywordEntry.get().lower()
    e1allcase = keywordEntry.get()
    e2Current = root.text.get(1.0, "end-1c")
    answer = tkinter.messagebox.askquestion("Update Notes!","Are you sure you want update your Notes for "+e1allcase+" This cannot be undone!")
    if answer == "yes":
        if e1Current in notebook[currentWorkingLib]:
            statusE.config(text = "Updating Keyword & Notes for the "+currentWorkingLib+" Library!")
            dict_to_be_updated = notebook[currentWorkingLib]
            dict_to_be_updated[e1Current] = e2Current
            with open("%s%s"%(path,currentWorkingLib),"w") as working_temp_var:
                json.dump(dict_to_be_updated, working_temp_var, indent = "")
            statusE.config(text = "Update Complete")          
        else:
            statusE.config(text= "Creating New Keyword & Notes for the "+currentWorkingLib+" Library!")
            dict_to_be_updated = notebook[currentWorkingLib]
            dict_to_be_updated[e1Current] = e2Current
            with open("%s%s"%(path,currentWorkingLib), "w" ) as working_temp_var:
                json.dump(dict_to_be_updated, working_temp_var, indent = "")
            keys_to_be_updated = notebook[currentWorkingKeys]
            keys_to_be_updated.append(e1allcase)
            with open("%s%s"%(path,currentWorkingKeys), "w" ) as working_temp_keys:
                json.dump(keys_to_be_updated, working_temp_keys, indent = "")
            statusE.config(text = "Update Complete")
        update_kw_display()            
    else:
        tkinter.messagebox.showinfo("...","That was close!")      
#~~~~~~~~~~~~~~~~~~~< Entry Widget >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def kw_entry(event=None):
    global currentWorkingLib
    e1Current = keywordEntry.get().lower()
    #e1IgnoreCase = keywordEntry.get()
    if currentWorkingLib in notebook:
        note_var = notebook[currentWorkingLib]
        if e1Current in note_var:
            #tags_list=[r"(?:<<)",r"(?:>>)",r"(?:<)",r"(?:>)"]
            root.text.delete(1.0, "end-1c")
            root.text.insert("end-1c", note_var[e1Current])
            root.text.see("end-1c")
        else:
            root.text.delete(1.0, "end-1c")
            root.text.insert("end-1c", "Not a Keyword")
            root.text.see("end-1c")
    else:
        root.text.delete(1.0, "end-1c")
        root.text.insert("end-1c", "No Library Selected")
        root.text.see("end-1c")
#~~~~~~~~~~~~~~~~~~~< Preset Themes >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
baseBGimage=PhotoImage(file="./Colors/pybgbase.png")
bgLable = Label(root, image= baseBGimage)
bgLable.place(x = 0, y = 0)

bgLable.config(image = baseBGimage)
bgLable.image = baseBGimage
currentTextColor = 'orange'

def MintThemeDefault(mainBG, textBG, txtColor,bgimage):
    global currentTextColor
    currentTextColor = txtColor
    themeBGimage = bgimage
    textFrame.config(bg = textBG)
    entryBGimage.config(image = themeBGimage)
    entryBGimage.image = themeBGimage
    kwBGimage.config(image = themeBGimage)
    kwBGimage.image = themeBGimage
    bgLable.config(image = themeBGimage)
    bgLable.image = themeBGimage
    #entryBGimage.config(image = themeBGimage)
    #entryBGimage.image = themeBGimage
    root.config(bg = mainBG)
    root.text.config(bg = textBG, fg = txtColor)
    root.textSideL.config(bg = textBG, fg = txtColor)
    root.textSideR.config(bg = textBG, fg = txtColor)
    searchEntry.config(fg = txtColor, bg = textBG)
    keywordEntry.config(fg = txtColor, bg = textBG)
    statusFrame.config(bg = textBG)
    statusE.config(fg = txtColor, bg = textBG)
    statusW.config(fg = txtColor, bg = textBG)
    searchLabel.config(fg = txtColor, bg = textBG)
    keywordLabel.config(fg = txtColor, bg = textBG)
    UpdateKeywordsButton.config(fg = txtColor, bg = textBG)
    try:
        vScrollBar.destroy() #@UndefinedVariable
        hScrollBar.destroy() #@UndefinedVariable
        makeScrollBars(textBG, txtColor, mainBG)
    except:
        makeScrollBars(textBG, txtColor, mainBG)

def makeScrollBars(textBG,txtColor,mainBG):
    vScrollBar = scrollBarClass.MyScrollbar(textFrame, width=15, command=root.text.yview, troughcolor = textBG,
                                            buttontype = 'square', thumbcolor = txtColor, buttoncolor = mainBG)
    vScrollBar.grid(row = 0, column = 2, columnspan = 1, rowspan = 1, padx =0, pady =0, sticky = N+S+E)
    root.text.configure(yscrollcommand=vScrollBar.set)
    vScrollBar.config(background = mainBG)
    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    hScrollBar = scrollBarClass.MyScrollbar(textFrame, height=15, command=root.text.xview, orient='horizontal', troughcolor = textBG,
                                            buttontype = 'square', thumbcolor = txtColor, buttoncolor = mainBG)
    hScrollBar.grid(row = 1 , column = 0, columnspan = 1, rowspan = 1, padx =0, pady =0, sticky = S+W+E)
    root.text.configure(xscrollcommand=hScrollBar.set)
    hScrollBar.config(background = mainBG)

def MintTheme1():
    mainBGcolor = "#%02x%02x%02x" % (64,89,82)
    textBGcolor = "#%02x%02x%02x" % (17,41,41)
    txtColor = "#%02x%02x%02x" % (175, 167, 157)
    bgimage=PhotoImage(file="./Colors/theme1bg.png")
    MintThemeDefault(mainBGcolor,textBGcolor,txtColor,bgimage)
def MintTheme2():
    global currentTextColor
    mainBGcolor = "#%02x%02x%02x" % (14, 51, 51)
    textBGcolor = "#%02x%02x%02x" % (4, 22, 22)
    txtColor = "#%02x%02x%02x" % (223, 171, 111)
    bgimage=PhotoImage(file="./Colors/theme2bg.png")
    MintThemeDefault(mainBGcolor,textBGcolor,txtColor,bgimage) 
#~~~~~~~~~~~~~~~~~~~< Menu function >~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def updateWorkingLibKeys(filename):
    global currentWorkingLib,currentWorkingKeys
    currentWorkingLib = "{}_notes".format(filename).lower()
    currentWorkingKeys = "{}_keys".format(filename).lower()
    update_kw_display()
def libraryMenu():
    menu = Menu(root)
    root.config(menu=menu)
    fileMenu = Menu(menu, tearoff=0)
    menu.add_cascade(label="File", menu=fileMenu)
    fileMenu.add_command(label="Save", command=doNothing)
    fileMenu.add_command(label="Save As", command=doNothing)
    fileMenu.add_separator()
    fileMenu.add_command(label="Exit", command= closeprogram)

    libMenu = Menu(menu, tearoff=0)
    menu.add_cascade(label="Note Libraries", menu=libMenu)
    libMenu.add_command(label="Library Help Page - Not Implemented Yet", command=doNothing)
    libMenu.add_separator()
    libMenu.add_command(label="New Library", command=new_lib_prompt)
    libMenu.add_command(label="Lock Library - Not Implemented Yet", command=doNothing)
    libMenu.add_command(label="Delete Library! - Not Implemented Yet", command=doNothing)
    libMenu.add_separator()

    prefMenu = Menu(menu, tearoff=0)
    menu.add_cascade(label="Preferences", menu=prefMenu)
    prefMenu.add_command(label="Mint Theme 1", command=MintTheme1)
    prefMenu.add_command(label="Mint Theme 2", command=MintTheme2)

    helpMenu = Menu(menu, tearoff=0)
    menu.add_cascade(label="Help", menu=helpMenu)
    helpMenu.add_command(label="Info", command=doNothing)

    for filename in list_of_all_filenames:
        libMenu.add_command(label = "%s"%(filename), command = lambda filename=filename: updateWorkingLibKeys(filename))

libraryMenu()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
textFrame = Frame(root, borderwidth = 0, highlightthickness = 0)
textFrame.grid(row = 0, column = 1, columnspan = 1, rowspan = 2, padx =0, pady =0, sticky = W+E+N+S)
textFrame.columnconfigure(0, weight=1)
textFrame.rowconfigure(0, weight=1)
textFrame.columnconfigure(1, weight=0)
textFrame.rowconfigure(1, weight=0)

entryFrame = Frame(root)
entryFrame.grid(row = 0, column = 0, rowspan = 1, columnspan = 1, padx =0, pady =0, sticky = W+E+N+S)
entryFrame.columnconfigure(0, weight=0)
entryFrame.columnconfigure(1, weight=0)
entryFrame.rowconfigure(0, weight=0)
entryFrame.rowconfigure(1, weight=0)
entryFrame.rowconfigure(2, weight=0)
entryBGimage = Label(entryFrame, image= baseBGimage, borderwidth = 0, highlightthickness = 0)
entryBGimage.image = baseBGimage
entryBGimage.place(x = 0, y = 0)
entryBGimage.config(image = baseBGimage)

kwListFrame = Frame(root, borderwidth = 0, highlightthickness = 0)
kwListFrame.grid(row = 1, column = 0, rowspan = 1, columnspan = 1, padx =0, pady =0, sticky = W+E+N+S)
kwListFrame.columnconfigure(0, weight=1)
kwBGimage = Label(kwListFrame, image= baseBGimage, borderwidth = 0, highlightthickness = 0)
kwBGimage.image = baseBGimage
kwBGimage.place(x = 0, y = 0)
kwBGimage.config(image = baseBGimage)

root.textSideL = Text(kwListFrame, width = 10, height = 20)
root.textSideL.place( x = 5, y = 5)
root.textSideL.config(wrap=NONE)
root.textSideR = Text(kwListFrame,  width = 10, height = 20)
root.textSideR.place( x = 95, y = 5)
root.textSideR.config(wrap=NONE)

statusFrame = Frame(root)
statusFrame.config(bg = pyFrameColor)
statusFrame.grid(row = 3, column = 0, rowspan = 3, columnspan = 2, padx =0, pady =0, sticky = W+E+N+S)
statusFrame.columnconfigure(0, weight=1)
statusFrame.columnconfigure(1, weight=1)
statusFrame.rowconfigure(0, weight=0)

root.text = Text(textFrame, undo = True)
root.text.grid(row = 0, column = 0, rowspan = 1, columnspan = 1, padx =0, pady =0, sticky = W+E+N+S)
root.text.config(bg = pyFrameColor, fg = "white", font=('times', 16), insertbackground = "orange")
root.text.config(wrap=NONE)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
statusW = Label(statusFrame, font=("times", 16, "bold"), fg = "white", bg = "black", relief = SUNKEN, anchor = W)
statusW.grid(row = 0, column = 0, padx =1, pady =1, sticky = W+S)
statusW.config(text = "Operation Status", bg = "#%02x%02x%02x"%(0, 23, 45))

statusE = Label(statusFrame, font=("times", 16, "bold"), fg = "white", bg = "black", relief = SUNKEN, anchor = E)
statusE.grid(row = 0, column = 1, padx =1, pady =1, sticky = E+S)
statusE.config(bg = "#%02x%02x%02x"%(0, 23, 45))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
searchLabel = Label(entryFrame)
searchLabel.grid(row = 1, column = 0, padx =5, pady=5)
searchLabel.config(text="Search Text Field")

searchEntry = Entry(entryFrame, width = 20)
searchEntry.bind("<Return>", searchTextbox)
searchEntry.grid(row = 1, column = 1, padx =5, pady=5)

keywordLabel = Label(entryFrame)
keywordLabel.grid(row = 0, column = 0, padx =5, pady=5)
keywordLabel.config(text="Keyword Search")

keywordEntry = Entry(entryFrame, width = 20)
keywordEntry.bind("<Return>", kw_entry)
keywordEntry.grid(row = 0, column = 1, padx =5, pady=5)

UpdateKeywordsButton = tkinter.Button(entryFrame, fg = 'Black', bg = 'Orange', text = "Update Notes", command = append_notes)
UpdateKeywordsButton.grid(row = 2, column = 0, padx =5, pady =5)

MintThemeDefault("#%02x%02x%02x"%(64,89,82),"#%02x%02x%02x"%(0, 23, 45),"#%02x%02x%02x"%(175, 167, 157),PhotoImage(file="./Colors/pybgbase.png"))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
status_time = ""
def tick():
    global status_time
    time2 = time.strftime("%H:%M:%S")
    if time2 != status_time:
        status_time = time2
        statusE.config(text=time2+"  Preparing to do nothing...")
    statusE.after(200, tick)
tick()
#~~~~~~~~~~~~~~~~~~~< root Main Loop >~~~~~~~~~~~~~~~~~~~~~~~~~~~~
root.mainloop()
\$\endgroup\$
8
  • \$\begingroup\$ Upvoted, but why give us a chopped down version? If there's noisy boilerplate in your code, reviewers can help with that, too! \$\endgroup\$ Commented May 19, 2017 at 18:46
  • \$\begingroup\$ @Mat's Mug: The chopped down version is related to my question. the rest of the code is around 300+ lines that perform the rest of the programs functions. \$\endgroup\$
    – Mike - SMT
    Commented May 19, 2017 at 18:47
  • \$\begingroup\$ I could provide the full code if that is ok. I do know on some other stack sites they want the Minimal, Complete, and Verifiable example \$\endgroup\$
    – Mike - SMT
    Commented May 19, 2017 at 18:49
  • 3
    \$\begingroup\$ SO is SO, CR is CR =) \$\endgroup\$ Commented May 19, 2017 at 18:50
  • \$\begingroup\$ Ahhhh. That is a good link to have. I did not realize there was such a big difference between SO and CR. I will include my main program code as well as my link to github for all the supporting files. \$\endgroup\$
    – Mike - SMT
    Commented May 19, 2017 at 18:52

1 Answer 1

2
\$\begingroup\$

Idiomatic Python:

  • The only lines that should be outside a method or class are global imports and these:

    if __name__ == '__main__':
        sys.exit(main())
    

    this makes it much easier to understand what the state is once the program starts, and makes it easier to follow as it changes while going through the code. As it stands I can't see the relationship between the top-level variables at a glance.

  • Avoid globals.
  • Use readable names. Names like ihnb are WTF moments waiting to happen.
  • Is it intentional that searchTextBox's event parameter defaults to null? Unless you know it will be called without a parameter it should not be defaulted.
  • Putting Class as a suffix in a class name is redundant.
  • The various GUI elements should be put together in an object.
  • trying to interact with possibly undefined variables is a definite code smell, indicating that the flow of your program is weird. Manually destroying objects is another smell in garbage collected languages like Python. Sometimes it is necessary, but most of the time you should be able to stamp over variables (or use with statements) without fear that your application will leak resources.

PEP8 stuff:

  • Variable names should be all_lower_case_and_underscore_separated.
  • This and various other stuff will be reported by the pep8 tool.

Personal preference:

  • You should not have commented code in checked in code.
  • I never import * from third party code and usually not even from my own libraries, to avoid polluting the name space and possibly creating collisions. root = tkinter.Tk() allows a reader to know instantly that it's an object based on outside code as opposed to something in the same file.
  • Nested if statements can easily be pulled out as methods, clearing up the code.
  • Comments should not include fancy separators. Those were only really necessary in the days of editors which didn't support code highlighting, and nowadays just distract from the content.
\$\endgroup\$
6
  • \$\begingroup\$ Why do you call tkinter "third party"? tkinter comes with python and is pythons GUI package. \$\endgroup\$
    – Mike - SMT
    Commented May 19, 2017 at 19:53
  • \$\begingroup\$ I use "third party" to mean "not your code". \$\endgroup\$
    – l0b0
    Commented May 19, 2017 at 19:54
  • \$\begingroup\$ Ok. I guess I just consider third party to mean "not from stock release". As I appreciate your feedback on all the points you mentioned you did not mention anything about my main question. Could you add something about my use of the try/except statement? \$\endgroup\$
    – Mike - SMT
    Commented May 19, 2017 at 19:57
  • \$\begingroup\$ So I will look into the Global thing and try to change my code to avoid them. the ihnb thing is a small test code that somehow made it into the final version. I will remove that. The searchTextBox has the argument (event = Null) due to the way tkinter assigns commands to objects. It was required to prevent the function from being called on initialization. I am still very new to the class concept so I will look into moving the GUI into a class. Can you tell me what code smell means? I will look into getting the pep8 tool you mentioned. \$\endgroup\$
    – Mike - SMT
    Commented May 24, 2017 at 13:32
  • \$\begingroup\$ Because I am not sure what other features I will be adding to my program I have used * to cover everything as I go. I will once I am satisfied with the program change the import from * to directly importing each function needed. When you say a nested if statement can be pulled out as method what dies that mean? The comments with the separators is really for my benefit. I use them to have a quick way of identifying sections of my code as I scroll around changing stuff. With all that being said, thanks for your feedback. I will get to work on the needed cleanup of my code. \$\endgroup\$
    – Mike - SMT
    Commented May 24, 2017 at 13:36

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.