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:
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.
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 onexcept
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()
-
\$\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\$Mathieu Guindon– Mathieu Guindon2017年05月19日 18:46:33 +00:00Commented 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– Mike - SMT2017年05月19日 18:47:57 +00:00Commented 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– Mike - SMT2017年05月19日 18:49:10 +00:00Commented May 19, 2017 at 18:49
-
3\$\begingroup\$ SO is SO, CR is CR =) \$\endgroup\$Mathieu Guindon– Mathieu Guindon2017年05月19日 18:50:04 +00:00Commented 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– Mike - SMT2017年05月19日 18:52:06 +00:00Commented May 19, 2017 at 18:52
1 Answer 1
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
global
s. - Use readable names. Names like
ihnb
are WTF moments waiting to happen. - Is it intentional that
searchTextBox
'sevent
parameter defaults tonull
? 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.
try
ing to interact with possibly undefined variables is a definite code smell, indicating that the flow of your program is weird. Manuallydestroy
ing 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 usewith
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.
-
\$\begingroup\$ Why do you call tkinter "third party"? tkinter comes with python and is pythons GUI package. \$\endgroup\$Mike - SMT– Mike - SMT2017年05月19日 19:53:37 +00:00Commented May 19, 2017 at 19:53
-
\$\begingroup\$ I use "third party" to mean "not your code". \$\endgroup\$l0b0– l0b02017年05月19日 19:54:05 +00:00Commented 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– Mike - SMT2017年05月19日 19:57:30 +00:00Commented May 19, 2017 at 19:57 -
\$\begingroup\$ So I will look into the
Global
thing and try to change my code to avoid them. theihnb
thing is a small test code that somehow made it into the final version. I will remove that. ThesearchTextBox
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 whatcode smell
means? I will look into getting the pep8 tool you mentioned. \$\endgroup\$Mike - SMT– Mike - SMT2017年05月24日 13:32:11 +00:00Commented 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 nestedif
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– Mike - SMT2017年05月24日 13:36:21 +00:00Commented May 24, 2017 at 13:36