Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import tkinter as tk
- import tkinter.messagebox
- import csv
- import datetime
- from fpdf import FPDF
- import os
- import webbrowser
- # Setting constants used
- TITLE_FONT = ("Segoe UI", 26)
- SUB_TEXT_FONT = ("Segoe UI", 12)
- ADMIN_USERNAME = "admin"
- ADMIN_PASSWORD = "admin"
- POSITIONS = []
- with open("config.txt", "r") as config_file_txt:
- csv_reader = csv.reader(config_file_txt)
- for config in csv_reader:
- if config[0] == "positions":
- for index, position_name in enumerate(config):
- if index != 0:
- POSITIONS.append(position_name)
- # Function to make PDF file with results
- def make_printout(data, controller):
- # Check if 'results.pdf' already exists or is open
- if os.path.isfile("results.pdf"):
- try:
- os.remove("results.pdf")
- except WindowsError:
- tk.messagebox.showerror("Error", "The file 'results.pdf' is already open, please close it.")
- return None
- # Construct PDF
- pdf = FPDF()
- pdf.add_page()
- pdf.set_font("Arial", size=14, style="B")
- pdf.cell(200, 10, txt="Voting Results", ln=1, align="C")
- pdf.image("gsu_logo.png", x=10, y=8, w=35)
- pdf.ln(10)
- for position in data.items():
- candidates = position[1]
- pdf.set_font("Arial", size=14, style="B")
- pdf.cell(100, 10, txt=position[0], ln=1)
- pdf.set_font("Arial", size=11)
- pdf.cell(35, 6, txt="Candidate", align="C")
- pdf.cell(35, 6, txt="1st preference", align="C")
- pdf.cell(35, 6, txt="2nd preference", align="C")
- pdf.cell(35, 6, txt="3rd preference", align="C")
- pdf.cell(35, 6, txt="4th preference", align="C", ln=1)
- candidates_sorted = []
- for candidate in candidates.items():
- row = [candidate[0], candidate[1][0], candidate[1][1], candidate[1][2], candidate[1][3]]
- candidates_sorted.append(row)
- candidates_sorted.sort()
- for candidate in candidates_sorted:
- pdf.cell(35, 6, txt=candidate[0], align="C")
- pdf.cell(35, 6, txt=str(candidate[1]), align="C")
- pdf.cell(35, 6, txt=str(candidate[2]), align="C")
- pdf.cell(35, 6, txt=str(candidate[3]), align="C")
- pdf.cell(35, 6, txt=str(candidate[4]), align="C", ln=1)
- pdf.ln(5)
- candidates = controller.votes.get_winner(position[0])
- pdf.cell(100, 6, txt="Winner: " + candidates[0][4], ln=1)
- total_votes = 0
- for vote in candidates:
- total_votes += vote[0]
- text = "Votes received: " + str(candidates[0][0]) + " ("\
- + str(int(round((candidates[0][0] / total_votes) * 100))) + "%)"
- pdf.cell(100, 6, txt=text, ln=1)
- pdf.cell(100, 6, txt="Total votes: " + str(total_votes), ln=1)
- pdf.ln(7)
- pdf.output("results.pdf")
- webbrowser.open_new("results.pdf")
- # Function to make a title label
- def title_label(root, text, grid):
- if grid:
- return tk.Label(root, text=text, font=TITLE_FONT) \
- .grid(column=0, row=0, columnspan=2, sticky=tk.W, padx=40, pady=10)
- return tk.Label(root, text=text, font=TITLE_FONT)
- # Function to make normal text
- def sub_text(root, text):
- return tk.Label(root, text=text, font=SUB_TEXT_FONT)
- class User:
- def __init__(self, login_id, first_name, last_name):
- # Basic details about user
- self.login_id = login_id
- self.first_name = first_name
- self.last_name = last_name
- self.preferences_voted = {}
- # self.preferences_voted = {
- # "President": self.is_pref_full("President"),
- # "GSU Officer": self.is_pref_full("GSU Officer"),
- # "Faculty Officer": self.is_pref_full("Faculty Officer")
- # }
- for position in POSITIONS:
- self.preferences_voted[position] = self.is_pref_full(position)
- self.can_vote = self.votes_available()
- self.position_chosen = ""
- def votes_available(self):
- # Check if all positions have been fully voted for
- if not self.preferences_voted["President"][0] and not self.preferences_voted["GSU Officer"][0] \
- and not self.preferences_voted["Faculty Officer"][0]:
- return False
- return True
- def is_pref_full(self, position):
- preferences_chosen = []
- with open("Votes.txt", "r") as votes_file:
- reader = csv.reader(votes_file)
- for line in reader:
- # Look for votes for user and position
- if line[2] == self.login_id and line[5] == position:
- preferences_chosen.append([line[6], line[3], line[4]])
- # If 4 votes exists, change can_vote
- if len(preferences_chosen) == 4:
- can_vote = False
- btn_state = "disabled"
- else:
- can_vote = True
- btn_state = "normal"
- return [can_vote, preferences_chosen, btn_state]
- class Application(tk.Tk):
- def __init__(self, *args, **kwargs):
- self.votes = Votes()
- self.current_user = User("", "", "")
- tk.Tk.__init__(self, *args, **kwargs)
- self.title("Voting System")
- self.position_voting = ""
- self.position_admining = ""
- self.position_viewing = ""
- container = tk.Frame(self)
- container.pack(expand=True, side="top", fill="both")
- container.grid_rowconfigure(0, weight=1)
- container.grid_columnconfigure(0, weight=1)
- self.frames = {}
- # Place all frames inside the main tkinter root
- for x in (LoginFrame, ChoosePositionFrame, CheckDate, VoteFrame, VoteFrame1, VoteFrame2,
- ManagementInterfaceFrame, ChooseDateFrame, EditPositionsFrame, ViewResultsFrame, ChooseDetailsFrame,
- ViewDetailsFrame):
- frame = x(container, self)
- self.frames[x] = frame
- frame.grid(column=0, row=0, sticky=tk.NSEW)
- # Show first frame
- self.show_frame(LoginFrame)
- def show_frame(self, name):
- frame = self.frames[name]
- # Check for frame name to see if function needs to be called before showing frame
- if name == ChoosePositionFrame:
- self.geometry("400x610")
- frame.make_title(self)
- elif name == CheckDate:
- if frame.in_date:
- self.geometry("400x610")
- frame = self.frames[ChoosePositionFrame]
- frame.make_title(self)
- else:
- self.geometry("400x190")
- elif name == VoteFrame:
- frame = self.frames[frame.on_open(self)]
- self.geometry("400x350")
- frame.make_ui(self, self.current_user.position_chosen)
- elif name == ViewDetailsFrame:
- frame.on_open()
- elif name == LoginFrame:
- self.geometry("400x230")
- elif name == ViewResultsFrame:
- self.geometry("400x350")
- elif name == ChooseDetailsFrame:
- self.geometry("400x570")
- elif name == ManagementInterfaceFrame:
- self.geometry("400x600")
- elif name == EditPositionsFrame:
- self.geometry("400x370")
- elif name == ChooseDateFrame:
- self.geometry("400x200")
- frame.tkraise()
- class LoginFrame(tk.Frame):
- def __init__(self, parent, controller):
- # Create UI
- tk.Frame.__init__(self, parent)
- title_label(self, "Login", True)
- sub_text(self, "Login ID:").grid(padx=42, row=1, column=0, sticky=tk.W)
- self.login_id_entry = tk.Entry(self, width=32)
- self.login_id_entry.grid(row=1, column=1, sticky=tk.E)
- sub_text(self, "Password:").grid(padx=42, pady=10, row=2, column=0, sticky=tk.W)
- self.password_entry = tk.Entry(self, width=32, show="*")
- self.password_entry.grid(row=2, column=1, sticky=tk.E)
- tk.Button(self, text="Submit", command=lambda: self.check_password(controller), height=2, width=10) \
- .grid(pady=10, row=3, column=1, sticky=tk.E)
- tk.Button(self, text="Exit", command=controller.destroy, width=10, height=2) \
- .grid(pady=10, row=3, column=0, sticky=tk.W, padx=(42, 0))
- def check_password(self, controller):
- # Check if admin details is entered
- if self.login_id_entry.get() == ADMIN_USERNAME and self.password_entry.get() == ADMIN_PASSWORD:
- self.password_entry.delete(0, "end")
- self.login_id_entry.delete(0, "end")
- controller.show_frame(ManagementInterfaceFrame)
- return None
- # Check for details in 'StudentVoters.txt'
- with open("StudentVoters.txt", "r", newline="") as student_voters:
- reader = csv.reader(student_voters)
- if not self.login_id_entry.get() in [item[0] for item in reader]:
- tk.messagebox.showerror("Incorrect details", "Your user ID was not found.")
- return None
- # Reset file reading position
- student_voters.seek(0)
- for user in reader:
- if user[0] == self.login_id_entry.get() and user[3] == self.password_entry.get():
- controller.current_user = User(user[0], user[1], user[2])
- self.password_entry.delete(0, "end")
- self.login_id_entry.delete(0, "end")
- controller.show_frame(CheckDate)
- return None
- tk.messagebox.showerror("Incorrect details", "The login ID or password you entered is incorrect.")
- class CheckDate(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- # Set in_date attribute, which is checked when controller.show_frame is called from any class
- self.in_date = True
- # Read config file
- with open("config.txt", "r") as config_file:
- reader = csv.reader(config_file)
- for line in reader:
- if line[0] == "start_date":
- self.start_date = datetime.datetime.strptime(line[1], "%d-%m-%Y %H:%M")
- elif line[0] == "end_date":
- self.end_date = datetime.datetime.strptime(line[1], "%d-%m-%Y %H:%M")
- # Compare current date to dates set in config
- self.current_date = datetime.datetime.now()
- if self.end_date < self.current_date:
- title_label(self, "Voting session ended", True)
- tk.Label(self, text="Voting ended on " + self.end_date.strftime("%d/%m/%Y") + ".", width=32, anchor=tk.W,
- font=SUB_TEXT_FONT) \
- .grid(padx=42, row=1, column=0, sticky=tk.W)
- self.in_date = False
- tk.Button(self, text="View results", command=lambda: controller.show_frame(ViewResultsFrame), height=2,
- width=10).grid(pady=20, row=2, column=0, sticky=tk.E, padx=42)
- elif self.start_date >= self.current_date:
- title_label(self, "Voting session\nnot started yet", True)
- tk.Label(self, text="Voting will start from " + self.start_date.strftime("%d/%m/%Y") + ".", width=29,
- anchor=tk.W, font=SUB_TEXT_FONT) \
- .grid(padx=42, row=1, column=0)
- self.in_date = False
- tk.Button(self, text="Back", command=lambda: controller.show_frame(LoginFrame), height=2, width=10) \
- .grid(pady=20, row=2, column=0, sticky=tk.W, padx=42)
- class EditPositionsFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- title_label(self, "Edit candidates", True)
- tk.Label(self, text="Enter 4 new candidates:", width=34, anchor=tk.W, font=SUB_TEXT_FONT) \
- .grid(row=1, column=0, sticky=tk.W, padx=(42, 0))
- tk.Label(self, text="WARNING: This will erase all existing candidates", fg="red") \
- .grid(row=2, column=0, padx=(42, 0), sticky=tk.W)
- # Generate 4 entry boxes for candidates' names
- self.entries = []
- for i in range(4):
- self.entries.append(tk.Entry(self, width=30))
- self.entries[i].grid(row=i + 3, column=0, sticky=tk.W, padx=(42, 0), pady=10)
- tk.Button(self, text="Back", width=10, height=2,
- command=lambda: controller.show_frame(ManagementInterfaceFrame))\
- .grid(row=7, column=0, sticky=tk.W, pady=10, padx=(42, 0))
- tk.Button(self, text="Submit", width=10, height=2, command=lambda: self.submit_candidates(controller))\
- .grid(row=7, column=0, sticky=tk.E, pady=10)
- def submit_candidates(self, controller):
- new_candidates = []
- position = controller.position_admining
- positions_entered = []
- # Check input data and extract information
- for entry in self.entries:
- positions_entered.append(entry.get())
- if entry.get().strip() == "":
- tk.messagebox.showerror("Error", "Please enter a value in all 4 entries")
- return None
- if len(entry.get().strip().split()) != 2:
- tk.messagebox.showerror("Error", "Please enter two names in each field")
- return None
- first_name = entry.get().strip().split()[0]
- last_name = entry.get().strip().split()[1]
- new_candidates.append([position, first_name, last_name])
- # Check for duplicates in entry boxes
- if len(new_candidates) != len([list(i) for i in set(map(tuple, new_candidates))]):
- tk.messagebox.showerror("Error", "Please ensure there are no duplicates")
- return None
- # Check if candidate already existing for another position
- with open("GSUCandidates.txt", "r") as cand_file:
- reader = csv.reader(cand_file)
- for candidate in reader:
- if candidate[0] != controller.position_admining:
- if candidate[1] + " " + candidate[2] in positions_entered:
- tk.messagebox.showerror("Error", "Candidate already exists for a different position.")
- return None
- new_candidates.append(candidate)
- # Write candidates into file
- with open("GSUCandidates.txt", "w", newline="") as cand_file:
- writer = csv.writer(cand_file)
- for candidate in new_candidates:
- writer.writerow(candidate)
- for entry in self.entries:
- entry.delete(0, "end")
- # Remove votes for position editing
- votes = []
- with open("Votes.txt", "r") as cand_file:
- reader = csv.reader(cand_file)
- for vote in reader:
- if vote[5] != position:
- votes.append(vote)
- with open("Votes.txt", "w", newline="") as cand_file:
- writer = csv.writer(cand_file)
- for vote in votes:
- writer.writerow(vote)
- controller.show_frame(ManagementInterfaceFrame)
- class ManagementInterfaceFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- title_label(self, "Management", True)
- tk.Label(self, text="Choose a position to edit:", width=35, anchor=tk.W, font=SUB_TEXT_FONT) \
- .grid(row=1, column=0, sticky=tk.W, padx=(42, 0))
- buttons = []
- # Create button for every position
- for x, name in enumerate(POSITIONS):
- buttons.append(tk.Button(self, text=name, height=2, width=23,
- command=lambda i=name: self.choose_position(i, controller)))
- buttons[x].grid(row=x + 2, column=0, pady=10, padx=(42, 0))
- tk.Button(self, text="Edit voting dates", width=23, height=2,
- command=lambda: controller.show_frame(ChooseDateFrame)).grid(row=len(POSITIONS) + 2, column=0,
- pady=10, padx=(42, 0))
- tk.Button(self, text="Back", width=10, height=2, command=lambda: controller.show_frame(LoginFrame)).grid(
- pady=10, row=len(POSITIONS) + 3, column=0, sticky=tk.W, padx=42)
- def choose_position(self, position, controller):
- # Set controller attribute for next class to find
- controller.position_admining = position
- controller.show_frame(EditPositionsFrame)
- class ChooseDateFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- tk.Label(self, text="Choose dates", width=13, anchor=tk.W, font=TITLE_FONT)\
- .grid(padx=42, row=0, column=0, sticky=tk.W, columnspan=2)
- tk.Label(self, text="Start date:", font=SUB_TEXT_FONT)\
- .grid(row=1, column=0, sticky=tk.W, padx=(42, 0))
- tk.Label(self, text="End date:", font=SUB_TEXT_FONT)\
- .grid(row=2, column=0, sticky=tk.W, padx=(42, 0))
- # Get dates from config file and put values in entries
- with open("config.txt", "r") as config_file:
- reader = csv.reader(config_file)
- for line in reader:
- if line[0] == "start_date":
- self.start_date = datetime.datetime.strptime(line[1], "%d-%m-%Y %H:%M")
- self.start_date = datetime.datetime.strftime(self.start_date, "%d-%m-%Y %H:%M")
- elif line[0] == "end_date":
- self.end_date = datetime.datetime.strptime(line[1], "%d-%m-%Y %H:%M")
- self.end_date = datetime.datetime.strftime(self.end_date, "%d-%m-%Y %H:%M")
- self.start_date_entry = tk.Entry(self)
- self.start_date_entry.insert(0, self.start_date)
- self.start_date_entry.grid(row=1, column=1, sticky=tk.EW, pady=5)
- self.end_date_entry = tk.Entry(self)
- self.end_date_entry.insert(0, self.end_date)
- self.end_date_entry.grid(row=2, column=1, sticky=tk.EW, pady=5)
- tk.Button(self, text="Back", width=10, height=2,
- command=lambda: controller.show_frame(ManagementInterfaceFrame)) \
- .grid(row=4, column=0, sticky=tk.W, padx=(42, 0), pady=10)
- tk.Button(self, text="Submit", width=10, height=2, command=lambda: self.change_date(controller)) \
- .grid(row=4, column=1, sticky=tk.E, pady=10)
- def change_date(self, controller):
- # Check format of entry
- try:
- datetime.datetime.strptime(self.end_date_entry.get(), "%d-%m-%Y %H:%M")
- datetime.datetime.strptime(self.start_date_entry.get(), "%d-%m-%Y %H:%M")
- except ValueError:
- tk.messagebox.showerror("Error",
- "Please enter the date and time in the correct format (DD-MM-YYYY HH: MM)")
- return None
- # Write dates into config file
- with open("config.txt", "w", newline="") as config_file:
- writer = csv.writer(config_file)
- writer.writerow(["start_date", self.start_date_entry.get()])
- writer.writerow(["end_date", self.end_date_entry.get()])
- controller.show_frame(ManagementInterfaceFrame)
- def make_choices(controller, position):
- with open("GSUCandidates.txt", "r") as cand_file:
- reader = csv.reader(cand_file)
- candidates_voted = controller.current_user.preferences_voted[position]
- candidates_voted_names = []
- for candidate in candidates_voted[1]:
- candidates_voted_names.append(candidate[1] + " " + candidate[2])
- candidates_available = []
- for candidate in reader:
- if candidate[0] == position:
- if not str(candidate[1] + " " + candidate[2]) in candidates_voted_names:
- candidates_available.append([str(candidate[1] + " " + candidate[2]), [candidate[1], candidate[2]]])
- return candidates_available
- # Function for first vote
- def cast_vote_1(controller, name, preference, position):
- cast_vote(controller, name, preference, position)
- controller.current_user.position_chosen = position
- controller.show_frame(VoteFrame)
- # Function to handle 2nd, 3rd and 4th vote
- def cast_vote_2(controller, choice_boxes, position):
- if len([item[0].get() for item in choice_boxes]) != len(set([item[0].get() for item in choice_boxes])):
- tk.messagebox.showerror("Invalid options", "You have selected a candidate more than once.")
- return None
- for i, choice_box in enumerate(choice_boxes):
- if not choice_box[0].get() == "N/A" and not choice_box[0].get()[0] == "(":
- cast_vote(controller, choice_box[0].get(), str(i + 2), position)
- controller.show_frame(ChoosePositionFrame)
- # Function to add individual vote into votes file
- def cast_vote(controller, name, preference, position):
- first_name = name.split()[0]
- last_name = name.split()[1]
- with open("Votes.txt", "a", newline="") as vote_file:
- csv.writer(vote_file).writerow([controller.current_user.first_name, controller.current_user.last_name,
- controller.current_user.login_id, first_name, last_name, position, preference])
- controller.current_user.__init__(controller.current_user.login_id, controller.current_user.first_name,
- controller.current_user.last_name)
- class ChoosePositionFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.make_title(controller)
- def make_title(self, controller):
- subtitle = tk.Label(self, text="You have already voted", font=SUB_TEXT_FONT, width=34, anchor=tk.W)
- subtitle.grid(padx=42, row=1, column=0, sticky=tk.W)
- # Destroy title and make new one if title already exists
- if hasattr(self, "title"):
- self.title.destroy()
- self.title = title_label(self, "Hey there " + controller.current_user.first_name + "!", False)
- self.title.grid(column=0, row=0, columnspan=2, sticky=tk.W, padx=40, pady=10)
- # Change text if current_user can_vote is true
- if controller.current_user.can_vote:
- subtitle.config(text="Choose a position to vote for:")
- self.draw_buttons(controller)
- def cast_vote(self, position, controller):
- # Change position_chosen to be accessed by other classes
- controller.current_user.position_chosen = position
- controller.show_frame(VoteFrame)
- def draw_buttons(self, controller):
- # Make buttons for each position
- buttons = []
- for x, name in enumerate(POSITIONS):
- buttons.append(tk.Button(self, text=name, height=2, width=25,
- state=controller.current_user.preferences_voted[name][2],
- command=lambda i=name: self.cast_vote(i, controller)))
- buttons[x].grid(row=x + 2, column=0, pady=15)
- tk.Button(self, text="Back", command=lambda: controller.show_frame(LoginFrame), height=2, width=10).grid(
- pady=20, row=len(POSITIONS) + 2, column=0, padx=42, sticky=tk.W)
- # Frame to redirect to the correct frame depending on votes made
- class VoteFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- def on_open(self, controller):
- if len(make_choices(controller, controller.current_user.position_chosen)) == 4:
- return VoteFrame1
- else:
- return VoteFrame2
- # Frame for 1st vote
- class VoteFrame1(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- title_label(self, "Vote", True)
- tk.Label(self, text="Choose your first preference:", width=29, anchor=tk.W, font=SUB_TEXT_FONT) \
- .grid(row=1, column=0, padx=42)
- tk.Button(self, text="Back", width=10, height=2, command=lambda: controller.show_frame(ChoosePositionFrame)) \
- .grid(row=3, column=0, sticky=tk.W, pady=10, padx=42)
- self.options = []
- self.default_value = tk.StringVar(self)
- def make_ui(self, controller, position):
- self.options = []
- # Get options available
- for candidate in make_choices(controller, position):
- self.options.append(candidate[0])
- # Remove OptionMenu if already exists in class
- if hasattr(self, "choice_box"):
- self.choice_box.destroy()
- self.default_value = tk.StringVar(self)
- self.default_value.set(self.options[0])
- self.choice_box = tk.OptionMenu(self, self.default_value, *self.options)
- self.choice_box.grid(column=0, row=2, padx=42, sticky=tk.W, pady=10)
- tk.Button(self, text="Submit", height=2, width=10,
- command=lambda: cast_vote_1(controller, self.default_value.get(), "1", position)) \
- .grid(pady=10, row=3, column=0, sticky=tk.E)
- # Frame for 2nd, 3rd and 4th vote
- class VoteFrame2(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- title_label(self, "Vote", True)
- tk.Label(self, text="Choose your other preferences:", width=29, anchor=tk.W, font=SUB_TEXT_FONT) \
- .grid(columnspan=2, row=1, column=0, padx=42, sticky=tk.W)
- self.options = ["N/A"]
- self.choice_boxes = []
- self.choice_labels = []
- def make_ui(self, controller, position):
- self.options = ["N/A"]
- self.choice_labels = []
- # Get candidates
- for candidate in make_choices(controller, position):
- self.options.append(candidate[0])
- if len(self.choice_boxes) == 3:
- for choice_box in self.choice_boxes:
- choice_box[1].destroy()
- self.choice_boxes = []
- preferences_voted = []
- for candidate in controller.current_user.preferences_voted[position][1]:
- preferences_voted.append(candidate[0])
- # Create choice boxes
- for x in range(3):
- sub_text(self, "Pref " + str(x + 2) + ":").grid(column=0, row=x + 3, padx=42, sticky=tk.W)
- self.choice_boxes.append([])
- self.choice_boxes[x].append(tk.StringVar(self))
- # Check if preference already voted for
- if str(x + 2) in preferences_voted:
- self.choice_boxes[x].append(tk.OptionMenu(self, self.choice_boxes[x][0], *self.options))
- self.choice_boxes[x][1].configure(state="disabled")
- for i, vote in enumerate(controller.current_user.preferences_voted[position][1]):
- if vote[0] == str(x + 2):
- self.choice_boxes[x][0].set(controller.current_user.preferences_voted[position][1][i][1:3])
- else:
- self.choice_boxes[x].append(tk.OptionMenu(self, self.choice_boxes[x][0], *self.options))
- self.choice_boxes[x][0].set(self.options[0])
- self.choice_boxes[x][1].grid(column=1, row=x + 3, padx=0, pady=10, sticky=tk.EW)
- self.choice_boxes[x][1].config(width=20)
- tk.Button(self, text="Back", width=10, height=2, command=lambda: controller.show_frame(ChoosePositionFrame)) \
- .grid(column=0, row=6, sticky=tk.W, padx=(42, 0), pady=10, columnspan=2)
- tk.Button(self, text="Submit", width=10, height=2,
- command=lambda: cast_vote_2(controller, self.choice_boxes, controller.current_user.position_chosen)) \
- .grid(column=0, row=6, sticky=tk.E, pady=10, columnspan=2)
- class Votes:
- def __init__(self):
- # self.votes = {
- # "President": {},
- # "GSU Officer": {},
- # "Faculty Officer": {}
- # }
- self.votes = {}
- for position in POSITIONS:
- self.votes[position] = {}
- # Add dictionaries with empty lists inside votes attribute
- with open("GSUCandidates.txt", "r") as cand_file:
- reader = csv.reader(cand_file)
- for candidate in reader:
- self.votes[candidate[0]][str(candidate[1] + " " + candidate[2])] = [0, 0, 0, 0]
- # Add up votes from votes file
- with open("Votes.txt", "r") as votes_file:
- reader = csv.reader(votes_file)
- for vote in reader:
- self.votes[vote[5]][str(vote[3] + " " + vote[4])][int(vote[6]) - 1] += 1
- def get_winner(self, position):
- # Sort candidates by votes
- votes_formed = []
- for candidate in self.votes[position].items():
- votes_formed.append([candidate[1][0], candidate[1][1], candidate[1][2], candidate[1][3], candidate[0]])
- votes_formed.sort(reverse=True)
- if votes_formed[0] == votes_formed[1]:
- tk.messagebox.showerror("No winner", "Unfortunately, there was no winner for "
- + position + ". A re-election is recommended. ")
- return votes_formed
- # Frame with summary statistics of the election
- class ViewResultsFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- tk.Label(self, text="Results", anchor=tk.W, font=TITLE_FONT, width=13).grid(row=0, column=0, sticky=tk.W,
- padx=42)
- for i, position in enumerate(POSITIONS):
- winner = controller.votes.get_winner(position)
- text = position + " winner: " + winner[0][4] + "."
- tk.Label(self, text=text, anchor=tk.W).grid(row=i + 1, column=0, sticky=tk.W, pady=3, padx=(42, 0))
- tk.Button(self, text="Back", width=10, height=2, command=lambda: controller.show_frame(CheckDate)) \
- .grid(row=len(POSITIONS) + 1, column=0, sticky=tk.W, padx=(42, 0), pady=10)
- tk.Button(self, text="Details", width=10, height=2, command=lambda: controller.show_frame(ChooseDetailsFrame)) \
- .grid(row=len(POSITIONS) + 1, column=0, sticky=tk.E, pady=10)
- tk.Button(self, text="Print", width=10, height=2,
- command=lambda: make_printout(controller.votes.votes, controller)) \
- .grid(row=len(POSITIONS) + 2, column=0, sticky=tk.E, pady=5)
- # Frame to show details of each position
- class ViewDetailsFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.controller = controller
- tk.Button(self, text="Back", width=10, height=2, command=self.go_back)\
- .grid(row=9, column=0, sticky=tk.W, padx=(42, 0), pady=10)
- def on_open(self):
- # Remove title if already made
- if hasattr(self, "title"):
- self.title.destroy()
- for label in self.summary_labels:
- label.destroy()
- position_votes = self.controller.votes.get_winner(self.controller.position_viewing)
- rows_of_text = [["Candidate", "1st pref", "2nd pref", "3rd pref", "4th pref"]]
- position_votes = sorted(position_votes, key=lambda o: o[4])
- candidates = self.controller.votes.get_winner(self.controller.position_viewing)
- # Create a table using vote data
- labels = []
- for vote in position_votes:
- rows_of_text.append([vote[4], str(vote[0]), str(vote[1]), str(vote[2]), str(vote[3])])
- for x, row in enumerate(rows_of_text):
- for i, col in enumerate(row):
- if i == 0:
- labels.append(tk.Label(self, text=col, width=10))
- labels[5*x+i].grid(padx=(42, 0), pady=5, row=x + 1, column=i)
- else:
- labels.append(tk.Label(self, text=col, width=10))
- labels[5*x+i].grid(pady=5, row=x + 1, column=i)
- # Calculate summary statistics
- total_votes = 0
- for vote in candidates:
- total_votes += vote[0]
- self.summary_labels = []
- self.summary_labels.append(tk.Label(self, text="Winner: " + candidates[0][4], font=SUB_TEXT_FONT))
- self.summary_labels[0].grid(row=6, column=0, columnspan=5, sticky=tk.W, padx=(42, 0), pady=5)
- text = "Votes received: " + str(candidates[0][0]) + " ("\
- + str(int(round((candidates[0][0] / total_votes) * 100))) + "%)"
- self.summary_labels.append(tk.Label(self, text=text, font=SUB_TEXT_FONT))
- self.summary_labels[1].grid(row=7, column=0, columnspan=5, sticky=tk.W, padx=(42, 0), pady=5)
- self.summary_labels.append(tk.Label(self, text="Total votes: " + str(total_votes), font=SUB_TEXT_FONT))
- self.summary_labels[2].grid(row=8, column=0, columnspan=5, sticky=tk.W, padx=(42, 0), pady=5)
- self.title = tk.Label(self, text=self.controller.position_viewing, anchor=tk.W, font=TITLE_FONT, width=13)
- self.title.grid(row=0, column=0, sticky=tk.W, padx=42, columnspan=5)
- # Make window bigger to accompany more data
- self.controller.geometry("460x410")
- def go_back(self):
- # Change window size back
- self.controller.geometry("400x410")
- self.controller.show_frame(ChooseDetailsFrame)
- class ChooseDetailsFrame(tk.Frame):
- def __init__(self, parent, controller):
- tk.Frame.__init__(self, parent)
- self.controller = controller
- tk.Label(self, text="View details", anchor=tk.W, font=TITLE_FONT, width=13)\
- .grid(row=0, column=0, sticky=tk.W, padx=42)
- # Create buttons for each position
- buttons = []
- for x, name in enumerate(POSITIONS):
- buttons.append(tk.Button(self, text=name, height=2, width=25,
- state=controller.current_user.preferences_voted[name][2],
- command=lambda i=name: self.view_details(i)))
- buttons[x].grid(row=x + 1, column=0, pady=15, padx=(42, 0))
- tk.Button(self, text="Back", width=10, height=2, command=lambda: controller.show_frame(ViewResultsFrame))\
- .grid(row=len(POSITIONS) + 1, column=0, sticky=tk.W, padx=(42, 0), pady=10)
- def view_details(self, position):
- self.controller.position_viewing = position
- self.controller.show_frame(ViewDetailsFrame)
- if __name__ == "__main__":
- # Create tkinter application
- app = Application()
- app.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement