There are many things to discuss about your code and I have two options to do do that:
- Redesign your program by applying a suitable design pattern.
- Obey to my legendary laziness and point out only the minimum things you should care about.
For some considerations, I chose the second option. So here are some random notes you should ponder about:
Do not confuse me
Before diving in any details, I see a bunch of functions and a class. That was the first thing that attracts my attention. This is confusing because it does not let the maintainer of your code to understand the ideology of your program and whether you belong to the OOP or procedural sects.
Opting only for one of those programming types will help to understand the flow logic of your program. This will also reflect you are not versatile but self-confident and a good decision maker.
As developers, we need to take a set of decision before coding anything. This is a big chance for us to train ourselves to take the right decisions. And the decision regarding which programming type to adopt for your program is not that difficult. Your program needs to comply to an OOP approach because:
- You are designing a GUI, so do not forget that the leaves of history inform us that object-oriented concept is the legitimate child of the simulation and graphical design.
- Python is FCF programming language. So be pythonic by adopting OOP since even functions are objects in this language.
We do not need to be more gossip because this is already convincing on why
you should write those functions in a proper class instead.
You can be monadic
Let me pick this function, for instance:
button(source,text,command=None,row=0,column=0,rowspan=None,columnspan=None)
Parameters are heretics that must be used parsimoniously because they are a different level of abstraction. The ideal is, when possible, to use monadic functions; and in your situation this is possible because row
, column
, columnspan
and rowspan
are already options of the grid()
geometry manager, so it is useless1 to inject them as parameters to the enclosing functions. For the command
and bg
parameters,you also can inject them directly as an option to the widgets you need to use it for (tkinter.Button()
in this function)
Container's type as a name: bad!
You used function names such as button()
and label()
while you already have widget types which names are Button()
and Label()
. Do not use the container's type as a name for your functions. This is a source of confusion as stated by Robert C. Martin in his book Clean code.
Function names must divulge the function's purpose:
What about this function name you used: iQuiz()
? You should rename this function to be informative in that if Donald Trump reads the name of that function he can instantly understand its purpose.
Choose the right names for variables
Your program is small, so maybe I can be enough smart and patient to guess, but also remember, why these variables are useful for: opt1
, opt2
, opt3
, opt4
. As your program grows, these variables will make your source code unclear and thus difficult to maintain. Also, if I am a mathematician, I may tend to understand that opt
stands for optimum
or anything else you do not think.
Code a lighter initializer
You are doing too much things in the initializer __init__()
. Initialize only the necessary things and delegate everything else to other functions.
init() takes a useless argument
The string argument you provide to init() is a bad decision. A good practice is to use as less parameters as possible. Plus, you can simply set the title of your GUI in a separate configuration function like this one:
def configure_gui(self):
self.window_height = 500
self.window_width = 1000
self.background_color = 'powder blue'
self.master.title('Quiz')
self.master.option_add('*Font','aerial 12')
self.master.config(width=self.window_width, height=self.window_height)
and use this configuration function within __init__()
:
def __init(self, master):
self.master = master
self.configure_gui()
Improve readability
Put spaces between the the coma and the option in all similar situations to this one:
storeObj.grid(row=row,column=column,rowspan=rowspan,columnspan=columnspan)
Put space also for your variables. I mean you have many situation like this one: pre=button(frame_pre,'Previous')
which should be written: pre = button(frame_pre,'Previous')
Remove unpractical graphical choices
You set the font weight to bold and font seize to 20: that is too much. This will lead to an ugly text, and you punish yourself if one of the answers or questions contains a half dozen or more of words.
1. But also may be harmful for the scalability of your program.