I've written a study program in an attempt to teach myself Python and help my classmates. I originally learned C , but that had been a while back. I feel like my code is a mess and I've tried organizing things into classes, but can't seem to get the program to work afterwards. Unfortunately, I'm incredibly rusty and know I've made mistakes, but the program itself seems to work. I'd appreciate any guidance. Here's the code I've developed so far:
import tkinter as tk
from tkinter import *
from PIL import ImageTk,Image
import random
#Well, this is my third attempt at getting this program to work how I want
#No idea why, but everything was working fine until I tried to fix another error
#so hopefully doing this stepwise will help me figure out why it's being a bastitch
#This is the core of the program. It's a list of the twenty amino acids, with
#a list containing the name, three letter code, one letter code, and the pKas
#of the C-terminal and N-terminal respecitvely. A third number is the pKa of the
#R group. More information can be added as needed. Each amino acid also has a
#number assigned to pull the acid from the RNG.
def aminoAcids(SelectionNo):
Alanine = ["Alanine", "Ala", "A", 2.2, 9.8]
Arginine = ["Arginine", "Arg", "R", 2.2, 9.8, 12.48]
Asparagine = ["Asparagine", "Asn", "N", 2.2, 9.8]
AsparticAcid = ["Aspartic Acid", "Asp", "D", 2.2, 9.8, 3.71]
Cysteine = ["Cysteine", "Cys", "C", 2.2, 9.8, 8.33]
Glutamine = ["Glutamine", "Gln", "Q", 2.2, 9.8]
GlutamicAcid = ["Glutamic Acid", "Glu", "E", 2.2, 9.8, 4.15]
Glycine = ["Glycine", "Gly", "G", 2.2, 9.8]
Histidine = ["Histidine", "His", "H", 2.2, 9.8, 6.00]
Isoleucine = ["Isoleucine", "Ile", "I", 2.2, 9.8]
Leucine = ["Leucine", "Leu", "L", 2.2, 9.8]
Lysine = ["Lysine", "Lys", "K", 2.2, 9.8, 10.53]
Methionine = ["Methionine", "Met", "M", 2.2, 9.8]
Phenylalanine = ["Phenylalanine", "Phe", "F", 2.2, 9.8]
Proline = ["Proline", "Pro", "P", 2.2, 9.8]
Serine = ["Serine", "Ser", "S", 2.2, 9.8]
Threonine = ["Threonine", "Thr", "T", 2.2, 9.8]
Tryptophan = ["Tryptophan", "Trp", "W", 2.2, 9.8]
Tyrosine = ["Tyrosine", "Tyr", "Y", 2.2, 9.8, 10.07]
Valine = ["Valine", "Val", "V", 2.2, 9.8]
if SelectionNo == 1:
AminoAcid = Alanine
elif SelectionNo == 2:
AminoAcid = Arginine
elif SelectionNo == 3:
AminoAcid = Asparagine
elif SelectionNo == 4:
AminoAcid = AsparticAcid
elif SelectionNo == 5:
AminoAcid = Cysteine
elif SelectionNo == 6:
AminoAcid = Glutamine
elif SelectionNo == 7:
AminoAcid = GlutamicAcid
elif SelectionNo == 8:
AminoAcid = Glycine
elif SelectionNo == 9:
AminoAcid = Histidine
elif SelectionNo == 10:
AminoAcid = Isoleucine
elif SelectionNo == 11:
AminoAcid = Leucine
elif SelectionNo == 12:
AminoAcid = Lysine
elif SelectionNo == 13:
AminoAcid = Methionine
elif SelectionNo == 14:
AminoAcid = Phenylalanine
elif SelectionNo == 15:
AminoAcid = Proline
elif SelectionNo == 16:
AminoAcid = Serine
elif SelectionNo == 17:
AminoAcid = Threonine
elif SelectionNo == 18:
AminoAcid = Tryptophan
elif SelectionNo == 19:
AminoAcid = Tyrosine
elif SelectionNo == 20:
AminoAcid = Valine
return AminoAcid
#######################################################
#This will open up the question window and allow the user to study
def openQuestionWindow():
global QuestionWindow
QuestionWindow = Toplevel(root)
QuestionWindow.title('Second Window')
global IDCall
global pKCall
IDCall = 0
pKCall = 0
global ErrorMsgLbl
global AcidName
global ImageLbl
global ShowAnswerBtn
AcidName = aminoAcids(SelectionNo = random.randint(1,20))
AminoAcidPic = Image.open(f"{AcidName[0]}.png")
AminoAcidPicResize = AminoAcidPic.resize((200, 200))
ActualImage = ImageTk.PhotoImage(AminoAcidPicResize)
ImageLbl = Label(QuestionWindow, image = ActualImage)
ImageLbl.config(image = ActualImage)
#ImageLbl.grid(column = 1, columnspan = 2, row = 0)
ImageLbl.pack()
ErrorMsgLbl = Label(QuestionWindow, text = ' ')
ErrorMsgLbl.pack()
if (SelName_V.get() == 1) & (SelPk_V.get() == 1):
IDCall = 1
pKCall = 1
CombinedWindow()
elif (SelName_V.get() == 1) & (SelPk_V.get() == 0):
IDCall =1
AminoAcidID()
elif (SelName_V.get() == 0) & (SelPk_V.get() == 1):
pKCall = 1
pKaQuestion()
CheckAnswerBtn = Button(QuestionWindow, text = "Check Answers", command = CheckAnswer)
CheckAnswerBtn.pack(padx = 5, pady = 5,side = RIGHT)
NewAminoBtn = Button(QuestionWindow, text = "Change Amino", command = AminoChoice)
NewAminoBtn.pack(pady = 5, padx = 5, side = RIGHT)
CloseBtn = Button(QuestionWindow, text = "Close", command = lambda: QuestionWindow.destroy())
CloseBtn.pack(padx = 5, pady = 5, side = LEFT)
ShowAnswerBtn = Button (QuestionWindow, text = "Show Answers", command = RevealAnswer)
ShowAnswerBtn.pack(pady = 5, padx = 5, side = LEFT)
ShowAnswerBtn.config(state = DISABLED)
QuestionWindow.mainloop()
#######################################################
#This defines which amino acid is used
def AminoChoice():
global AcidName
NewAcidName = aminoAcids(SelectionNo = random.randint(1,20))
NewAminoAcidPic = Image.open(f"{NewAcidName[0]}.png")
NewAminoAcidPicResize = NewAminoAcidPic.resize((200, 200))
NewActualImage = ImageTk.PhotoImage(NewAminoAcidPicResize)
ImageLbl.configure(image = NewActualImage)
ImageLbl.photo = NewActualImage
AcidName = NewAcidName
ShowAnswerBtn.config(state = DISABLED)
ErrorMsgLbl.config(text = ' ')
if IDCall == 1:
NameAnswer.config(bg = "yellow")
NameAnswer.delete(0,END)
Let3Answer.config(bg = "yellow")
Let3Answer.delete(0,END)
Let1Answer.config(bg = "yellow")
Let1Answer.delete(0,END)
NameReveal.config(text = ' ')
Let3Reveal.config(text = ' ')
Let1Reveal.config(text = ' ')
if pKCall == 1:
pKAnswer.config(bg = "yellow")
pKAnswer.delete(0, END)
NewpHVal = round(random.uniform(0, 14), 2)
TotatlCharge = tk.IntVar()
TotalCharge.set(0)
if AcidName[3] < NewpHVal:
TotalCharge.set(TotalCharge.get() - 1)
elif AcidName[3] == NewpHVal:
TotalCharge.set(TotalCharge.get() - .5)
if AcidName[4] > NewpHVal:
TotalCharge.set(TotalCharge.get() 1)
elif AcidName[4] == NewpHVal:
TotalCharge.set(TotalCharge.get() .5)
pKQuestionLbl.config(text = f"What is the amino acids charge at pH {NewpHVal: .2f}?")
pKReveal.config(textvariable = ' ')
#######################################################
#This will show the questions of all question types
def CombinedWindow():
AminoAcidID()
pKaQuestion()
#######################################################
#This will ask for ID if ID questions are selected
def AminoAcidID():
global NameAnswer
global NameReveal
global Let3Answer
global Let3Reveal
global Let1Answer
global Let1Reveal
NameQuest = Label(QuestionWindow, text = "What is the full name of the amino acid?", wraplength = 300)
NameAnswer = Entry(QuestionWindow, width = 20, bg = "yellow")
NameReveal = Label (QuestionWindow, text = " ", width = 20)
Let3Quest = Label(QuestionWindow, text = "What is the three letter code of the amino acid?", wraplength = 300)
Let3Answer = Entry(QuestionWindow, width = 20, bg = "yellow")
Let3Reveal = Label (QuestionWindow, text = " ", width = 20)
Let1Quest = Label(QuestionWindow, text = "What is the one letter code of the amino acid?", wraplength = 300)
Let1Answer = Entry(QuestionWindow, width = 20, bg = "yellow")
Let1Reveal = Label (QuestionWindow, text = " ", width = 20)
NameQuest.pack()
NameAnswer.pack()
NameReveal.pack()
Let3Quest.pack()
Let3Answer.pack()
Let3Reveal.pack()
Let1Quest.pack()
Let1Answer.pack()
Let1Reveal.pack()
#######################################################
def pKaQuestion():
pHVal = round(random.uniform(0, 14), 2)
global TotalCharge
global pKAnswer
global pKReveal
global pKQuestionLbl
TotalCharge = tk.IntVar()
TotalCharge.set(0)
if AcidName[3] < pHVal:
TotalCharge.set(TotalCharge.get() - 1)
elif AcidName[3] == pHVal:
TotalCharge.set(TotalCharge.get() - .5)
if AcidName[4] > pHVal:
TotalCharge.set(TotalCharge.get() 1)
elif AcidName[4] == pHVal:
TotalCharge.set(TotalCharge.get() .5)
pKQuestionLbl = Label(QuestionWindow, text = f"What is the amino acids charge at pH {pHVal: .2f}?")
pKQuestionLbl.pack()
pKAnswer = Entry(QuestionWindow, width = 20, bg = "yellow")
pKAnswer.pack()
pKReveal = Label (QuestionWindow, text = ' ')
pKReveal.pack()
######################################################################
#This will validate the entered answer and show if they are correct
def CheckAnswer():
if IDCall == 1:
CorrectName = AcidName[0]
Correct3Let = AcidName[1]
CorrectLet = AcidName[2]
NameInput = NameAnswer.get()
Let3Input = Let3Answer.get()
Let1Input = Let1Answer.get()
if len(NameInput.get() == 0) or len(Let3Input.get() == 0) or len(Let1Input.get() == 0):
ErrorMsgLbl.config(text = "Please Enter A Value Into All Fields", fg = "red")
else:
ShowAnswerBtn.config(state = ACTIVE)
if CorrectName.upper() == NameInput.upper():
NameAnswer.config(bg = "green")
else:
NameAnswer.config(bg = "red")
if Correct3Let.upper() == Let3Input.upper():
Let3Answer.config(bg = "green")
else:
Let3Answer.config(bg = "red")
if CorrectLet.upper() == Let1Input.upper():
Let1Answer.config(bg = "green")
else:
Let1Answer.config(bg = "red")
if pKCall == 1:
ActualCharge = TotalCharge.get()
if len(pKAnswer.get()) == 0:
ErrorMsgLbl.config(text = "Please Enter A Value Into All Fields", fg = "red")
else:
ShowAnswerBtn.config(state = ACTIVE)
pKAnswerInt = int(pKAnswer.get())
ErrorMsgLbl.config(text = ' ')
if pKAnswerInt == ActualCharge:
pKAnswer.config(bg = "green")
else:
pKAnswer.config(bg = "red")
#######################################################
#This will show the answer when pressed
def RevealAnswer():
if IDCall == 1:
NameReveal.config(text = AcidName[0])
Let3Reveal.config(text = AcidName[1])
Let1Reveal.config(text = AcidName[2])
if pKCall == 1:
pKReveal.config(textvariable = TotalCharge)
#######################################################
#This will act as the main, interactable window
root = tk.Tk()
root.title("Biochemistry Start Window")
root.geometry('400x200')
#root.columnconfigure( 1, weight = 1 )
#root.rowconfigure( 1, weight = 0 )
#This function will ensure that at least one item is selected
def SwitchState():
if SelName_V.get() == 0 and SelPk_V.get() == 0:
QuestionOpenbtn.config(state = DISABLED)
else:
QuestionOpenbtn.config(state = NORMAL)
Introlbl = Label(root, text = "Welcome to the amino acid study aid. Down below you can choose what you'd like to focus on.", wraplength = 300)
#Introlbl.grid(column = 1, row = 0 )
Introlbl.pack()
SelName_V = IntVar()
SelPk_V = IntVar()
SelName = Checkbutton(root, text = "Amino Acid Identification", command = SwitchState, wraplength = 100, variable = SelName_V, onvalue = 1, offvalue = 0)
SelPk = Checkbutton(root, text = "Amino Charge", command = SwitchState, height = 2, width = 10, variable = SelPk_V, onvalue = 1, offvalue = 0)
#SelName.grid(column = 1, row = 1)
SelName.pack()
#SelPk.grid(column = 1, row = 2)
SelPk.pack()
QuestionOpenbtn = Button(root, text = "Show Selection Questions", command = openQuestionWindow)
#QuestionOpenbtn.grid(column = 1, row = 3)
QuestionOpenbtn.pack()
CloseWindowBtn = Button(root, text = "Close", command = lambda: root.destroy())
#CloseWindowBtn.grid(column = 1, row = 4)
CloseWindowBtn.pack()
QuestionOpenbtn.config(state = DISABLED)
root.mainloop()
I'm very unfamiliar with classes and had a hard time setting everything up and had issues with being unable to interact between the two.
CodePudding user response:
Yes. You seriously need to learn about python lists and dictionaries. Your code could be about three times shorted.
Also, not all data needs to be part of the code. Loading the amino acid names and properties from a text file would have separated concerns of logic and data.
And, you know C , so you should know better than to use globals. You have no use case for them, so properly design your function interfaces and get rid of those you use to exchange data. However, declaring globals within a function body at the start probably means you do not understand what that means - so please revisit the official python.org introduction on writing basic python.
CodePudding user response:
one small suggestion I can give you is to use 'switch' condition instead of this ifelse (because it's ugly seeing it too much). now if you want a quick fix to hide those variables in the beginning of the code, you can wrap them with "if(true){all variables goes here}". then you can 'expand/collapse' it using your editor. Also you can wrap it with comment to know what is wrapped. I know this is 'unprofessional' but I personally use sometimes I thought I throw it here ..