From e6006463feee1b12af9b305791bfd5eafc84e92f Mon Sep 17 00:00:00 2001 From: AnasKhan0607 <76663779+AnasKhan0607@users.noreply.github.com> Date: Mon, 22 Mar 2021 21:56:10 -0400 Subject: [PATCH 01/21] commit --- apicollect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apicollect.py b/apicollect.py index 5e6da95..a7137ea 100644 --- a/apicollect.py +++ b/apicollect.py @@ -60,4 +60,6 @@ def test_get_player_info(self): # Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch ov = Overwatch('pc', 'us', 'cats-11481') ov.get_filers() +print("hey") +print("testing push") From 29b3eb977f6f47da74ad69ed982db42bad49d248 Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sat, 27 Mar 2021 14:21:10 -0400 Subject: [PATCH 02/21] Implemented methods to compare 2 players --- apicollect.py | 156 +++++++++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/apicollect.py b/apicollect.py index a7137ea..33049c5 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,65 +1,91 @@ -import requests -# API address we can fill the parameters: platform, region and battle tag of a player to get their profile -url = 'https://ow-api.com/v1/stats/{}/{}/{}/profile' - - -class Overwatch: - def __init__(self, platform, region, battle_tag): - # Send a request to the api to get information about the user profile - self.result = requests.get(url.format(platform, region, battle_tag)) - # Convert to JSON (basically dictionary formatted info) - self.result_json = self.result.json() - # List of all filters for player to select - self.filters = [] - - def get_filers(self): - """ - Get the main filters(stats) available for a user to select to compare with another player. - We don't really care about icon, level icon, etc. for this since they aren't stats used for comparision. - - :return: list of possible filters - """ - - # The primary filters - self.filters.extend(['name', 'level', 'prestige', 'rating', 'gamesWon']) - - # - for match_filter in ['quickPlayStats', 'competitiveStats']: - qp_game_filters = [] - qp_award_filters = [] - qp_total_filters = [] - for qp_filter in self.result_json[match_filter]: - if qp_filter == 'games': - for game_filter in self.result_json[match_filter]['games']: - qp_game_filters.extend(([game_filter])) - qp_total_filters.extend([qp_filter, qp_game_filters]) - elif qp_filter == 'awards': - - for award_filter in self.result_json[match_filter]['awards']: - qp_award_filters.extend(([award_filter])) - - qp_total_filters.extend([qp_filter, qp_award_filters]) - self.filters.extend([[match_filter, qp_total_filters]]) - return self.filters - - def test_get_player_info(self): - """ - This is just a simple example of how to make API requests for demonstration purposes. - :return: - """ - if self.result: - name = self.result_json['name'] - games_won = self.result_json['gamesWon'] - level = self.result_json['level'] - rating = self.result_json['rating'] - return [name, games_won, level, rating] - else: - return None - - -# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch -ov = Overwatch('pc', 'us', 'cats-11481') -ov.get_filers() -print("hey") -print("testing push") - +import requests +# API address we can fill the parameters: platform, region and battle tag of a player to get their profile +url = 'https://ow-api.com/v1/stats/{}/{}/{}/profile' + + +class Overwatch: + def __init__(self, platform, region, battle_tag): + # Send a request to the api to get information about the user profile + self.result = requests.get(url.format(platform, region, battle_tag)) + # Convert to JSON (basically dictionary formatted info) + self.result_json = self.result.json() + # List of all filters for player to select + self.filters = [] + + def get_filers(self): + """ + Get the main filters(stats) available for a user to select to compare with another player. + We don't really care about icon, level icon, etc. for this since they aren't stats used for comparision. + + :return: list of possible filters + """ + + # The primary filters + self.filters.extend(['name', 'level', 'prestige', 'rating', 'gamesWon']) + + # + for match_filter in ['quickPlayStats', 'competitiveStats']: + qp_game_filters = [] + qp_award_filters = [] + qp_total_filters = [] + for qp_filter in self.result_json[match_filter]: + if qp_filter == 'games': + for game_filter in self.result_json[match_filter]['games']: + qp_game_filters.extend(([game_filter])) + qp_total_filters.extend([qp_filter, qp_game_filters]) + elif qp_filter == 'awards': + + for award_filter in self.result_json[match_filter]['awards']: + qp_award_filters.extend(([award_filter])) + + qp_total_filters.extend([qp_filter, qp_award_filters]) + self.filters.extend([[match_filter, qp_total_filters]]) + return self.filters + + def test_get_player_info(self): + """ + This is just a simple example of how to make API requests for demonstration purposes. + :return: + """ + if self.result: + name = self.result_json['name'] + games_won = self.result_json['gamesWon'] + level = self.result_json['level'] + rating = self.result_json['rating'] + return [name, games_won, level, rating] + return None + + def analyze_stats(self, player): + """ + analyze the stats of a player and return an integer value representing its final + score after evaluation + + :param player: Battle Tag of player + :return: evaluation score + """ + if player == self.test_get_player_info()[0]: + player_stats = self.test_get_player_info() + return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations + return "Invalid player" + + def compare_2players(self, player1, player2): + """ + compares stats of 2 players, and returns the winning player + + :param player1: Battle Tag of player1 + :param player2: Battle Tag of player 2 + :return: player with higher stats, else return a message saying players are equal + """ + if self.analyze_stats(player1) > self.analyze_stats(player2): + return player1 + elif self.analyze_stats(player1) < self.analyze_stats(player2): + return player2 + return "Players are equal in comparison" + +# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch + + +ov = Overwatch('pc', 'us', 'cats-11481') +ov.get_filers() +print("hey") +print("testing push") From b9aa6ec0dc16ceff3e1553dfbb2eb63c98072d77 Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sat, 27 Mar 2021 14:22:06 -0400 Subject: [PATCH 03/21] Implemented Label beside entry boxes (To be fixed) --- GUI.py | 177 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 98 insertions(+), 79 deletions(-) diff --git a/GUI.py b/GUI.py index 936d5f7..fde3f7f 100644 --- a/GUI.py +++ b/GUI.py @@ -1,79 +1,98 @@ -from tkinter import * -from tkinter import ttk -from apicollect import Overwatch - -class FirstGUI: - """ - This is pertaining to Overwatch only, Remember that in the apicollect.py file, - Overwatch API requires you to put in platform, region and battle id of the player. - """ - def __init__(self, parent): - self.parent = parent - self.game = None - - self.frame = Frame(self.parent) - self.labelSelect = Label(self.frame, text='Choose a game to find stats to compare between multiple players') - self.labelSelect.grid(row=0, column=1) - self.game_chosen = StringVar() - # Create a dropdown menu - self.game_choices = ttk.Combobox(self.frame, state="readonly", textvariable=self.game_chosen, width=30) - # Default text shown - self.game_choices.set("Select a game") - # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] - self.game_choices.grid(row=1, column=1) - - """ - Idea: Maybe we can use validate commands for the entries - """ - # Entry for user to put in platform - platform_id = StringVar() - self.first_gamer_plat = Entry(self.frame, textvariable=platform_id) - self.first_gamer_plat.grid(row=2, column=1) - - # Entry for user to put in region - region_id = StringVar() - self.first_gamer_reg= Entry(self.frame, textvariable=region_id) - self.first_gamer_reg.grid(row=3, column=1) - - # Entry for user to put in battle_id - battle_id = StringVar() - self.first_gamer_batt = Entry(self.frame, textvariable=battle_id) - self.first_gamer_batt.grid(row=4, column=1) - - # Submit Button - self.sub_btn = Button(self.frame, text='Submit', command=self.submit) - self.sub_btn.grid(row=5, column=3) - - self.frame.pack() - # If a game option is selected call the callbackf function - self.game_choices.bind("<>", self.callback) - - def callback(self, event_object): - self.game = event_object.widget.get() - - def submit(self): - """ - Retrieve the values from each entry and check if they are valid. - """ - platform = self.first_gamer_plat.get() - region = self.first_gamer_reg.get() - battle_tag = self.first_gamer_batt.get() - - try: - o = Overwatch(platform, region, battle_tag) - if o.result: - # Simple check to see if values are valid - print(o.test_get_player_info()) - else: - print("Invalid Profile") - except: - # Need to likely change this try/except. Debugging required - print("Invalid Profile") - - -app = Tk() -gui = FirstGUI(app) -app.title("Game App") -app.geometry('500x600') -app.mainloop() \ No newline at end of file +from tkinter import * +from tkinter import ttk +from apicollect import Overwatch + + +class FirstGUI: + """ + This is pertaining to Overwatch only, Remember that in the apicollect.py file, + Overwatch API requires you to put in platform, region and battle id of the player. + """ + def __init__(self, parent): + self.parent = parent + self.game = None + + self.frame = Frame(self.parent) + self.labelSelect = Label(self.frame, text='Choose a game to find stats to compare between multiple players') + self.labelSelect.grid(row=0, column=1) + self.game_chosen = StringVar() + # Create a dropdown menu + self.game_choices = ttk.Combobox(self.frame, state="readonly", textvariable=self.game_chosen, width=30) + # Default text shown + self.game_choices.set("Select a game") + # Possible games to choose from: Cold war and WoW are examples for now + self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] + self.game_choices.grid(row=1, column=1) + + """ + Idea: Maybe we can use validate commands for the entries + """ + # Entry for user to put in platform + + # platform_label_text = StringVar() + # platform_label_text.set("Enter game platform (pc, etc)") + # self.label1 = Label(app, textvariable=platform_label_text, height=4) + # self.label1.grid(row=2, column=0) + + platform_id = StringVar() + self.first_gamer_plat = Entry(self.frame, textvariable=platform_id) + self.first_gamer_plat.grid(row=2, column=1) + + # Entry for user to put in region + + # region_label_text = StringVar() + # region_label_text.set("Enter game region (us, eu, asia)") + # self.label2 = Label(app, textvariable=region_label_text, height=4) + # self.label2.grid(row=3, column=0) + + region_id = StringVar() + self.first_gamer_reg = Entry(self.frame, textvariable=region_id) + self.first_gamer_reg.grid(row=3, column=1) + + # Entry for user to put in battle_id + + # battleID_label_text = StringVar() + # battleID_label_text.set("Your battlenet tag, replacing the # with a -") + # self.label3 = Label(app, textvariable=battleID_label_text, height=4) + # self.label3.grid(row=3, column=0) + + battle_id = StringVar() + self.first_gamer_batt = Entry(self.frame, textvariable=battle_id) + self.first_gamer_batt.grid(row=4, column=1) + + # Submit Button + self.sub_btn = Button(self.frame, text='Submit', command=self.submit) + self.sub_btn.grid(row=5, column=3) + + self.frame.pack() + # If a game option is selected call the callbackf function + self.game_choices.bind("<>", self.callback) + + def callback(self, event_object): + self.game = event_object.widget.get() + + def submit(self): + """ + Retrieve the values from each entry and check if they are valid. + """ + platform = self.first_gamer_plat.get() + region = self.first_gamer_reg.get() + battle_tag = self.first_gamer_batt.get() + + try: + o = Overwatch(platform, region, battle_tag) + if o.result: + # Simple check to see if values are valid + print(o.test_get_player_info()) + else: + print("Invalid Profile") + except: + # Need to likely change this try/except. Debugging required + print("Invalid Profile") + + +app = Tk() +gui = FirstGUI(app) +app.title("Game App") +app.geometry('500x600') +app.mainloop() From 0f0627287fa917c0ecfa3cd88619c825e15cf1f1 Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 7 Apr 2021 17:54:54 -0400 Subject: [PATCH 04/21] Almost finished the second stage --- GUI.py | 102 +++++--------------------------- Pages.py | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ apicollect.py | 3 +- 3 files changed, 176 insertions(+), 88 deletions(-) create mode 100644 Pages.py diff --git a/GUI.py b/GUI.py index fde3f7f..6596340 100644 --- a/GUI.py +++ b/GUI.py @@ -1,98 +1,28 @@ from tkinter import * from tkinter import ttk +import tkinter as tk +from Pages import PageOne from apicollect import Overwatch - -class FirstGUI: +class FirstGUI(tk.Tk): """ This is pertaining to Overwatch only, Remember that in the apicollect.py file, Overwatch API requires you to put in platform, region and battle id of the player. """ - def __init__(self, parent): - self.parent = parent - self.game = None - - self.frame = Frame(self.parent) - self.labelSelect = Label(self.frame, text='Choose a game to find stats to compare between multiple players') - self.labelSelect.grid(row=0, column=1) - self.game_chosen = StringVar() - # Create a dropdown menu - self.game_choices = ttk.Combobox(self.frame, state="readonly", textvariable=self.game_chosen, width=30) - # Default text shown - self.game_choices.set("Select a game") - # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] - self.game_choices.grid(row=1, column=1) - - """ - Idea: Maybe we can use validate commands for the entries - """ - # Entry for user to put in platform - - # platform_label_text = StringVar() - # platform_label_text.set("Enter game platform (pc, etc)") - # self.label1 = Label(app, textvariable=platform_label_text, height=4) - # self.label1.grid(row=2, column=0) - - platform_id = StringVar() - self.first_gamer_plat = Entry(self.frame, textvariable=platform_id) - self.first_gamer_plat.grid(row=2, column=1) - - # Entry for user to put in region - - # region_label_text = StringVar() - # region_label_text.set("Enter game region (us, eu, asia)") - # self.label2 = Label(app, textvariable=region_label_text, height=4) - # self.label2.grid(row=3, column=0) - - region_id = StringVar() - self.first_gamer_reg = Entry(self.frame, textvariable=region_id) - self.first_gamer_reg.grid(row=3, column=1) - - # Entry for user to put in battle_id - - # battleID_label_text = StringVar() - # battleID_label_text.set("Your battlenet tag, replacing the # with a -") - # self.label3 = Label(app, textvariable=battleID_label_text, height=4) - # self.label3.grid(row=3, column=0) - - battle_id = StringVar() - self.first_gamer_batt = Entry(self.frame, textvariable=battle_id) - self.first_gamer_batt.grid(row=4, column=1) - - # Submit Button - self.sub_btn = Button(self.frame, text='Submit', command=self.submit) - self.sub_btn.grid(row=5, column=3) - - self.frame.pack() - # If a game option is selected call the callbackf function - self.game_choices.bind("<>", self.callback) - - def callback(self, event_object): - self.game = event_object.widget.get() + def __init__(self): + tk.Tk.__init__(self) + self._frame = None + self.change_frame(PageOne) - def submit(self): - """ - Retrieve the values from each entry and check if they are valid. - """ - platform = self.first_gamer_plat.get() - region = self.first_gamer_reg.get() - battle_tag = self.first_gamer_batt.get() + def change_frame(self, change_frame): + new_frame = change_frame(self) + if self._frame is not None: + self._frame.destroy() + self._frame = new_frame + self._frame.pack() - try: - o = Overwatch(platform, region, battle_tag) - if o.result: - # Simple check to see if values are valid - print(o.test_get_player_info()) - else: - print("Invalid Profile") - except: - # Need to likely change this try/except. Debugging required - print("Invalid Profile") -app = Tk() -gui = FirstGUI(app) -app.title("Game App") -app.geometry('500x600') -app.mainloop() +if __name__ == "__main__": + app = FirstGUI() + app.mainloop() \ No newline at end of file diff --git a/Pages.py b/Pages.py new file mode 100644 index 0000000..c47e13b --- /dev/null +++ b/Pages.py @@ -0,0 +1,159 @@ +from tkinter import * +import tkinter as tk +from tkinter import ttk +from apicollect import Overwatch +""" +Sources: +https://www.youtube.com/watch?v=YTqDYmfccQU +https://www.delftstack.com/howto/python-tkinter/how-to-switch-frames-in-tkinter/ +https://www.youtube.com/watch?v=7JoMTQgdxg0 +""" + + + + + +class PageOne(tk.Frame): + def __init__(self, parent): + tk.Frame.__init__(self, parent) + + self.game = None + self.labelSelect = Label(self, text='Choose a game to find stats to compare between multiple players') + self.labelSelect.grid(row=0, column=1) + self.game_chosen = StringVar() + # Create a dropdown menu + self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) + # Default text shown + self.game_choices.set("Select a game") + # Possible games to choose from: Cold war and WoW are examples for now + self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] + self.game_choices.grid(row=1, column=1) + + """ + Idea: Maybe we can use validate commands for the entries + """ + + # Submit Button: we will need to change this for different games entered + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo)).grid(row=2, column=1) + # self.sub_btn.grid(row=5, column=3) + + self.pack() + # If a game option is selected call the callback function + self.game_choices.bind("<>", self.callback) + + + def callback(self, event_object): + self.game = event_object.widget.get() + +class PageTwo(tk.Frame): + """ + For Overwatch + """ + + def __init__(self, parent): + tk.Frame.__init__(self, parent) + tk.Label(self, text="Input the player").grid(row=1, column = 0, columnspan = 2) + self.num_players = 0 + # self.all_players = [] + + self.ow_tree = ttk.Treeview(self) + #Create the columns + self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") + self.ow_tree.column("#0", width=120, minwidth = 25) + self.ow_tree.column("Battle Tag", anchor=W, width=120) + self.ow_tree.column("Platform", anchor=CENTER, width=80) + self.ow_tree.column("Region", anchor = W, width = 60) + #Create the headings + self.ow_tree.heading("#0", text="Label", anchor=W) + self.ow_tree.heading("Battle Tag", text="Battle Tag", anchor=CENTER) + self.ow_tree.heading("Platform", text="Platform", anchor=W) + self.ow_tree.heading("Region", text="Region", anchor=CENTER) + + #Add Data + # ow_tree.insert('', index='end', iid=0, text="Player", values=("Yash", "pc", "us")) + + self.ow_tree.grid(row=0, column=0) + + + self.platform_chosen = StringVar() + self.region_chosen = StringVar() + self.battletag_chosen = StringVar() + + tk.Label(self, text="Player 1").grid(row=2, column=0, columnspan = 2) + + tk.Label(self, text="Platform:").grid(row=3, column=0, columnspan = 2) + # Create a dropdown menu + self.platform_choices = ttk.Combobox(self, state="readonly", textvariable=self.platform_chosen, width=30) + # Default text shown + self.platform_choices.set("Select a platform") + # Possible platforms to choose + self.platform_choices['values'] = ['pc', 'xbl', 'psn'] + self.platform_choices.grid(row=3, column=1) + + tk.Label(self, text="Region:").grid(row=4, column=0, columnspan = 2) + # Create a dropdown menu + self.region_choices = ttk.Combobox(self, state="readonly", textvariable=self.region_chosen, width=30) + # Default text shown + self.region_choices.set("Select a region") + # Possible regions to choose + self.region_choices['values'] = ['us', 'eu', 'kr', 'cn', 'global'] + self.region_choices.grid(row=4, column=1) + + tk.Label(self, text="Battle Tag:").grid(row=5, column=0, columnspan = 2) + + self.battle_id = StringVar() + self.gamer_tag = Entry(self, textvariable=self.battle_id) + self.gamer_tag.grid(row=5, column=1) + + + self.add_btn = Button(self, text='Add Player', command= self.add_player) + self.add_btn.grid(row=6, column=4) + self.add_btn = Button(self, text='Clear', command=self.clear) + self.add_btn.grid(row=7, column=4) + self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) + self.add_btn.grid(row=8, column=4) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=9, column=4) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=10, column=4) + + def add_player(self): + + try: + o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) + if o.result: + self.num_players += 1 + self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), + values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + + self.gamer_tag.delete(0, END) + self.platform_choices.set('Select a platform') + self.region_choices.set('Select a region') + else: + print("Invalid Profile") + + except: + print("Invalid Profile") + + + def clear(self): + for player in self.ow_tree.get_children(): + self.ow_tree.delete(player) + + def remove_players(self): + t = self.ow_tree.selection() + for player in t: + self.ow_tree.delete(player) + + +class PageThree(tk.Frame): + """ + The Third page + """ + + def __init__(self, parent): + tk.Frame.__init__(self, parent) + tk.Label(self, text="Input the player").grid(row=1, column=0, columnspan=2) + + + + + diff --git a/apicollect.py b/apicollect.py index 33049c5..c8f2f94 100644 --- a/apicollect.py +++ b/apicollect.py @@ -87,5 +87,4 @@ def compare_2players(self, player1, player2): ov = Overwatch('pc', 'us', 'cats-11481') ov.get_filers() -print("hey") -print("testing push") + From 42d256e56a368810815a660d27cec21d0775f83e Mon Sep 17 00:00:00 2001 From: Rieley Hega Date: Wed, 7 Apr 2021 23:40:20 -0400 Subject: [PATCH 05/21] New style for GUI with titled window. --- GUI.py | 1 + Pages.py | 42 +++++++++++++++----------- __pycache__/Pages.cpython-39.pyc | Bin 0 -> 4926 bytes __pycache__/apicollect.cpython-39.pyc | Bin 0 -> 2915 bytes 4 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 __pycache__/Pages.cpython-39.pyc create mode 100644 __pycache__/apicollect.cpython-39.pyc diff --git a/GUI.py b/GUI.py index 6596340..ed15081 100644 --- a/GUI.py +++ b/GUI.py @@ -11,6 +11,7 @@ class FirstGUI(tk.Tk): """ def __init__(self): tk.Tk.__init__(self) + self.title("Statistical Tracker for:") self._frame = None self.change_frame(PageOne) diff --git a/Pages.py b/Pages.py index c47e13b..93b64cb 100644 --- a/Pages.py +++ b/Pages.py @@ -1,5 +1,6 @@ from tkinter import * import tkinter as tk +from tkinter import messagebox from tkinter import ttk from apicollect import Overwatch """ @@ -52,8 +53,10 @@ class PageTwo(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) - tk.Label(self, text="Input the player").grid(row=1, column = 0, columnspan = 2) + parent.title('Statistical Tracker for: Overwatch') + tk.Label(self, text="Player information:").grid(row=0, column = 0, columnspan = 2) self.num_players = 0 + # self.all_players = [] self.ow_tree = ttk.Treeview(self) @@ -69,51 +72,54 @@ def __init__(self, parent): self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) + #Add Data # ow_tree.insert('', index='end', iid=0, text="Player", values=("Yash", "pc", "us")) - self.ow_tree.grid(row=0, column=0) + self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E+W+S+N) self.platform_chosen = StringVar() self.region_chosen = StringVar() self.battletag_chosen = StringVar() - tk.Label(self, text="Player 1").grid(row=2, column=0, columnspan = 2) + tk.Label(self, text="Player 1").grid(row=1, column=0, columnspan = 2) - tk.Label(self, text="Platform:").grid(row=3, column=0, columnspan = 2) + tk.Label(self, text="Platform:").grid(row=2, column=0, columnspan = 1) # Create a dropdown menu self.platform_choices = ttk.Combobox(self, state="readonly", textvariable=self.platform_chosen, width=30) # Default text shown self.platform_choices.set("Select a platform") # Possible platforms to choose self.platform_choices['values'] = ['pc', 'xbl', 'psn'] - self.platform_choices.grid(row=3, column=1) + self.platform_choices.grid(row=2, column=1) - tk.Label(self, text="Region:").grid(row=4, column=0, columnspan = 2) + tk.Label(self, text="Region:").grid(row=3, column=0, columnspan = 1) # Create a dropdown menu self.region_choices = ttk.Combobox(self, state="readonly", textvariable=self.region_chosen, width=30) # Default text shown self.region_choices.set("Select a region") # Possible regions to choose self.region_choices['values'] = ['us', 'eu', 'kr', 'cn', 'global'] - self.region_choices.grid(row=4, column=1) + self.region_choices.grid(row=3, column=1) - tk.Label(self, text="Battle Tag:").grid(row=5, column=0, columnspan = 2) + tk.Label(self, text="Battle Tag:").grid(row=4, column=0, columnspan = 1) self.battle_id = StringVar() self.gamer_tag = Entry(self, textvariable=self.battle_id) - self.gamer_tag.grid(row=5, column=1) + self.gamer_tag.grid(row=4, column=1) + window = tk.Tk() self.add_btn = Button(self, text='Add Player', command= self.add_player) - self.add_btn.grid(row=6, column=4) - self.add_btn = Button(self, text='Clear', command=self.clear) - self.add_btn.grid(row=7, column=4) + self.add_btn.grid(row=0, column=4) self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) - self.add_btn.grid(row=8, column=4) - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=9, column=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=10, column=4) + self.add_btn.grid(row=1, padx=5, column=4) + self.add_btn = Button(self, text='Clear', command=self.clear) + self.add_btn.grid(row=2, column=4) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) + def add_player(self): @@ -128,10 +134,10 @@ def add_player(self): self.platform_choices.set('Select a platform') self.region_choices.set('Select a region') else: - print("Invalid Profile") + messagebox.showinfo('Error!', 'You have entered an invalid profile!') except: - print("Invalid Profile") + messagebox.showinfo('Error!', 'You have entered an invalid profile!') def clear(self): @@ -151,7 +157,7 @@ class PageThree(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) - tk.Label(self, text="Input the player").grid(row=1, column=0, columnspan=2) + tk.Label(self, text="Input the player").grid(row=0, column=1, columnspan=2) diff --git a/__pycache__/Pages.cpython-39.pyc b/__pycache__/Pages.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecbfefcb95ebf5a2730e415decc36a34c47ed360 GIT binary patch literal 4926 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 NvN~kGxBm62`!8Q?1=aun literal 0 HcmV?d00001 From 18202b0d619c8115d44f775face2a7e89b1af140 Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Thu, 8 Apr 2021 01:40:26 -0400 Subject: [PATCH 06/21] Fixed submit button bug for pageOne --- Pages.py | 322 +++++++++++++++++++++++++++---------------------------- 1 file changed, 157 insertions(+), 165 deletions(-) diff --git a/Pages.py b/Pages.py index 93b64cb..2db740d 100644 --- a/Pages.py +++ b/Pages.py @@ -1,165 +1,157 @@ -from tkinter import * -import tkinter as tk -from tkinter import messagebox -from tkinter import ttk -from apicollect import Overwatch -""" -Sources: -https://www.youtube.com/watch?v=YTqDYmfccQU -https://www.delftstack.com/howto/python-tkinter/how-to-switch-frames-in-tkinter/ -https://www.youtube.com/watch?v=7JoMTQgdxg0 -""" - - - - - -class PageOne(tk.Frame): - def __init__(self, parent): - tk.Frame.__init__(self, parent) - - self.game = None - self.labelSelect = Label(self, text='Choose a game to find stats to compare between multiple players') - self.labelSelect.grid(row=0, column=1) - self.game_chosen = StringVar() - # Create a dropdown menu - self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) - # Default text shown - self.game_choices.set("Select a game") - # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] - self.game_choices.grid(row=1, column=1) - - """ - Idea: Maybe we can use validate commands for the entries - """ - - # Submit Button: we will need to change this for different games entered - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo)).grid(row=2, column=1) - # self.sub_btn.grid(row=5, column=3) - - self.pack() - # If a game option is selected call the callback function - self.game_choices.bind("<>", self.callback) - - - def callback(self, event_object): - self.game = event_object.widget.get() - -class PageTwo(tk.Frame): - """ - For Overwatch - """ - - def __init__(self, parent): - tk.Frame.__init__(self, parent) - parent.title('Statistical Tracker for: Overwatch') - tk.Label(self, text="Player information:").grid(row=0, column = 0, columnspan = 2) - self.num_players = 0 - - # self.all_players = [] - - self.ow_tree = ttk.Treeview(self) - #Create the columns - self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") - self.ow_tree.column("#0", width=120, minwidth = 25) - self.ow_tree.column("Battle Tag", anchor=W, width=120) - self.ow_tree.column("Platform", anchor=CENTER, width=80) - self.ow_tree.column("Region", anchor = W, width = 60) - #Create the headings - self.ow_tree.heading("#0", text="Label", anchor=W) - self.ow_tree.heading("Battle Tag", text="Battle Tag", anchor=CENTER) - self.ow_tree.heading("Platform", text="Platform", anchor=W) - self.ow_tree.heading("Region", text="Region", anchor=CENTER) - - - #Add Data - # ow_tree.insert('', index='end', iid=0, text="Player", values=("Yash", "pc", "us")) - - self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E+W+S+N) - - - self.platform_chosen = StringVar() - self.region_chosen = StringVar() - self.battletag_chosen = StringVar() - - tk.Label(self, text="Player 1").grid(row=1, column=0, columnspan = 2) - - tk.Label(self, text="Platform:").grid(row=2, column=0, columnspan = 1) - # Create a dropdown menu - self.platform_choices = ttk.Combobox(self, state="readonly", textvariable=self.platform_chosen, width=30) - # Default text shown - self.platform_choices.set("Select a platform") - # Possible platforms to choose - self.platform_choices['values'] = ['pc', 'xbl', 'psn'] - self.platform_choices.grid(row=2, column=1) - - tk.Label(self, text="Region:").grid(row=3, column=0, columnspan = 1) - # Create a dropdown menu - self.region_choices = ttk.Combobox(self, state="readonly", textvariable=self.region_chosen, width=30) - # Default text shown - self.region_choices.set("Select a region") - # Possible regions to choose - self.region_choices['values'] = ['us', 'eu', 'kr', 'cn', 'global'] - self.region_choices.grid(row=3, column=1) - - tk.Label(self, text="Battle Tag:").grid(row=4, column=0, columnspan = 1) - - self.battle_id = StringVar() - self.gamer_tag = Entry(self, textvariable=self.battle_id) - self.gamer_tag.grid(row=4, column=1) - window = tk.Tk() - - - self.add_btn = Button(self, text='Add Player', command= self.add_player) - self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) - self.add_btn.grid(row=1, padx=5, column=4) - self.add_btn = Button(self, text='Clear', command=self.clear) - self.add_btn.grid(row=2, column=4) - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) - - - def add_player(self): - - try: - o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) - if o.result: - self.num_players += 1 - self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), - values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) - - self.gamer_tag.delete(0, END) - self.platform_choices.set('Select a platform') - self.region_choices.set('Select a region') - else: - messagebox.showinfo('Error!', 'You have entered an invalid profile!') - - except: - messagebox.showinfo('Error!', 'You have entered an invalid profile!') - - - def clear(self): - for player in self.ow_tree.get_children(): - self.ow_tree.delete(player) - - def remove_players(self): - t = self.ow_tree.selection() - for player in t: - self.ow_tree.delete(player) - - -class PageThree(tk.Frame): - """ - The Third page - """ - - def __init__(self, parent): - tk.Frame.__init__(self, parent) - tk.Label(self, text="Input the player").grid(row=0, column=1, columnspan=2) - - - - - +from tkinter import * +import tkinter as tk +from tkinter import messagebox +from tkinter import ttk +from apicollect import Overwatch + +""" +Sources: +https://www.youtube.com/watch?v=YTqDYmfccQU +https://www.delftstack.com/howto/python-tkinter/how-to-switch-frames-in-tkinter/ +https://www.youtube.com/watch?v=7JoMTQgdxg0 +""" + + +class PageOne(tk.Frame): + def __init__(self, parent): + tk.Frame.__init__(self, parent) + + self.game = None + self.labelSelect = Label(self, text='Choose a game to find stats to compare between multiple players') + self.labelSelect.grid(row=0, column=1) + self.game_chosen = StringVar() + # Create a dropdown menu + self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) + # Default text shown + self.game_choices.set("Select a game") + # Possible games to choose from: Cold war and WoW are examples for now + self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] + self.game_choices.grid(row=1, column=1) + + """ + Idea: Maybe we can use validate commands for the entries + """ + + self.sub_btn = Button(self, text='Submit', command=lambda: self.testing(parent)).grid( + row=2, column=1) + # self.sub_btn.grid(row=5, column=3) + + self.pack() + # If a game option is selected call the callback function + self.game_choices.bind("<>", self.callback) + + def callback(self, event_object): + self.game = event_object.widget.get() + + def testing(self, parent): + if self.game_choices.get() != "Select a game": + parent.change_frame(PageTwo) + + +class PageTwo(tk.Frame): + """ + For Overwatch + """ + + def __init__(self, parent): + tk.Frame.__init__(self, parent) + parent.title('Statistical Tracker for: Overwatch') + tk.Label(self, text="Player information:").grid(row=0, column=0, columnspan=2) + self.num_players = 0 + + # self.all_players = [] + + self.ow_tree = ttk.Treeview(self) + # Create the columns + self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") + self.ow_tree.column("#0", width=120, minwidth=25) + self.ow_tree.column("Battle Tag", anchor=W, width=120) + self.ow_tree.column("Platform", anchor=CENTER, width=80) + self.ow_tree.column("Region", anchor=W, width=60) + # Create the headings + self.ow_tree.heading("#0", text="Label", anchor=W) + self.ow_tree.heading("Battle Tag", text="Battle Tag", anchor=CENTER) + self.ow_tree.heading("Platform", text="Platform", anchor=W) + self.ow_tree.heading("Region", text="Region", anchor=CENTER) + + # Add Data + # ow_tree.insert('', index='end', iid=0, text="Player", values=("Yash", "pc", "us")) + + self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E + W + S + N) + + self.platform_chosen = StringVar() + self.region_chosen = StringVar() + self.battletag_chosen = StringVar() + + tk.Label(self, text="Player 1").grid(row=1, column=0, columnspan=2) + + tk.Label(self, text="Platform:").grid(row=2, column=0, columnspan=1) + # Create a dropdown menu + self.platform_choices = ttk.Combobox(self, state="readonly", textvariable=self.platform_chosen, width=30) + # Default text shown + self.platform_choices.set("Select a platform") + # Possible platforms to choose + self.platform_choices['values'] = ['pc', 'xbl', 'psn'] + self.platform_choices.grid(row=2, column=1) + + tk.Label(self, text="Region:").grid(row=3, column=0, columnspan=1) + # Create a dropdown menu + self.region_choices = ttk.Combobox(self, state="readonly", textvariable=self.region_chosen, width=30) + # Default text shown + self.region_choices.set("Select a region") + # Possible regions to choose + self.region_choices['values'] = ['us', 'eu', 'kr', 'cn', 'global'] + self.region_choices.grid(row=3, column=1) + + tk.Label(self, text="Battle Tag:").grid(row=4, column=0, columnspan=1) + + self.battle_id = StringVar() + self.gamer_tag = Entry(self, textvariable=self.battle_id) + self.gamer_tag.grid(row=4, column=1) + window = tk.Tk() + + self.add_btn = Button(self, text='Add Player', command=self.add_player) + self.add_btn.grid(row=0, column=4) + self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) + self.add_btn.grid(row=1, padx=5, column=4) + self.add_btn = Button(self, text='Clear', command=self.clear) + self.add_btn.grid(row=2, column=4) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) + + def add_player(self): + + try: + o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) + if o.result: + self.num_players += 1 + self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), + values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + + self.gamer_tag.delete(0, END) + self.platform_choices.set('Select a platform') + self.region_choices.set('Select a region') + else: + messagebox.showinfo('Error!', 'You have entered an invalid profile!') + + except: + messagebox.showinfo('Error!', 'You have entered an invalid profile!') + + def clear(self): + for player in self.ow_tree.get_children(): + self.ow_tree.delete(player) + + def remove_players(self): + t = self.ow_tree.selection() + for player in t: + self.ow_tree.delete(player) + + +class PageThree(tk.Frame): + """ + The Third page + """ + + def __init__(self, parent): + tk.Frame.__init__(self, parent) + tk.Label(self, text="Input the player").grid(row=0, column=1, columnspan=2) From 2b25d2ab419749f367d8db44cef6aabd8abac1a5 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 8 Apr 2021 10:19:34 -0400 Subject: [PATCH 07/21] Fixing up some changes for submitting --- Pages.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Pages.py b/Pages.py index 2db740d..6f58120 100644 --- a/Pages.py +++ b/Pages.py @@ -28,13 +28,14 @@ def __init__(self, parent): self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] self.game_choices.grid(row=1, column=1) + """ Idea: Maybe we can use validate commands for the entries """ - self.sub_btn = Button(self, text='Submit', command=lambda: self.testing(parent)).grid( - row=2, column=1) - # self.sub_btn.grid(row=5, column=3) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo)) + self.sub_btn.grid(row=2, column=1) + self.sub_btn["state"] = DISABLED self.pack() # If a game option is selected call the callback function @@ -42,10 +43,10 @@ def __init__(self, parent): def callback(self, event_object): self.game = event_object.widget.get() + if self.game != "Select a game": + self.sub_btn["state"] = NORMAL + - def testing(self, parent): - if self.game_choices.get() != "Select a game": - parent.change_frame(PageTwo) class PageTwo(tk.Frame): @@ -74,8 +75,6 @@ def __init__(self, parent): self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) - # Add Data - # ow_tree.insert('', index='end', iid=0, text="Player", values=("Yash", "pc", "us")) self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E + W + S + N) @@ -108,7 +107,6 @@ def __init__(self, parent): self.battle_id = StringVar() self.gamer_tag = Entry(self, textvariable=self.battle_id) self.gamer_tag.grid(row=4, column=1) - window = tk.Tk() self.add_btn = Button(self, text='Add Player', command=self.add_player) self.add_btn.grid(row=0, column=4) From d2044e1f495d3178a72dceb4b306746eef818aa2 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 8 Apr 2021 10:23:10 -0400 Subject: [PATCH 08/21] Fixing up some changes for the treeview --- Pages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pages.py b/Pages.py index 6f58120..00077cf 100644 --- a/Pages.py +++ b/Pages.py @@ -70,7 +70,7 @@ def __init__(self, parent): self.ow_tree.column("Platform", anchor=CENTER, width=80) self.ow_tree.column("Region", anchor=W, width=60) # Create the headings - self.ow_tree.heading("#0", text="Label", anchor=W) + self.ow_tree.heading("#0", text="Player #", anchor=W) self.ow_tree.heading("Battle Tag", text="Battle Tag", anchor=CENTER) self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) From 27aaf25a8f6a155ca76dc3d17f4759642a6c7d66 Mon Sep 17 00:00:00 2001 From: Yash Date: Thu, 8 Apr 2021 13:02:55 -0400 Subject: [PATCH 09/21] Validating the entry --- Pages.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Pages.py b/Pages.py index 00077cf..861ad29 100644 --- a/Pages.py +++ b/Pages.py @@ -75,12 +75,11 @@ def __init__(self, parent): self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) - self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E + W + S + N) self.platform_chosen = StringVar() self.region_chosen = StringVar() - self.battletag_chosen = StringVar() + self.battle_id = StringVar() tk.Label(self, text="Player 1").grid(row=1, column=0, columnspan=2) @@ -104,19 +103,26 @@ def __init__(self, parent): tk.Label(self, text="Battle Tag:").grid(row=4, column=0, columnspan=1) - self.battle_id = StringVar() + self.battle_id.trace("w", lambda name, index, mode, new_id=self.battle_id: self.validate_tag(new_id)) self.gamer_tag = Entry(self, textvariable=self.battle_id) + self.gamer_tag.grid(row=4, column=1) self.add_btn = Button(self, text='Add Player', command=self.add_player) self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) + self.add_btn = Button(self, text='Remove Player(s)', command=self.validate_tag) self.add_btn.grid(row=1, padx=5, column=4) self.add_btn = Button(self, text='Clear', command=self.clear) self.add_btn.grid(row=2, column=4) self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) + + + def validate_tag(self, id): + if "#" in id.get(): + self.battle_id.set(self.battle_id.get().replace("#", "-")) + def add_player(self): try: From c8bb57173b2d6214236676ea00986f7084b76e8d Mon Sep 17 00:00:00 2001 From: Yash Date: Sat, 10 Apr 2021 23:40:03 -0400 Subject: [PATCH 10/21] Finished Overwatch --- GUI.py | 7 +- Pages.py | 204 +++++++++++++++++++++++++++++++++++++++++++++++++- apicollect.py | 150 ++++++++++++++++++++++--------------- 3 files changed, 296 insertions(+), 65 deletions(-) diff --git a/GUI.py b/GUI.py index ed15081..111d7cb 100644 --- a/GUI.py +++ b/GUI.py @@ -14,8 +14,13 @@ def __init__(self): self.title("Statistical Tracker for:") self._frame = None self.change_frame(PageOne) + self.all_players = [] + self.game_filters = {} + self.displayed_stats = [] + self.compared_stats = [] + self.game_mode = None - def change_frame(self, change_frame): + def change_frame(self, change_frame, *player_info): new_frame = change_frame(self) if self._frame is not None: self._frame.destroy() diff --git a/Pages.py b/Pages.py index 861ad29..a0e04a8 100644 --- a/Pages.py +++ b/Pages.py @@ -9,9 +9,14 @@ https://www.youtube.com/watch?v=YTqDYmfccQU https://www.delftstack.com/howto/python-tkinter/how-to-switch-frames-in-tkinter/ https://www.youtube.com/watch?v=7JoMTQgdxg0 +https://stackoverflow.com/questions/13828531/problems-in-python-getting-multiple-selections-from-tkinter-listbox """ + + + + class PageOne(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) @@ -33,7 +38,7 @@ def __init__(self, parent): Idea: Maybe we can use validate commands for the entries """ - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo)) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) self.sub_btn.grid(row=2, column=1) self.sub_btn["state"] = DISABLED @@ -60,7 +65,8 @@ def __init__(self, parent): tk.Label(self, text="Player information:").grid(row=0, column=0, columnspan=2) self.num_players = 0 - # self.all_players = [] + self.parent = parent + self.ow_tree = ttk.Treeview(self) # Create the columns @@ -118,7 +124,6 @@ def __init__(self, parent): self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) - def validate_tag(self, id): if "#" in id.get(): self.battle_id.set(self.battle_id.get().replace("#", "-")) @@ -127,14 +132,26 @@ def add_player(self): try: o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) + if o.result: + if not self.parent.game_filters: + self.parent.game_filters = o.get_filters() + self.parent.displayed_stats = o.displayed_filters + + self.num_players += 1 + self.parent.all_players.extend([o]) + self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) self.gamer_tag.delete(0, END) self.platform_choices.set('Select a platform') self.region_choices.set('Select a region') + + + + else: messagebox.showinfo('Error!', 'You have entered an invalid profile!') @@ -158,4 +175,183 @@ class PageThree(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) - tk.Label(self, text="Input the player").grid(row=0, column=1, columnspan=2) + self.parent = parent + + self.Label_Stats = Label(self, text='Choose at least two stats to compare') + self.Label_Stats.grid(row=0, column=1, columnspan = 2) + + self.gameplay = StringVar() + self.qp_btn = Radiobutton(self, text ="Quick Play", variable = self.gameplay, value = "quickPlayStats", command = lambda: self.gameplay_chosen(), tristatevalue=0) + self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", command=lambda: self.gameplay_chosen(), tristatevalue=0) + + + + self.qp_btn.grid(row = 1, column = 1) + self.cp_btn.grid(row = 1, column = 2) + + self.scrollbar = Scrollbar(self, orient = VERTICAL) + self.scrollbar.grid(row=2, column=2, sticky=tk.N + tk.S) + self.filter_list = self.parent.displayed_stats + + + + self.filter_lb = Listbox(self, selectmode = MULTIPLE, width = 50, yscrollcommand=self.scrollbar.set) + for filter in self.filter_list[1:]: + self.filter_lb.insert(END, filter) + self.filter_lb.grid(row = 2, column = 1, sticky=tk.N + tk.S + tk.E + tk.W) + self.filter_lb["state"] = DISABLED + self.filter_lb.bind("<>", self.selected_stats) + self.scrollbar['command'] = self.filter_lb.yview + + self.sbt_stats = Button(self, text='Submit', command=lambda: parent.change_frame(PageFour)) + self.sbt_stats.grid(row=3, column=1) + self.sbt_stats["state"] = DISABLED + + def selected_stats(self, lb): + selected_stats = lb.widget.curselection() + self.parent.compared_stats = ["Name"] + if (selected_stats != ()): + for stat in selected_stats: + + if self.filter_list[int(stat)+1] not in self.parent.compared_stats: + self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) + if len(self.parent.compared_stats) >= 2: + self.sbt_stats["state"] = NORMAL + else: + self.sbt_stats["state"] = DISABLED + + + + def gameplay_chosen(self): + self.filter_lb["state"] = NORMAL + self.parent.game_mode = self.gameplay.get() + + + +class PageFour(tk.Frame): + """ + The Fourth page + """ + + def __init__(self, parent): + tk.Frame.__init__(self, parent) + self.parent = parent + self.compared_players = self.parent.all_players + self.compared_stats = self.parent.compared_stats + self.Label_table = Label(self, text='Table') + self.Label_table.grid(row=0, column=1, columnspan=2) + self.tree_stats = {} + + self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', 'Silver Medals': 'medalsSilver', + 'Gold Medals': 'medalsGold'} + self.sub_game_results = {'Games Won':'gamesWon', 'gamesLost':'gamesLost', 'gamesPlayed':'gamesPlayed'} + self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths', + 'eliminations': 'eliminations','soloKills': 'soloKills','objectiveKills': 'objectiveKills'} + self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', 'barrierDamageDoneMostInGame':'barrierDamageDoneMostInGame', 'eliminationsMostInGame':'eliminationsMostInGame', + 'healingDoneMostInGame':'healingDoneMostInGame', 'killsStreakBest':'killsStreakBest', 'multikillsBest':'multikillsBest'} + self.in_game_index = 0 + self.best_in_game_index = 0 + self.game_outcome_index = 0 + self.awards_index = 0 + + + + + + + + for stat in self.parent.compared_stats: + self.tree_stats[stat] = [] + self.get_player_info(stat) + + self.ow_stat_tree = ttk.Treeview(self) + # Create the columns + self.ow_stat_tree['columns'] = self.tree_stats['Name'] + + + self.ow_stat_tree.column("#0", width=120, minwidth=25) + # + for x, stat in enumerate(self.tree_stats['Name']): + + self.ow_stat_tree.column(x, anchor=CENTER, width=100) + + # Create the headings + self.ow_stat_tree.heading("#0", text="Player #", anchor=W) + for x, stat in enumerate(self.tree_stats['Name']): + self.ow_stat_tree.heading(x, text="Player {}".format(x+1), anchor=CENTER) + self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, sticky=E + W + S + N) + + + + for x, stat in enumerate(self.tree_stats): + """ + Create this in the parent class as attribute + """ + if stat == 'In-Game Stats': + self.in_game_index = x + self.ow_stat_tree.insert('', index='end', iid=x, text=stat) + elif stat == 'Best In-Game Stats': + self.best_in_game_index = x + self.ow_stat_tree.insert('', index='end', iid=x, text=stat) + elif stat == 'Game Outcomes': + self.game_outcome_index = x + self.ow_stat_tree.insert('', index='end', iid=x, text=stat) + elif stat == 'Awards': + self.awards_index = x + self.ow_stat_tree.insert('', index='end', iid=x, text=stat) + elif stat in self.sub_awards: + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.move(str(x), str(self.awards_index), str(self.awards_index)) + elif stat in self.best_game_results: + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.move(str(x), str(self.best_in_game_index), str(self.best_in_game_index)) + elif stat in self.in_game_stats: + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.move(str(x), str(self.in_game_index), str(self.in_game_index)) + elif stat in self.sub_game_results: + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.move(str(x), str(self.game_outcome_index), str(self.game_outcome_index)) + else: + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + + # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', + # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + # self.api_filters.extend( + # ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', + # 'Game Outcomes', 'Awards']) + def get_player_info(self, stat): + + for player in self.compared_players: + if stat == 'Awards': + sub_awards = self.sub_awards + for sub_stat in sub_awards: + if sub_stat not in self.tree_stats: + self.tree_stats[sub_stat] = [] + self.tree_stats[sub_stat].append(player.get_stat(sub_awards[sub_stat], self.parent.game_mode)) + elif stat == 'Game Outcomes': + sub_game_results = self.sub_game_results + for sub_stat in sub_game_results: + if sub_stat not in self.tree_stats: + self.tree_stats[sub_stat] = [] + self.tree_stats[sub_stat].append(player.get_stat(sub_game_results[sub_stat], self.parent.game_mode)) + elif stat == 'In-Game Stats': + in_game_stats = self.in_game_stats + for sub_stat in in_game_stats: + if sub_stat not in self.tree_stats: + self.tree_stats[sub_stat] = [] + self.tree_stats[sub_stat].append(player.get_stat(in_game_stats[sub_stat], self.parent.game_mode)) + elif stat == 'Best In-Game Stats': + best_game_results = self.best_game_results + for sub_stat in best_game_results: + if sub_stat not in self.tree_stats: + self.tree_stats[sub_stat] = [] + self.tree_stats[sub_stat].append(player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) + else: + self.tree_stats[stat].append(player.get_stat(stat, self.parent.game_mode)) + + + + + + + diff --git a/apicollect.py b/apicollect.py index c8f2f94..3a64e07 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,6 +1,6 @@ import requests # API address we can fill the parameters: platform, region and battle tag of a player to get their profile -url = 'https://ow-api.com/v1/stats/{}/{}/{}/profile' +url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete' class Overwatch: @@ -10,9 +10,12 @@ def __init__(self, platform, region, battle_tag): # Convert to JSON (basically dictionary formatted info) self.result_json = self.result.json() # List of all filters for player to select - self.filters = [] + self.displayed_filters = [] + self.api_filters = [] + self.sub_stats = [] - def get_filers(self): + + def get_filters(self): """ Get the main filters(stats) available for a user to select to compare with another player. We don't really care about icon, level icon, etc. for this since they aren't stats used for comparision. @@ -21,70 +24,97 @@ def get_filers(self): """ # The primary filters - self.filters.extend(['name', 'level', 'prestige', 'rating', 'gamesWon']) + self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + self.api_filters.extend(['name', 'level', 'prestige', 'rating','Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards']) - # - for match_filter in ['quickPlayStats', 'competitiveStats']: - qp_game_filters = [] - qp_award_filters = [] - qp_total_filters = [] - for qp_filter in self.result_json[match_filter]: - if qp_filter == 'games': - for game_filter in self.result_json[match_filter]['games']: - qp_game_filters.extend(([game_filter])) - qp_total_filters.extend([qp_filter, qp_game_filters]) - elif qp_filter == 'awards': - - for award_filter in self.result_json[match_filter]['awards']: - qp_award_filters.extend(([award_filter])) - - qp_total_filters.extend([qp_filter, qp_award_filters]) - self.filters.extend([[match_filter, qp_total_filters]]) - return self.filters - - def test_get_player_info(self): - """ - This is just a simple example of how to make API requests for demonstration purposes. - :return: - """ - if self.result: - name = self.result_json['name'] - games_won = self.result_json['gamesWon'] - level = self.result_json['level'] - rating = self.result_json['rating'] - return [name, games_won, level, rating] - return None - - def analyze_stats(self, player): - """ - analyze the stats of a player and return an integer value representing its final - score after evaluation + filter_dict = {} - :param player: Battle Tag of player - :return: evaluation score - """ - if player == self.test_get_player_info()[0]: - player_stats = self.test_get_player_info() - return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations - return "Invalid player" - def compare_2players(self, player1, player2): - """ - compares stats of 2 players, and returns the winning player + for x, stat in enumerate(self.displayed_filters): + filter_dict[stat] = self.api_filters[x] - :param player1: Battle Tag of player1 - :param player2: Battle Tag of player 2 - :return: player with higher stats, else return a message saying players are equal - """ - if self.analyze_stats(player1) > self.analyze_stats(player2): - return player1 - elif self.analyze_stats(player1) < self.analyze_stats(player2): - return player2 - return "Players are equal in comparison" + # + # for match_filter in ['quickPlayStats', 'competitiveStats']: + # qp_game_filters = [] + # qp_award_filters = [] + # qp_total_filters = [] + # for qp_filter in self.result_json[match_filter]: + # if qp_filter == 'games': + # for game_filter in self.result_json[match_filter]['games']: + # qp_game_filters.extend(([game_filter])) + # qp_total_filters.extend([qp_filter, qp_game_filters]) + # elif qp_filter == 'awards': + # + # for award_filter in self.result_json[match_filter]['awards']: + # qp_award_filters.extend(([award_filter])) + # + # qp_total_filters.extend([qp_filter, qp_award_filters]) + # self.filters.extend([[match_filter, qp_total_filters]]) + return filter_dict + + # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', + # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + # self.api_filters.extend( + # ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', + # 'Game Outcomes', 'Awards']) + + def get_stat(self, stat, game_mode): + + if stat == 'Name': + return self.result_json['name'] + elif stat == 'Level': + return self.result_json['level'] + elif stat == 'Endorsement Level': + return self.result_json['endorsement'] + elif stat == 'Rating': + return self.result_json['rating'] + elif stat == 'Prestige': + return self.result_json['prestige'] + elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver','medalsGold']: + return self.result_json[game_mode]['awards'][stat] + elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: + return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] + elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: + return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] + elif stat in ['barrierDamageDone', 'damageDone', 'deaths','eliminations','soloKills','objectiveKills']: + return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] + else: + return self.result_json[stat] + + + + + + # def analyze_stats(self, player): + # """ + # analyze the stats of a player and return an integer value representing its final + # score after evaluation + # + # :param player: Battle Tag of player + # :return: evaluation score + # """ + # if player == self.test_get_player_info()[0]: + # player_stats = self.test_get_player_info() + # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations + # return "Invalid player" + + # def compare_2players(self, player1, player2): + # """ + # compares stats of 2 players, and returns the winning player + # + # :param player1: Battle Tag of player1 + # :param player2: Battle Tag of player 2 + # :return: player with higher stats, else return a message saying players are equal + # """ + # if self.analyze_stats(player1) > self.analyze_stats(player2): + # return player1 + # elif self.analyze_stats(player1) < self.analyze_stats(player2): + # return player2 + # return "Players are equal in comparison" # Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch ov = Overwatch('pc', 'us', 'cats-11481') -ov.get_filers() + From d2b1e307cc0103ae735a17a91705e709942d764f Mon Sep 17 00:00:00 2001 From: AnasKhan0607 <76663779+AnasKhan0607@users.noreply.github.com> Date: Sun, 11 Apr 2021 03:49:56 -0400 Subject: [PATCH 11/21] added some back buttons, fixed adding players so same player cant be added twice, tried to add image wont load for some reason, couldnt figure out bug for when 2 players are added but last 4 stats wont show. couldnt figure out bug for when you press back after adding players and then submit again it still has the previous players. --- Pages.py | 26 ++++++++++++++++---------- apicollect.py | 31 ------------------------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/Pages.py b/Pages.py index a0e04a8..0198e63 100644 --- a/Pages.py +++ b/Pages.py @@ -3,6 +3,8 @@ from tkinter import messagebox from tkinter import ttk from apicollect import Overwatch +from PIL import ImageTk, Image +import os """ Sources: @@ -23,23 +25,26 @@ def __init__(self, parent): self.game = None self.labelSelect = Label(self, text='Choose a game to find stats to compare between multiple players') - self.labelSelect.grid(row=0, column=1) + self.labelSelect.grid(row=1, column=1) self.game_chosen = StringVar() # Create a dropdown menu self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) # Default text shown self.game_choices.set("Select a game") # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] - self.game_choices.grid(row=1, column=1) + self.game_choices['values'] = ['Overwatch'] + self.game_choices.grid(row=2, column=1) """ Idea: Maybe we can use validate commands for the entries """ + img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) + self.panel = Label(self, image = img) + self.panel.grid(row=0, column=1, columnspan= 4) self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) - self.sub_btn.grid(row=2, column=1) + self.sub_btn.grid(row=3, column=1) self.sub_btn["state"] = DISABLED self.pack() @@ -64,6 +69,7 @@ def __init__(self, parent): parent.title('Statistical Tracker for: Overwatch') tk.Label(self, text="Player information:").grid(row=0, column=0, columnspan=2) self.num_players = 0 + self.players = [] self.parent = parent @@ -133,12 +139,12 @@ def add_player(self): try: o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) - if o.result: + if o.result and self.battle_id.get() not in self.players: if not self.parent.game_filters: self.parent.game_filters = o.get_filters() self.parent.displayed_stats = o.displayed_filters - + self.players.append(self.battle_id.get()) self.num_players += 1 self.parent.all_players.extend([o]) @@ -149,9 +155,6 @@ def add_player(self): self.platform_choices.set('Select a platform') self.region_choices.set('Select a region') - - - else: messagebox.showinfo('Error!', 'You have entered an invalid profile!') @@ -178,7 +181,7 @@ def __init__(self, parent): self.parent = parent self.Label_Stats = Label(self, text='Choose at least two stats to compare') - self.Label_Stats.grid(row=0, column=1, columnspan = 2) + self.Label_Stats.grid(row=0, column=1, columnspan=2) self.gameplay = StringVar() self.qp_btn = Radiobutton(self, text ="Quick Play", variable = self.gameplay, value = "quickPlayStats", command = lambda: self.gameplay_chosen(), tristatevalue=0) @@ -204,7 +207,9 @@ def __init__(self, parent): self.scrollbar['command'] = self.filter_lb.yview self.sbt_stats = Button(self, text='Submit', command=lambda: parent.change_frame(PageFour)) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageTwo)) self.sbt_stats.grid(row=3, column=1) + self.back_btn.grid(row=3, column=2) self.sbt_stats["state"] = DISABLED def selected_stats(self, lb): @@ -253,6 +258,7 @@ def __init__(self, parent): self.best_in_game_index = 0 self.game_outcome_index = 0 self.awards_index = 0 + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageThree)).grid(row=3, column=2) diff --git a/apicollect.py b/apicollect.py index 3a64e07..4760146 100644 --- a/apicollect.py +++ b/apicollect.py @@ -84,37 +84,6 @@ def get_stat(self, stat, game_mode): - - # def analyze_stats(self, player): - # """ - # analyze the stats of a player and return an integer value representing its final - # score after evaluation - # - # :param player: Battle Tag of player - # :return: evaluation score - # """ - # if player == self.test_get_player_info()[0]: - # player_stats = self.test_get_player_info() - # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations - # return "Invalid player" - - # def compare_2players(self, player1, player2): - # """ - # compares stats of 2 players, and returns the winning player - # - # :param player1: Battle Tag of player1 - # :param player2: Battle Tag of player 2 - # :return: player with higher stats, else return a message saying players are equal - # """ - # if self.analyze_stats(player1) > self.analyze_stats(player2): - # return player1 - # elif self.analyze_stats(player1) < self.analyze_stats(player2): - # return player2 - # return "Players are equal in comparison" - -# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch - - ov = Overwatch('pc', 'us', 'cats-11481') From 9e5da93edf02698e191358895f72fcc3a0652773 Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sun, 11 Apr 2021 14:08:49 -0400 Subject: [PATCH 12/21] Submit button only works when atleast 2 players --- Pages.py | 121 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/Pages.py b/Pages.py index 0198e63..9ca7655 100644 --- a/Pages.py +++ b/Pages.py @@ -4,6 +4,7 @@ from tkinter import ttk from apicollect import Overwatch from PIL import ImageTk, Image +import glob import os """ @@ -15,12 +16,9 @@ """ - - - - class PageOne(tk.Frame): def __init__(self, parent): + global img tk.Frame.__init__(self, parent) self.game = None @@ -35,14 +33,18 @@ def __init__(self, parent): self.game_choices['values'] = ['Overwatch'] self.game_choices.grid(row=2, column=1) - """ Idea: Maybe we can use validate commands for the entries """ + for filename in glob.glob('yourpath/logo.png'): + img = ImageTk.PhotoImage(Image.open(filename).resize((475, 221))) + self.panel = Label(self, image=img) + self.panel.grid(row=0, column=1, columnspan=4) - img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) - self.panel = Label(self, image = img) - self.panel.grid(row=0, column=1, columnspan= 4) + # img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) + + # self.panel = Label(self, image=img) + # self.panel.grid(row=0, column=1, columnspan=4) self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) self.sub_btn.grid(row=3, column=1) self.sub_btn["state"] = DISABLED @@ -57,8 +59,6 @@ def callback(self, event_object): self.sub_btn["state"] = NORMAL - - class PageTwo(tk.Frame): """ For Overwatch @@ -73,7 +73,6 @@ def __init__(self, parent): self.parent = parent - self.ow_tree = ttk.Treeview(self) # Create the columns self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") @@ -122,13 +121,14 @@ def __init__(self, parent): self.add_btn = Button(self, text='Add Player', command=self.add_player) self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.validate_tag) + self.add_btn = Button(self, text='Remove Player(s)', command=self.validate_tag(self.battle_id)) self.add_btn.grid(row=1, padx=5, column=4) self.add_btn = Button(self, text='Clear', command=self.clear) self.add_btn.grid(row=2, column=4) self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)).grid(row=4, column=4) - + self.sub_btn2 = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)) + self.sub_btn2.grid(row=4, column=4) + self.sub_btn2["state"] = DISABLED def validate_tag(self, id): if "#" in id.get(): @@ -160,15 +160,26 @@ def add_player(self): except: messagebox.showinfo('Error!', 'You have entered an invalid profile!') + self.callback() def clear(self): for player in self.ow_tree.get_children(): self.ow_tree.delete(player) + self.num_players = 0 + self.callback() def remove_players(self): t = self.ow_tree.selection() for player in t: self.ow_tree.delete(player) + self.num_players -= 1 + self.callback() + + def callback(self): + if self.num_players >= 2: + self.sub_btn2["state"] = NORMAL + else: + self.sub_btn2["state"] = DISABLED class PageThree(tk.Frame): @@ -184,24 +195,22 @@ def __init__(self, parent): self.Label_Stats.grid(row=0, column=1, columnspan=2) self.gameplay = StringVar() - self.qp_btn = Radiobutton(self, text ="Quick Play", variable = self.gameplay, value = "quickPlayStats", command = lambda: self.gameplay_chosen(), tristatevalue=0) - self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", command=lambda: self.gameplay_chosen(), tristatevalue=0) - - + self.qp_btn = Radiobutton(self, text="Quick Play", variable=self.gameplay, value="quickPlayStats", + command=lambda: self.gameplay_chosen(), tristatevalue=0) + self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", + command=lambda: self.gameplay_chosen(), tristatevalue=0) - self.qp_btn.grid(row = 1, column = 1) - self.cp_btn.grid(row = 1, column = 2) + self.qp_btn.grid(row=1, column=1) + self.cp_btn.grid(row=1, column=2) - self.scrollbar = Scrollbar(self, orient = VERTICAL) + self.scrollbar = Scrollbar(self, orient=VERTICAL) self.scrollbar.grid(row=2, column=2, sticky=tk.N + tk.S) self.filter_list = self.parent.displayed_stats - - - self.filter_lb = Listbox(self, selectmode = MULTIPLE, width = 50, yscrollcommand=self.scrollbar.set) + self.filter_lb = Listbox(self, selectmode=MULTIPLE, width=50, yscrollcommand=self.scrollbar.set) for filter in self.filter_list[1:]: self.filter_lb.insert(END, filter) - self.filter_lb.grid(row = 2, column = 1, sticky=tk.N + tk.S + tk.E + tk.W) + self.filter_lb.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W) self.filter_lb["state"] = DISABLED self.filter_lb.bind("<>", self.selected_stats) self.scrollbar['command'] = self.filter_lb.yview @@ -215,24 +224,21 @@ def __init__(self, parent): def selected_stats(self, lb): selected_stats = lb.widget.curselection() self.parent.compared_stats = ["Name"] - if (selected_stats != ()): + if selected_stats != (): for stat in selected_stats: - if self.filter_list[int(stat)+1] not in self.parent.compared_stats: + if self.filter_list[int(stat) + 1] not in self.parent.compared_stats: self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) if len(self.parent.compared_stats) >= 2: self.sbt_stats["state"] = NORMAL else: self.sbt_stats["state"] = DISABLED - - def gameplay_chosen(self): self.filter_lb["state"] = NORMAL self.parent.game_mode = self.gameplay.get() - class PageFour(tk.Frame): """ The Fourth page @@ -247,24 +253,24 @@ def __init__(self, parent): self.Label_table.grid(row=0, column=1, columnspan=2) self.tree_stats = {} - self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', 'Silver Medals': 'medalsSilver', - 'Gold Medals': 'medalsGold'} - self.sub_game_results = {'Games Won':'gamesWon', 'gamesLost':'gamesLost', 'gamesPlayed':'gamesPlayed'} + self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', + 'Silver Medals': 'medalsSilver', + 'Gold Medals': 'medalsGold'} + self.sub_game_results = {'Games Won': 'gamesWon', 'gamesLost': 'gamesLost', 'gamesPlayed': 'gamesPlayed'} self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths', - 'eliminations': 'eliminations','soloKills': 'soloKills','objectiveKills': 'objectiveKills'} - self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', 'barrierDamageDoneMostInGame':'barrierDamageDoneMostInGame', 'eliminationsMostInGame':'eliminationsMostInGame', - 'healingDoneMostInGame':'healingDoneMostInGame', 'killsStreakBest':'killsStreakBest', 'multikillsBest':'multikillsBest'} + 'eliminations': 'eliminations', 'soloKills': 'soloKills', + 'objectiveKills': 'objectiveKills'} + self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', + 'barrierDamageDoneMostInGame': 'barrierDamageDoneMostInGame', + 'eliminationsMostInGame': 'eliminationsMostInGame', + 'healingDoneMostInGame': 'healingDoneMostInGame', + 'killsStreakBest': 'killsStreakBest', 'multikillsBest': 'multikillsBest'} self.in_game_index = 0 self.best_in_game_index = 0 self.game_outcome_index = 0 self.awards_index = 0 - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageThree)).grid(row=3, column=2) - - - - - - + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageThree)).grid(row=3, + column=2) for stat in self.parent.compared_stats: self.tree_stats[stat] = [] @@ -274,20 +280,17 @@ def __init__(self, parent): # Create the columns self.ow_stat_tree['columns'] = self.tree_stats['Name'] - self.ow_stat_tree.column("#0", width=120, minwidth=25) # for x, stat in enumerate(self.tree_stats['Name']): - self.ow_stat_tree.column(x, anchor=CENTER, width=100) # Create the headings self.ow_stat_tree.heading("#0", text="Player #", anchor=W) for x, stat in enumerate(self.tree_stats['Name']): - self.ow_stat_tree.heading(x, text="Player {}".format(x+1), anchor=CENTER) - self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, sticky=E + W + S + N) - - + self.ow_stat_tree.heading(x, text="Player {}".format(x + 1), anchor=CENTER) + self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, + sticky=E + W + S + N) for x, stat in enumerate(self.tree_stats): """ @@ -306,19 +309,19 @@ def __init__(self, parent): self.awards_index = x self.ow_stat_tree.insert('', index='end', iid=x, text=stat) elif stat in self.sub_awards: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.awards_index), str(self.awards_index)) elif stat in self.best_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.best_in_game_index), str(self.best_in_game_index)) elif stat in self.in_game_stats: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.in_game_index), str(self.in_game_index)) elif stat in self.sub_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.game_outcome_index), str(self.game_outcome_index)) else: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] @@ -351,13 +354,7 @@ def get_player_info(self, stat): for sub_stat in best_game_results: if sub_stat not in self.tree_stats: self.tree_stats[sub_stat] = [] - self.tree_stats[sub_stat].append(player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) + self.tree_stats[sub_stat].append( + player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) else: self.tree_stats[stat].append(player.get_stat(stat, self.parent.game_mode)) - - - - - - - From 6c8c37d5d72019622d6b9a6216f98b2fdec1baae Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sun, 11 Apr 2021 14:09:35 -0400 Subject: [PATCH 13/21] fixed some styling and convention in the code --- GUI.py | 4 ++-- apicollect.py | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/GUI.py b/GUI.py index 111d7cb..a62ee38 100644 --- a/GUI.py +++ b/GUI.py @@ -4,6 +4,7 @@ from Pages import PageOne from apicollect import Overwatch + class FirstGUI(tk.Tk): """ This is pertaining to Overwatch only, Remember that in the apicollect.py file, @@ -28,7 +29,6 @@ def change_frame(self, change_frame, *player_info): self._frame.pack() - if __name__ == "__main__": app = FirstGUI() - app.mainloop() \ No newline at end of file + app.mainloop() diff --git a/apicollect.py b/apicollect.py index 4760146..83cc78e 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,4 +1,5 @@ import requests + # API address we can fill the parameters: platform, region and battle tag of a player to get their profile url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete' @@ -14,7 +15,6 @@ def __init__(self, platform, region, battle_tag): self.api_filters = [] self.sub_stats = [] - def get_filters(self): """ Get the main filters(stats) available for a user to select to compare with another player. @@ -24,12 +24,14 @@ def get_filters(self): """ # The primary filters - self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards'] - self.api_filters.extend(['name', 'level', 'prestige', 'rating','Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards']) + self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', + 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + self.api_filters.extend( + ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', + 'Game Outcomes', 'Awards']) filter_dict = {} - for x, stat in enumerate(self.displayed_filters): filter_dict[stat] = self.api_filters[x] @@ -70,20 +72,16 @@ def get_stat(self, stat, game_mode): return self.result_json['rating'] elif stat == 'Prestige': return self.result_json['prestige'] - elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver','medalsGold']: + elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']: return self.result_json[game_mode]['awards'][stat] elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] - elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: + elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', + 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] - elif stat in ['barrierDamageDone', 'damageDone', 'deaths','eliminations','soloKills','objectiveKills']: + elif stat in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] - else: - return self.result_json[stat] - - + return self.result_json[stat] ov = Overwatch('pc', 'us', 'cats-11481') - - From e4afcf9089dd6d54db6b8a9d97b858ee7e2e5a51 Mon Sep 17 00:00:00 2001 From: Yash Date: Sun, 11 Apr 2021 14:20:22 -0400 Subject: [PATCH 14/21] Finished debugging almost --- GUI.py | 4 +- Pages.py | 200 ++++++++++++++++++++++++++++---------------------- apicollect.py | 91 ++++++++++++++++------- 3 files changed, 177 insertions(+), 118 deletions(-) diff --git a/GUI.py b/GUI.py index a62ee38..1c24d64 100644 --- a/GUI.py +++ b/GUI.py @@ -4,7 +4,6 @@ from Pages import PageOne from apicollect import Overwatch - class FirstGUI(tk.Tk): """ This is pertaining to Overwatch only, Remember that in the apicollect.py file, @@ -28,7 +27,6 @@ def change_frame(self, change_frame, *player_info): self._frame = new_frame self._frame.pack() - if __name__ == "__main__": app = FirstGUI() - app.mainloop() + app.mainloop() \ No newline at end of file diff --git a/Pages.py b/Pages.py index 9ca7655..8cc9ac3 100644 --- a/Pages.py +++ b/Pages.py @@ -3,9 +3,6 @@ from tkinter import messagebox from tkinter import ttk from apicollect import Overwatch -from PIL import ImageTk, Image -import glob -import os """ Sources: @@ -16,37 +13,33 @@ """ + + + + class PageOne(tk.Frame): def __init__(self, parent): - global img tk.Frame.__init__(self, parent) self.game = None self.labelSelect = Label(self, text='Choose a game to find stats to compare between multiple players') - self.labelSelect.grid(row=1, column=1) + self.labelSelect.grid(row=0, column=1) self.game_chosen = StringVar() # Create a dropdown menu self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) # Default text shown self.game_choices.set("Select a game") # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch'] - self.game_choices.grid(row=2, column=1) + self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] + self.game_choices.grid(row=1, column=1) + """ Idea: Maybe we can use validate commands for the entries """ - for filename in glob.glob('yourpath/logo.png'): - img = ImageTk.PhotoImage(Image.open(filename).resize((475, 221))) - self.panel = Label(self, image=img) - self.panel.grid(row=0, column=1, columnspan=4) - - # img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) - # self.panel = Label(self, image=img) - # self.panel.grid(row=0, column=1, columnspan=4) self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) - self.sub_btn.grid(row=3, column=1) + self.sub_btn.grid(row=2, column=1) self.sub_btn["state"] = DISABLED self.pack() @@ -59,6 +52,8 @@ def callback(self, event_object): self.sub_btn["state"] = NORMAL + + class PageTwo(tk.Frame): """ For Overwatch @@ -69,19 +64,19 @@ def __init__(self, parent): parent.title('Statistical Tracker for: Overwatch') tk.Label(self, text="Player information:").grid(row=0, column=0, columnspan=2) self.num_players = 0 - self.players = [] - + self.duplicate_profile = False self.parent = parent + self.ow_tree = ttk.Treeview(self) # Create the columns self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") - self.ow_tree.column("#0", width=120, minwidth=25) + self.ow_tree.column("#0", width=0, stretch=NO) self.ow_tree.column("Battle Tag", anchor=W, width=120) self.ow_tree.column("Platform", anchor=CENTER, width=80) self.ow_tree.column("Region", anchor=W, width=60) # Create the headings - self.ow_tree.heading("#0", text="Player #", anchor=W) + self.ow_tree.heading("#0", text="", anchor=W) self.ow_tree.heading("Battle Tag", text="Battle Tag", anchor=CENTER) self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) @@ -92,7 +87,6 @@ def __init__(self, parent): self.region_chosen = StringVar() self.battle_id = StringVar() - tk.Label(self, text="Player 1").grid(row=1, column=0, columnspan=2) tk.Label(self, text="Platform:").grid(row=2, column=0, columnspan=1) # Create a dropdown menu @@ -121,65 +115,82 @@ def __init__(self, parent): self.add_btn = Button(self, text='Add Player', command=self.add_player) self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.validate_tag(self.battle_id)) + self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) + self.add_btn.grid(row=1, padx=5, column=4) self.add_btn = Button(self, text='Clear', command=self.clear) self.add_btn.grid(row=2, column=4) self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) - self.sub_btn2 = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)) - self.sub_btn2.grid(row=4, column=4) - self.sub_btn2["state"] = DISABLED + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)) + self.sub_btn.grid(row=4, column=4) + self.sub_btn["state"] = DISABLED + + def validate_tag(self, id): - if "#" in id.get(): - self.battle_id.set(self.battle_id.get().replace("#", "-")) + if "#" or " " in id.get(): + self.battle_id.set(self.battle_id.get().replace("#", "-").replace(" ", "")) def add_player(self): try: o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) - if o.result and self.battle_id.get() not in self.players: - if not self.parent.game_filters: - self.parent.game_filters = o.get_filters() - self.parent.displayed_stats = o.displayed_filters + if o.result: + self.duplicate_profile = False + + for registered_player in self.parent.all_players: + if registered_player.information == [self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()]: + self.duplicate_profile = True + messagebox.showinfo('Error!', 'That profile has already been registered!') - self.players.append(self.battle_id.get()) - self.num_players += 1 - self.parent.all_players.extend([o]) + if not self.duplicate_profile: + if not self.parent.game_filters: + self.parent.game_filters = o.get_filters() + self.parent.displayed_stats = o.displayed_filters - self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), - values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + self.num_players += 1 - self.gamer_tag.delete(0, END) - self.platform_choices.set('Select a platform') - self.region_choices.set('Select a region') + self.parent.all_players.extend([o]) + + self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), + values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + + self.gamer_tag.delete(0, END) + self.platform_choices.set('Select a platform') + self.region_choices.set('Select a region') else: messagebox.showinfo('Error!', 'You have entered an invalid profile!') except: messagebox.showinfo('Error!', 'You have entered an invalid profile!') - self.callback() + finally: + if len(self.parent.all_players) >=2: + self.sub_btn["state"] = NORMAL def clear(self): for player in self.ow_tree.get_children(): self.ow_tree.delete(player) - self.num_players = 0 - self.callback() + self.parent.all_players.clear() + self.sub_btn["state"] = DISABLED def remove_players(self): - t = self.ow_tree.selection() - for player in t: - self.ow_tree.delete(player) - self.num_players -= 1 - self.callback() + curItem = self.ow_tree.focus() + deleted_player = self.ow_tree.item(curItem)['values'] + for player in self.parent.all_players: + if set(player.information) == set(deleted_player): + self.parent.all_players.remove(player) + selected = self.ow_tree.selection()[0] + self.ow_tree.delete(selected) + - def callback(self): - if self.num_players >= 2: - self.sub_btn2["state"] = NORMAL - else: - self.sub_btn2["state"] = DISABLED + + + # for player in t: + # self.ow_tree.delete(player) + # print(int(player)) + # del self.parent.all_players[int(player) - 1] class PageThree(tk.Frame): @@ -192,53 +203,56 @@ def __init__(self, parent): self.parent = parent self.Label_Stats = Label(self, text='Choose at least two stats to compare') - self.Label_Stats.grid(row=0, column=1, columnspan=2) + self.Label_Stats.grid(row=0, column=1, columnspan = 2) self.gameplay = StringVar() - self.qp_btn = Radiobutton(self, text="Quick Play", variable=self.gameplay, value="quickPlayStats", - command=lambda: self.gameplay_chosen(), tristatevalue=0) - self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", - command=lambda: self.gameplay_chosen(), tristatevalue=0) + self.qp_btn = Radiobutton(self, text ="Quick Play", variable = self.gameplay, value = "quickPlayStats", command = lambda: self.gameplay_chosen(), tristatevalue=0) + self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", command=lambda: self.gameplay_chosen(), tristatevalue=0) + - self.qp_btn.grid(row=1, column=1) - self.cp_btn.grid(row=1, column=2) - self.scrollbar = Scrollbar(self, orient=VERTICAL) + self.qp_btn.grid(row = 1, column = 1) + self.cp_btn.grid(row = 1, column = 2) + + self.scrollbar = Scrollbar(self, orient = VERTICAL) self.scrollbar.grid(row=2, column=2, sticky=tk.N + tk.S) self.filter_list = self.parent.displayed_stats - self.filter_lb = Listbox(self, selectmode=MULTIPLE, width=50, yscrollcommand=self.scrollbar.set) + + + self.filter_lb = Listbox(self, selectmode = MULTIPLE, width = 50, yscrollcommand=self.scrollbar.set) for filter in self.filter_list[1:]: self.filter_lb.insert(END, filter) - self.filter_lb.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W) + self.filter_lb.grid(row = 2, column = 1, sticky=tk.N + tk.S + tk.E + tk.W) self.filter_lb["state"] = DISABLED self.filter_lb.bind("<>", self.selected_stats) self.scrollbar['command'] = self.filter_lb.yview self.sbt_stats = Button(self, text='Submit', command=lambda: parent.change_frame(PageFour)) - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageTwo)) self.sbt_stats.grid(row=3, column=1) - self.back_btn.grid(row=3, column=2) self.sbt_stats["state"] = DISABLED def selected_stats(self, lb): selected_stats = lb.widget.curselection() self.parent.compared_stats = ["Name"] - if selected_stats != (): + if (selected_stats != ()): for stat in selected_stats: - if self.filter_list[int(stat) + 1] not in self.parent.compared_stats: + if self.filter_list[int(stat)+1] not in self.parent.compared_stats: self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) if len(self.parent.compared_stats) >= 2: self.sbt_stats["state"] = NORMAL else: self.sbt_stats["state"] = DISABLED + + def gameplay_chosen(self): self.filter_lb["state"] = NORMAL self.parent.game_mode = self.gameplay.get() + class PageFour(tk.Frame): """ The Fourth page @@ -253,24 +267,23 @@ def __init__(self, parent): self.Label_table.grid(row=0, column=1, columnspan=2) self.tree_stats = {} - self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', - 'Silver Medals': 'medalsSilver', - 'Gold Medals': 'medalsGold'} - self.sub_game_results = {'Games Won': 'gamesWon', 'gamesLost': 'gamesLost', 'gamesPlayed': 'gamesPlayed'} + self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', 'Silver Medals': 'medalsSilver', + 'Gold Medals': 'medalsGold'} + self.sub_game_results = {'Games Won':'gamesWon', 'gamesLost':'gamesLost', 'gamesPlayed':'gamesPlayed'} self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths', - 'eliminations': 'eliminations', 'soloKills': 'soloKills', - 'objectiveKills': 'objectiveKills'} - self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', - 'barrierDamageDoneMostInGame': 'barrierDamageDoneMostInGame', - 'eliminationsMostInGame': 'eliminationsMostInGame', - 'healingDoneMostInGame': 'healingDoneMostInGame', - 'killsStreakBest': 'killsStreakBest', 'multikillsBest': 'multikillsBest'} + 'eliminations': 'eliminations','soloKills': 'soloKills','objectiveKills': 'objectiveKills'} + self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', 'barrierDamageDoneMostInGame':'barrierDamageDoneMostInGame', 'eliminationsMostInGame':'eliminationsMostInGame', + 'healingDoneMostInGame':'healingDoneMostInGame', 'killsStreakBest':'killsStreakBest', 'multikillsBest':'multikillsBest'} self.in_game_index = 0 self.best_in_game_index = 0 self.game_outcome_index = 0 self.awards_index = 0 - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageThree)).grid(row=3, - column=2) + + + + + + for stat in self.parent.compared_stats: self.tree_stats[stat] = [] @@ -280,17 +293,20 @@ def __init__(self, parent): # Create the columns self.ow_stat_tree['columns'] = self.tree_stats['Name'] + self.ow_stat_tree.column("#0", width=120, minwidth=25) # for x, stat in enumerate(self.tree_stats['Name']): + self.ow_stat_tree.column(x, anchor=CENTER, width=100) # Create the headings self.ow_stat_tree.heading("#0", text="Player #", anchor=W) for x, stat in enumerate(self.tree_stats['Name']): - self.ow_stat_tree.heading(x, text="Player {}".format(x + 1), anchor=CENTER) - self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, - sticky=E + W + S + N) + self.ow_stat_tree.heading(x, text="Player {}".format(x+1), anchor=CENTER) + self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, sticky=E + W + S + N) + + for x, stat in enumerate(self.tree_stats): """ @@ -309,19 +325,19 @@ def __init__(self, parent): self.awards_index = x self.ow_stat_tree.insert('', index='end', iid=x, text=stat) elif stat in self.sub_awards: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.awards_index), str(self.awards_index)) elif stat in self.best_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.best_in_game_index), str(self.best_in_game_index)) elif stat in self.in_game_stats: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.in_game_index), str(self.in_game_index)) elif stat in self.sub_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.game_outcome_index), str(self.game_outcome_index)) else: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] @@ -354,7 +370,13 @@ def get_player_info(self, stat): for sub_stat in best_game_results: if sub_stat not in self.tree_stats: self.tree_stats[sub_stat] = [] - self.tree_stats[sub_stat].append( - player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) + self.tree_stats[sub_stat].append(player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) else: self.tree_stats[stat].append(player.get_stat(stat, self.parent.game_mode)) + + + + + + + diff --git a/apicollect.py b/apicollect.py index 83cc78e..80b7ac2 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,11 +1,11 @@ import requests - # API address we can fill the parameters: platform, region and battle tag of a player to get their profile url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete' class Overwatch: def __init__(self, platform, region, battle_tag): + self.information = [platform, region, battle_tag] # Send a request to the api to get information about the user profile self.result = requests.get(url.format(platform, region, battle_tag)) # Convert to JSON (basically dictionary formatted info) @@ -15,6 +15,7 @@ def __init__(self, platform, region, battle_tag): self.api_filters = [] self.sub_stats = [] + def get_filters(self): """ Get the main filters(stats) available for a user to select to compare with another player. @@ -24,14 +25,12 @@ def get_filters(self): """ # The primary filters - self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', - 'Best In-Game Stats', 'Game Outcomes', 'Awards'] - self.api_filters.extend( - ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', - 'Game Outcomes', 'Awards']) + self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + self.api_filters.extend(['name', 'level', 'prestige', 'rating','Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards']) filter_dict = {} + for x, stat in enumerate(self.displayed_filters): filter_dict[stat] = self.api_filters[x] @@ -61,27 +60,67 @@ def get_filters(self): # 'Game Outcomes', 'Awards']) def get_stat(self, stat, game_mode): + try: + if stat == 'Name': + return self.result_json['name'] + elif stat == 'Level': + return self.result_json['level'] + elif stat == 'Endorsement Level': + return self.result_json['endorsement'] + elif stat == 'Rating': + return self.result_json['rating'] + elif stat == 'Prestige': + return self.result_json['prestige'] + elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver','medalsGold']: + return self.result_json[game_mode]['awards'][stat] + elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: + return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] + elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: + return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] + elif stat in ['barrierDamageDone', 'damageDone', 'deaths','eliminations','soloKills','objectiveKills']: + return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] + else: + return self.result_json[stat] + except TypeError: + # If the api does not have the information associated with a profile + return 'N/A' + except KeyError: + return 'N/A' + + + - if stat == 'Name': - return self.result_json['name'] - elif stat == 'Level': - return self.result_json['level'] - elif stat == 'Endorsement Level': - return self.result_json['endorsement'] - elif stat == 'Rating': - return self.result_json['rating'] - elif stat == 'Prestige': - return self.result_json['prestige'] - elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']: - return self.result_json[game_mode]['awards'][stat] - elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: - return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] - elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', - 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: - return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] - elif stat in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: - return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] - return self.result_json[stat] + + # def analyze_stats(self, player): + # """ + # analyze the stats of a player and return an integer value representing its final + # score after evaluation + # + # :param player: Battle Tag of player + # :return: evaluation score + # """ + # if player == self.test_get_player_info()[0]: + # player_stats = self.test_get_player_info() + # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations + # return "Invalid player" + + # def compare_2players(self, player1, player2): + # """ + # compares stats of 2 players, and returns the winning player + # + # :param player1: Battle Tag of player1 + # :param player2: Battle Tag of player 2 + # :return: player with higher stats, else return a message saying players are equal + # """ + # if self.analyze_stats(player1) > self.analyze_stats(player2): + # return player1 + # elif self.analyze_stats(player1) < self.analyze_stats(player2): + # return player2 + # return "Players are equal in comparison" + +# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch ov = Overwatch('pc', 'us', 'cats-11481') + + From c396329372bd1d81cada06407986e13ac463e44a Mon Sep 17 00:00:00 2001 From: Yash Date: Sun, 11 Apr 2021 14:51:22 -0400 Subject: [PATCH 15/21] Finished debugging everything --- Pages.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Pages.py b/Pages.py index 8cc9ac3..0425261 100644 --- a/Pages.py +++ b/Pages.py @@ -232,6 +232,9 @@ def __init__(self, parent): self.sbt_stats.grid(row=3, column=1) self.sbt_stats["state"] = DISABLED + self.back_btn = Button(self, text='Go back', command=self.transfer_second_page) + self.back_btn.grid(row=3, column=2) + def selected_stats(self, lb): selected_stats = lb.widget.curselection() self.parent.compared_stats = ["Name"] @@ -245,6 +248,10 @@ def selected_stats(self, lb): else: self.sbt_stats["state"] = DISABLED + def transfer_second_page(self): + self.parent.all_players.clear() + self.parent.change_frame(PageTwo) + def gameplay_chosen(self): @@ -279,6 +286,13 @@ def __init__(self, parent): self.game_outcome_index = 0 self.awards_index = 0 + self.change_btn = Button(self, text='Change Filters', command=lambda: parent.change_frame(PageThree)) + self.change_btn.grid(row=5, column=1, columnspan=2) + + + self.back_btn = Button(self, text='New Comparision', command=self.transfer_second_page) + self.back_btn.grid(row = 4, column = 1, columnspan=2) + @@ -344,6 +358,17 @@ def __init__(self, parent): # self.api_filters.extend( # ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', # 'Game Outcomes', 'Awards']) + + def transfer_second_page(self): + self.parent.all_players.clear() + self.parent.game_filters = {} + self.parent.displayed_stats.clear() + self.parent.compared_stats.clear() + self.parent.game_mode = None + self.compared_players.clear() + self.compared_stats.clear() + self.parent.change_frame(PageTwo) + def get_player_info(self, stat): for player in self.compared_players: From c0f74ab59895521972c7e339270bfcb99f69d37e Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sun, 11 Apr 2021 15:04:42 -0400 Subject: [PATCH 16/21] PEP styled, logo loads on different paths (almost) --- GUI.py | 5 ++- Pages.py | 120 ++++++++++++++++++++++---------------------------- apicollect.py | 46 +++++++++---------- 3 files changed, 79 insertions(+), 92 deletions(-) diff --git a/GUI.py b/GUI.py index 1c24d64..e8851a4 100644 --- a/GUI.py +++ b/GUI.py @@ -4,11 +4,13 @@ from Pages import PageOne from apicollect import Overwatch + class FirstGUI(tk.Tk): """ This is pertaining to Overwatch only, Remember that in the apicollect.py file, Overwatch API requires you to put in platform, region and battle id of the player. """ + def __init__(self): tk.Tk.__init__(self) self.title("Statistical Tracker for:") @@ -27,6 +29,7 @@ def change_frame(self, change_frame, *player_info): self._frame = new_frame self._frame.pack() + if __name__ == "__main__": app = FirstGUI() - app.mainloop() \ No newline at end of file + app.mainloop() diff --git a/Pages.py b/Pages.py index 0425261..145c469 100644 --- a/Pages.py +++ b/Pages.py @@ -3,6 +3,9 @@ from tkinter import messagebox from tkinter import ttk from apicollect import Overwatch +from PIL import Image +from PIL import ImageTk +import glob """ Sources: @@ -13,12 +16,9 @@ """ - - - - class PageOne(tk.Frame): def __init__(self, parent): + global img tk.Frame.__init__(self, parent) self.game = None @@ -33,10 +33,18 @@ def __init__(self, parent): self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] self.game_choices.grid(row=1, column=1) - """ Idea: Maybe we can use validate commands for the entries """ + for filename in glob.glob('yourpath/logo.png'): + img = ImageTk.PhotoImage(Image.open(filename).resize((475, 221))) + self.panel = Label(self, image=img) + self.panel.grid(row=0, column=1, columnspan=4) + + # img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) + + # self.panel = Label(self, image=img) + # self.panel.grid(row=0, column=1, columnspan=4) self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) self.sub_btn.grid(row=2, column=1) @@ -52,8 +60,6 @@ def callback(self, event_object): self.sub_btn["state"] = NORMAL - - class PageTwo(tk.Frame): """ For Overwatch @@ -67,7 +73,6 @@ def __init__(self, parent): self.duplicate_profile = False self.parent = parent - self.ow_tree = ttk.Treeview(self) # Create the columns self.ow_tree['columns'] = ("Battle Tag", "Platform", "Region") @@ -87,7 +92,6 @@ def __init__(self, parent): self.region_chosen = StringVar() self.battle_id = StringVar() - tk.Label(self, text="Platform:").grid(row=2, column=0, columnspan=1) # Create a dropdown menu self.platform_choices = ttk.Combobox(self, state="readonly", textvariable=self.platform_chosen, width=30) @@ -125,8 +129,6 @@ def __init__(self, parent): self.sub_btn.grid(row=4, column=4) self.sub_btn["state"] = DISABLED - - def validate_tag(self, id): if "#" or " " in id.get(): self.battle_id.set(self.battle_id.get().replace("#", "-").replace(" ", "")) @@ -140,7 +142,8 @@ def add_player(self): self.duplicate_profile = False for registered_player in self.parent.all_players: - if registered_player.information == [self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()]: + if registered_player.information == [self.platform_chosen.get(), self.region_chosen.get(), + self.battle_id.get()]: self.duplicate_profile = True messagebox.showinfo('Error!', 'That profile has already been registered!') @@ -153,8 +156,10 @@ def add_player(self): self.parent.all_players.extend([o]) - self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), - values=(self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + self.ow_tree.insert('', index='end', iid=self.num_players, + text="Player {}".format(self.num_players), + values=( + self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) self.gamer_tag.delete(0, END) self.platform_choices.set('Select a platform') @@ -166,7 +171,7 @@ def add_player(self): except: messagebox.showinfo('Error!', 'You have entered an invalid profile!') finally: - if len(self.parent.all_players) >=2: + if len(self.parent.all_players) >= 2: self.sub_btn["state"] = NORMAL def clear(self): @@ -184,9 +189,6 @@ def remove_players(self): selected = self.ow_tree.selection()[0] self.ow_tree.delete(selected) - - - # for player in t: # self.ow_tree.delete(player) # print(int(player)) @@ -203,27 +205,25 @@ def __init__(self, parent): self.parent = parent self.Label_Stats = Label(self, text='Choose at least two stats to compare') - self.Label_Stats.grid(row=0, column=1, columnspan = 2) + self.Label_Stats.grid(row=0, column=1, columnspan=2) self.gameplay = StringVar() - self.qp_btn = Radiobutton(self, text ="Quick Play", variable = self.gameplay, value = "quickPlayStats", command = lambda: self.gameplay_chosen(), tristatevalue=0) - self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", command=lambda: self.gameplay_chosen(), tristatevalue=0) + self.qp_btn = Radiobutton(self, text="Quick Play", variable=self.gameplay, value="quickPlayStats", + command=lambda: self.gameplay_chosen(), tristatevalue=0) + self.cp_btn = Radiobutton(self, text="Competitive", variable=self.gameplay, value="competitiveStats", + command=lambda: self.gameplay_chosen(), tristatevalue=0) + self.qp_btn.grid(row=1, column=1) + self.cp_btn.grid(row=1, column=2) - - self.qp_btn.grid(row = 1, column = 1) - self.cp_btn.grid(row = 1, column = 2) - - self.scrollbar = Scrollbar(self, orient = VERTICAL) + self.scrollbar = Scrollbar(self, orient=VERTICAL) self.scrollbar.grid(row=2, column=2, sticky=tk.N + tk.S) self.filter_list = self.parent.displayed_stats - - - self.filter_lb = Listbox(self, selectmode = MULTIPLE, width = 50, yscrollcommand=self.scrollbar.set) + self.filter_lb = Listbox(self, selectmode=MULTIPLE, width=50, yscrollcommand=self.scrollbar.set) for filter in self.filter_list[1:]: self.filter_lb.insert(END, filter) - self.filter_lb.grid(row = 2, column = 1, sticky=tk.N + tk.S + tk.E + tk.W) + self.filter_lb.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W) self.filter_lb["state"] = DISABLED self.filter_lb.bind("<>", self.selected_stats) self.scrollbar['command'] = self.filter_lb.yview @@ -241,7 +241,7 @@ def selected_stats(self, lb): if (selected_stats != ()): for stat in selected_stats: - if self.filter_list[int(stat)+1] not in self.parent.compared_stats: + if self.filter_list[int(stat) + 1] not in self.parent.compared_stats: self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) if len(self.parent.compared_stats) >= 2: self.sbt_stats["state"] = NORMAL @@ -252,14 +252,11 @@ def transfer_second_page(self): self.parent.all_players.clear() self.parent.change_frame(PageTwo) - - def gameplay_chosen(self): self.filter_lb["state"] = NORMAL self.parent.game_mode = self.gameplay.get() - class PageFour(tk.Frame): """ The Fourth page @@ -274,13 +271,18 @@ def __init__(self, parent): self.Label_table.grid(row=0, column=1, columnspan=2) self.tree_stats = {} - self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', 'Silver Medals': 'medalsSilver', - 'Gold Medals': 'medalsGold'} - self.sub_game_results = {'Games Won':'gamesWon', 'gamesLost':'gamesLost', 'gamesPlayed':'gamesPlayed'} + self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', + 'Silver Medals': 'medalsSilver', + 'Gold Medals': 'medalsGold'} + self.sub_game_results = {'Games Won': 'gamesWon', 'gamesLost': 'gamesLost', 'gamesPlayed': 'gamesPlayed'} self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths', - 'eliminations': 'eliminations','soloKills': 'soloKills','objectiveKills': 'objectiveKills'} - self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', 'barrierDamageDoneMostInGame':'barrierDamageDoneMostInGame', 'eliminationsMostInGame':'eliminationsMostInGame', - 'healingDoneMostInGame':'healingDoneMostInGame', 'killsStreakBest':'killsStreakBest', 'multikillsBest':'multikillsBest'} + 'eliminations': 'eliminations', 'soloKills': 'soloKills', + 'objectiveKills': 'objectiveKills'} + self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', + 'barrierDamageDoneMostInGame': 'barrierDamageDoneMostInGame', + 'eliminationsMostInGame': 'eliminationsMostInGame', + 'healingDoneMostInGame': 'healingDoneMostInGame', + 'killsStreakBest': 'killsStreakBest', 'multikillsBest': 'multikillsBest'} self.in_game_index = 0 self.best_in_game_index = 0 self.game_outcome_index = 0 @@ -289,15 +291,8 @@ def __init__(self, parent): self.change_btn = Button(self, text='Change Filters', command=lambda: parent.change_frame(PageThree)) self.change_btn.grid(row=5, column=1, columnspan=2) - self.back_btn = Button(self, text='New Comparision', command=self.transfer_second_page) - self.back_btn.grid(row = 4, column = 1, columnspan=2) - - - - - - + self.back_btn.grid(row=4, column=1, columnspan=2) for stat in self.parent.compared_stats: self.tree_stats[stat] = [] @@ -307,20 +302,17 @@ def __init__(self, parent): # Create the columns self.ow_stat_tree['columns'] = self.tree_stats['Name'] - self.ow_stat_tree.column("#0", width=120, minwidth=25) # for x, stat in enumerate(self.tree_stats['Name']): - self.ow_stat_tree.column(x, anchor=CENTER, width=100) # Create the headings self.ow_stat_tree.heading("#0", text="Player #", anchor=W) for x, stat in enumerate(self.tree_stats['Name']): - self.ow_stat_tree.heading(x, text="Player {}".format(x+1), anchor=CENTER) - self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, sticky=E + W + S + N) - - + self.ow_stat_tree.heading(x, text="Player {}".format(x + 1), anchor=CENTER) + self.ow_stat_tree.grid(row=0, column=2, rowspan=len(self.tree_stats['Name']) + 1, padx=5, pady=5, + sticky=E + W + S + N) for x, stat in enumerate(self.tree_stats): """ @@ -339,19 +331,19 @@ def __init__(self, parent): self.awards_index = x self.ow_stat_tree.insert('', index='end', iid=x, text=stat) elif stat in self.sub_awards: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.awards_index), str(self.awards_index)) elif stat in self.best_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.best_in_game_index), str(self.best_in_game_index)) elif stat in self.in_game_stats: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.in_game_index), str(self.in_game_index)) elif stat in self.sub_game_results: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) self.ow_stat_tree.move(str(x), str(self.game_outcome_index), str(self.game_outcome_index)) else: - self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values = self.tree_stats[stat]) + self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] @@ -395,13 +387,7 @@ def get_player_info(self, stat): for sub_stat in best_game_results: if sub_stat not in self.tree_stats: self.tree_stats[sub_stat] = [] - self.tree_stats[sub_stat].append(player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) + self.tree_stats[sub_stat].append( + player.get_stat(best_game_results[sub_stat], self.parent.game_mode)) else: self.tree_stats[stat].append(player.get_stat(stat, self.parent.game_mode)) - - - - - - - diff --git a/apicollect.py b/apicollect.py index 80b7ac2..874f1b1 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,4 +1,5 @@ import requests + # API address we can fill the parameters: platform, region and battle tag of a player to get their profile url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete' @@ -15,7 +16,6 @@ def __init__(self, platform, region, battle_tag): self.api_filters = [] self.sub_stats = [] - def get_filters(self): """ Get the main filters(stats) available for a user to select to compare with another player. @@ -25,12 +25,14 @@ def get_filters(self): """ # The primary filters - self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards'] - self.api_filters.extend(['name', 'level', 'prestige', 'rating','Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', 'Game Outcomes', 'Awards']) + self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', + 'Best In-Game Stats', 'Game Outcomes', 'Awards'] + self.api_filters.extend( + ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', + 'Game Outcomes', 'Awards']) filter_dict = {} - for x, stat in enumerate(self.displayed_filters): filter_dict[stat] = self.api_filters[x] @@ -71,13 +73,14 @@ def get_stat(self, stat, game_mode): return self.result_json['rating'] elif stat == 'Prestige': return self.result_json['prestige'] - elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver','medalsGold']: + elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']: return self.result_json[game_mode]['awards'][stat] elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] - elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: + elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', + 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] - elif stat in ['barrierDamageDone', 'damageDone', 'deaths','eliminations','soloKills','objectiveKills']: + elif stat in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] else: return self.result_json[stat] @@ -87,22 +90,18 @@ def get_stat(self, stat, game_mode): except KeyError: return 'N/A' - - - - # def analyze_stats(self, player): - # """ - # analyze the stats of a player and return an integer value representing its final - # score after evaluation - # - # :param player: Battle Tag of player - # :return: evaluation score - # """ - # if player == self.test_get_player_info()[0]: - # player_stats = self.test_get_player_info() - # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations - # return "Invalid player" + # """ + # analyze the stats of a player and return an integer value representing its final + # score after evaluation + # + # :param player: Battle Tag of player + # :return: evaluation score + # """ + # if player == self.test_get_player_info()[0]: + # player_stats = self.test_get_player_info() + # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations + # return "Invalid player" # def compare_2players(self, player1, player2): # """ @@ -118,9 +117,8 @@ def get_stat(self, stat, game_mode): # return player2 # return "Players are equal in comparison" + # Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch ov = Overwatch('pc', 'us', 'cats-11481') - - From 58221213fcbd3f38cdf8dc15e862c71d7d98b869 Mon Sep 17 00:00:00 2001 From: AnasKhan0607 <76663779+AnasKhan0607@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:31:15 -0400 Subject: [PATCH 17/21] logo --- Pages.py | 4 ++-- logo.png | Bin 0 -> 14254 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 logo.png diff --git a/Pages.py b/Pages.py index 145c469..8672baf 100644 --- a/Pages.py +++ b/Pages.py @@ -36,8 +36,8 @@ def __init__(self, parent): """ Idea: Maybe we can use validate commands for the entries """ - for filename in glob.glob('yourpath/logo.png'): - img = ImageTk.PhotoImage(Image.open(filename).resize((475, 221))) + for filename in glob.glob('logo.png'): + img = ImageTk.PhotoImage(Image.open(filename).resize((380, 221))) self.panel = Label(self, image=img) self.panel.grid(row=0, column=1, columnspan=4) diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e055514bccd4713be332ae81100681434b522cf6 GIT binary patch literal 14254 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 literal 0 HcmV?d00001 From 17f316a2afd9e481d35daee87a757fd027029d4a Mon Sep 17 00:00:00 2001 From: Rieley Hega Date: Sun, 11 Apr 2021 23:00:19 -0400 Subject: [PATCH 18/21] Second page edits and formatting --- GUI.py | 1 + Pages.py | 22 +++++++++++++++------- __pycache__/Pages.cpython-39.pyc | Bin 4926 -> 12165 bytes __pycache__/apicollect.cpython-39.pyc | Bin 2915 -> 2394 bytes 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/GUI.py b/GUI.py index e8851a4..aea806a 100644 --- a/GUI.py +++ b/GUI.py @@ -13,6 +13,7 @@ class FirstGUI(tk.Tk): def __init__(self): tk.Tk.__init__(self) + self.geometry("720x360") self.title("Statistical Tracker for:") self._frame = None self.change_frame(PageOne) diff --git a/Pages.py b/Pages.py index 8672baf..e6da35a 100644 --- a/Pages.py +++ b/Pages.py @@ -86,7 +86,7 @@ def __init__(self, parent): self.ow_tree.heading("Platform", text="Platform", anchor=W) self.ow_tree.heading("Region", text="Region", anchor=CENTER) - self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=5, sticky=E + W + S + N) + self.ow_tree.grid(row=0, column=2, rowspan=5, padx=5, pady=20, sticky=E + W + S + N) self.platform_chosen = StringVar() self.region_chosen = StringVar() @@ -113,22 +113,30 @@ def __init__(self, parent): tk.Label(self, text="Battle Tag:").grid(row=4, column=0, columnspan=1) self.battle_id.trace("w", lambda name, index, mode, new_id=self.battle_id: self.validate_tag(new_id)) - self.gamer_tag = Entry(self, textvariable=self.battle_id) + self.gamer_tag = Entry(self, textvariable=self.battle_id, width=33) self.gamer_tag.grid(row=4, column=1) - self.add_btn = Button(self, text='Add Player', command=self.add_player) + self.add_btn = Button(self, text='Add Player', command=self.add_player, height = 1, width = 20) self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players) + self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players, height = 1, width = 20) self.add_btn.grid(row=1, padx=5, column=4) - self.add_btn = Button(self, text='Clear', command=self.clear) + self.add_btn = Button(self, text='Clear', command=self.clear, height = 1, width = 20) self.add_btn.grid(row=2, column=4) - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne)).grid(row=3, column=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree)) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne), height = 1, width = 20).grid(row=3, column=4) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree), height = 1, width = 20) self.sub_btn.grid(row=4, column=4) self.sub_btn["state"] = DISABLED + tk.Label(self, text="Sample input to compare:\nPlatform: pc \nRegion: us \nID: OmniOptic-1773", + anchor="w", width = 30, justify=LEFT).grid(row=5, column=2, columnspan = 1) + tk.Label(self, text="How to use: \nSelect a platform and region, \nthen type in the BattleTag of the player." + "\nMore than 2 players are allowed.", + anchor="e", width = 30, justify=LEFT).grid(row=5, column=1, columnspan=1) + + + def validate_tag(self, id): if "#" or " " in id.get(): self.battle_id.set(self.battle_id.get().replace("#", "-").replace(" ", "")) diff --git a/__pycache__/Pages.cpython-39.pyc b/__pycache__/Pages.cpython-39.pyc index ecbfefcb95ebf5a2730e415decc36a34c47ed360..caf844e0b117d15dd98bf9103047ef42e5393f7c 100644 GIT binary patch literal 12165 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

9v zpS-HGvm1wRSdeBw+ILZ&T2Horyy^-H&)aff2_pRUWwS$Gmwc{Y9j<5&k4EEz4@?s(@)OIzrn=I zzb5jRME(i{fo)cSzo&w~Bl24y*o(35*&%hPj8)|yC`I0k{3j52M&!RrTBIDkmLvip zY#1?axSPGtJ>o_DBQS@gRIebRVIkr`Bvz^8k4@83B;_N;8-9>6mHW&4&mKE9TTDIP zar-`=D5(Q|o$C2)9aQ9~XRNLi?|#?Lu#;6Bj8fq;{CZES2or6g>XbfHUa8{y9SZrY z&wb4+7ccSGp8O4{JWZTW6CtT;t<6)aLxdmRBQ!zyFjjr1cotpJf^iT!y{5Ag^|!Ob M&kTP>D-56gKQ;PPC;$Ke literal 4926 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 NvN~kGxBm62`!8Q?1=aun From dcba32c681e98d4ef73c1bc4a32d4d9c071253bd Mon Sep 17 00:00:00 2001 From: Yash Date: Sun, 11 Apr 2021 23:42:38 -0400 Subject: [PATCH 19/21] Finished Project --- GUI.py | 6 +++ Pages.py | 96 ++++++++++++++++++++++++++---------------------- apicollect.py | 100 +++++++++++++++----------------------------------- 3 files changed, 88 insertions(+), 114 deletions(-) diff --git a/GUI.py b/GUI.py index aea806a..778f7d8 100644 --- a/GUI.py +++ b/GUI.py @@ -24,6 +24,9 @@ def __init__(self): self.game_mode = None def change_frame(self, change_frame, *player_info): + """ + Needed to handle frame changes so that the user can move from one window to the other + """ new_frame = change_frame(self) if self._frame is not None: self._frame.destroy() @@ -32,5 +35,8 @@ def change_frame(self, change_frame, *player_info): if __name__ == "__main__": + """ + Runs the application + """ app = FirstGUI() app.mainloop() diff --git a/Pages.py b/Pages.py index e6da35a..5a2969d 100644 --- a/Pages.py +++ b/Pages.py @@ -17,6 +17,9 @@ class PageOne(tk.Frame): + """ + The introduction page to the GUI + """ def __init__(self, parent): global img tk.Frame.__init__(self, parent) @@ -29,23 +32,18 @@ def __init__(self, parent): self.game_choices = ttk.Combobox(self, state="readonly", textvariable=self.game_chosen, width=30) # Default text shown self.game_choices.set("Select a game") - # Possible games to choose from: Cold war and WoW are examples for now - self.game_choices['values'] = ['Overwatch', 'Fortnite', 'Cold War', 'WoW'] + # Possible games to choose from: We used Overwatch + self.game_choices['values'] = ['Overwatch'] self.game_choices.grid(row=1, column=1) """ - Idea: Maybe we can use validate commands for the entries + To use the logo image on the front page """ for filename in glob.glob('logo.png'): img = ImageTk.PhotoImage(Image.open(filename).resize((380, 221))) self.panel = Label(self, image=img) self.panel.grid(row=0, column=1, columnspan=4) - # img = ImageTk.PhotoImage(Image.open(r"C:\Users\maste\Desktop\CCT211\Term_Project\logo.png").resize((475, 221))) - - # self.panel = Label(self, image=img) - # self.panel.grid(row=0, column=1, columnspan=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageTwo, "Hello")) self.sub_btn.grid(row=2, column=1) self.sub_btn["state"] = DISABLED @@ -55,6 +53,9 @@ def __init__(self, parent): self.game_choices.bind("<>", self.callback) def callback(self, event_object): + """ + To ensure a game is selected to enable the submit button + """ self.game = event_object.widget.get() if self.game != "Select a game": self.sub_btn["state"] = NORMAL @@ -62,7 +63,7 @@ def callback(self, event_object): class PageTwo(tk.Frame): """ - For Overwatch + The second page for accepting player to compare stats with. """ def __init__(self, parent): @@ -135,14 +136,19 @@ def __init__(self, parent): "\nMore than 2 players are allowed.", anchor="e", width = 30, justify=LEFT).grid(row=5, column=1, columnspan=1) - - - def validate_tag(self, id): - if "#" or " " in id.get(): + def validate_tag(self, check_id): + """ + Battle tags used in the API request must not contain spaces or #'s (-'s are used to replace them). + """ + if "#" or " " in check_id.get(): self.battle_id.set(self.battle_id.get().replace("#", "-").replace(" ", "")) def add_player(self): - + """ + Validates a player in the API, and adds it to the list of all players who have been registered. + If the player is not found in the API it is not valid, and error messages are used to inform users + about this. There must be at least two players registered to submit. + """ try: o = Overwatch(self.platform_chosen.get(), self.region_chosen.get(), self.battle_id.get()) @@ -183,29 +189,30 @@ def add_player(self): self.sub_btn["state"] = NORMAL def clear(self): + """ + Clears all the players registered in the treeview + """ for player in self.ow_tree.get_children(): self.ow_tree.delete(player) self.parent.all_players.clear() self.sub_btn["state"] = DISABLED def remove_players(self): - curItem = self.ow_tree.focus() - deleted_player = self.ow_tree.item(curItem)['values'] + """ + Remove selected players registered in the treeview + """ + cur_item = self.ow_tree.focus() + deleted_player = self.ow_tree.item(cur_item)['values'] for player in self.parent.all_players: if set(player.information) == set(deleted_player): self.parent.all_players.remove(player) selected = self.ow_tree.selection()[0] self.ow_tree.delete(selected) - # for player in t: - # self.ow_tree.delete(player) - # print(int(player)) - # del self.parent.all_players[int(player) - 1] - class PageThree(tk.Frame): """ - The Third page + The Third page for looking at the potential filters to compare the selected players with from page two. """ def __init__(self, parent): @@ -229,8 +236,8 @@ def __init__(self, parent): self.filter_list = self.parent.displayed_stats self.filter_lb = Listbox(self, selectmode=MULTIPLE, width=50, yscrollcommand=self.scrollbar.set) - for filter in self.filter_list[1:]: - self.filter_lb.insert(END, filter) + for new_filter in self.filter_list[1:]: + self.filter_lb.insert(END, new_filter) self.filter_lb.grid(row=2, column=1, sticky=tk.N + tk.S + tk.E + tk.W) self.filter_lb["state"] = DISABLED self.filter_lb.bind("<>", self.selected_stats) @@ -244,11 +251,14 @@ def __init__(self, parent): self.back_btn.grid(row=3, column=2) def selected_stats(self, lb): + """ + To retrieve selected stats from the listbox the player can select filters from. At least one filter must be + selected, not included the default name to proceed. Resource to help us with this feature was listed in sources. + """ selected_stats = lb.widget.curselection() self.parent.compared_stats = ["Name"] if (selected_stats != ()): for stat in selected_stats: - if self.filter_list[int(stat) + 1] not in self.parent.compared_stats: self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) if len(self.parent.compared_stats) >= 2: @@ -267,7 +277,7 @@ def gameplay_chosen(self): class PageFour(tk.Frame): """ - The Fourth page + The fourth page used to display the players in a treeview to """ def __init__(self, parent): @@ -278,19 +288,19 @@ def __init__(self, parent): self.Label_table = Label(self, text='Table') self.Label_table.grid(row=0, column=1, columnspan=2) self.tree_stats = {} - + # Needed to organize the filters self.sub_awards = {'Cards': 'cards', 'Medals': 'medals', 'Bronze Medals': 'medalsBronze', 'Silver Medals': 'medalsSilver', 'Gold Medals': 'medalsGold'} - self.sub_game_results = {'Games Won': 'gamesWon', 'gamesLost': 'gamesLost', 'gamesPlayed': 'gamesPlayed'} - self.in_game_stats = {'barrierDamageDone': 'barrierDamageDone', 'damageDone': 'damageDone', 'deaths': 'deaths', - 'eliminations': 'eliminations', 'soloKills': 'soloKills', - 'objectiveKills': 'objectiveKills'} - self.best_game_results = {'allDamageDoneMostInGame': 'allDamageDoneMostInGame', - 'barrierDamageDoneMostInGame': 'barrierDamageDoneMostInGame', - 'eliminationsMostInGame': 'eliminationsMostInGame', - 'healingDoneMostInGame': 'healingDoneMostInGame', - 'killsStreakBest': 'killsStreakBest', 'multikillsBest': 'multikillsBest'} + self.sub_game_results = {'Games Won': 'gamesWon', 'GamesLost': 'gamesLost', 'Games Played': 'gamesPlayed'} + self.in_game_stats = {'Barrier DamageDone': 'barrierDamageDone', 'Damage Done': 'damageDone', 'Deaths': 'deaths', + 'Eliminations': 'eliminations', 'Solo Kills': 'soloKills', + 'Objective Kills': 'objectiveKills'} + self.best_game_results = {'All Damage Done Most In Game': 'allDamageDoneMostInGame', + 'Barrier Damage Done Most In Game': 'barrierDamageDoneMostInGame', + 'Eliminations Most In Game': 'eliminationsMostInGame', + 'Healing Done Most In Game': 'healingDoneMostInGame', + 'Kills Streak Best': 'killsStreakBest', 'Multi kills Best': 'multikillsBest'} self.in_game_index = 0 self.best_in_game_index = 0 self.game_outcome_index = 0 @@ -353,13 +363,11 @@ def __init__(self, parent): else: self.ow_stat_tree.insert('', index='end', iid=x, text=stat, values=self.tree_stats[stat]) - # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', - # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] - # self.api_filters.extend( - # ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', - # 'Game Outcomes', 'Awards']) - def transfer_second_page(self): + """ + To revisit the second page from the third page, clearing information about the filters that could + have been selected + """ self.parent.all_players.clear() self.parent.game_filters = {} self.parent.displayed_stats.clear() @@ -370,7 +378,9 @@ def transfer_second_page(self): self.parent.change_frame(PageTwo) def get_player_info(self, stat): - + """ + Organizes the information for each player for each particular filter to access it later on. + """ for player in self.compared_players: if stat == 'Awards': sub_awards = self.sub_awards diff --git a/apicollect.py b/apicollect.py index 874f1b1..7268a65 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,10 +1,17 @@ import requests - +""" +Required installments: requests +""" # API address we can fill the parameters: platform, region and battle tag of a player to get their profile url = 'https://ow-api.com/v1/stats/{}/{}/{}/complete' class Overwatch: + """ + This is the class for the game which keeps track of all the players in it. + It sends requests to the Overwatch API online to fetch stats of players in the game. + To fetch the results the user needs to input a valid platform, region and battle tag of their account. + """ def __init__(self, platform, region, battle_tag): self.information = [platform, region, battle_tag] # Send a request to the api to get information about the user profile @@ -36,89 +43,40 @@ def get_filters(self): for x, stat in enumerate(self.displayed_filters): filter_dict[stat] = self.api_filters[x] - # - # for match_filter in ['quickPlayStats', 'competitiveStats']: - # qp_game_filters = [] - # qp_award_filters = [] - # qp_total_filters = [] - # for qp_filter in self.result_json[match_filter]: - # if qp_filter == 'games': - # for game_filter in self.result_json[match_filter]['games']: - # qp_game_filters.extend(([game_filter])) - # qp_total_filters.extend([qp_filter, qp_game_filters]) - # elif qp_filter == 'awards': - # - # for award_filter in self.result_json[match_filter]['awards']: - # qp_award_filters.extend(([award_filter])) - # - # qp_total_filters.extend([qp_filter, qp_award_filters]) - # self.filters.extend([[match_filter, qp_total_filters]]) return filter_dict - # self.displayed_filters = ['Name', 'Level', 'Prestige', 'Rating', 'Endorsement Level', 'In-Game Stats', - # 'Best In-Game Stats', 'Game Outcomes', 'Awards'] - # self.api_filters.extend( - # ['name', 'level', 'prestige', 'rating', 'Endorsement Level', 'In-Game Stats', 'Best In-Game Stats', - # 'Game Outcomes', 'Awards']) + def get_stat(self, find_filter, game_mode): + """ + Retrieve the required stat from the api, based on the user choice and game mode. + Certain stats/filters are not applicable for all gamers and as such they are not + listed in the API. N/A is used for such cases. - def get_stat(self, stat, game_mode): + :return: A stat from the api based on inputted game mode and filter + """ try: - if stat == 'Name': + if find_filter == 'Name': return self.result_json['name'] - elif stat == 'Level': + elif find_filter == 'Level': return self.result_json['level'] - elif stat == 'Endorsement Level': + elif find_filter == 'Endorsement Level': return self.result_json['endorsement'] - elif stat == 'Rating': + elif find_filter == 'Rating': return self.result_json['rating'] - elif stat == 'Prestige': + elif find_filter == 'Prestige': return self.result_json['prestige'] - elif stat in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']: - return self.result_json[game_mode]['awards'][stat] - elif stat in ['gameWon', 'gamesLost', 'gamesPlayed']: - return self.result_json[game_mode]['careerStats']['allHeroes']['game'][stat] - elif stat in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', + elif find_filter in ['cards', 'medals', 'medalsBronze', 'medalsSilver', 'medalsGold']: + return self.result_json[game_mode]['awards'][find_filter] + elif find_filter in ['gameWon', 'gamesLost', 'gamesPlayed']: + return self.result_json[game_mode]['careerStats']['allHeroes']['game'][find_filter] + elif find_filter in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: - return self.result_json[game_mode]['careerStats']['allHeroes']['best'][stat] - elif stat in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: - return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][stat] + return self.result_json[game_mode]['careerStats']['allHeroes']['best'][find_filter] + elif find_filter in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: + return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][find_filter] else: - return self.result_json[stat] + return self.result_json[find_filter] except TypeError: # If the api does not have the information associated with a profile return 'N/A' except KeyError: return 'N/A' - - # def analyze_stats(self, player): - # """ - # analyze the stats of a player and return an integer value representing its final - # score after evaluation - # - # :param player: Battle Tag of player - # :return: evaluation score - # """ - # if player == self.test_get_player_info()[0]: - # player_stats = self.test_get_player_info() - # return 0.6 * player_stats[1] + 0.8 * player_stats[2] + 0.8 * player_stats[3] # example calculations - # return "Invalid player" - - # def compare_2players(self, player1, player2): - # """ - # compares stats of 2 players, and returns the winning player - # - # :param player1: Battle Tag of player1 - # :param player2: Battle Tag of player 2 - # :return: player with higher stats, else return a message saying players are equal - # """ - # if self.analyze_stats(player1) > self.analyze_stats(player2): - # return player1 - # elif self.analyze_stats(player1) < self.analyze_stats(player2): - # return player2 - # return "Players are equal in comparison" - - -# Example of a user who uses platform is pc, region us, and battle tag of player of cats-11481 in Overwatch - - -ov = Overwatch('pc', 'us', 'cats-11481') From 64cc5b0dfe3e3fb5b02ac96d3c5f9ec025416345 Mon Sep 17 00:00:00 2001 From: emadahmad2001 <77213867+emadahmad2001@users.noreply.github.com> Date: Sun, 11 Apr 2021 23:51:25 -0400 Subject: [PATCH 20/21] Fixed styling --- Pages.py | 23 +++++++++++++---------- apicollect.py | 7 +++++-- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Pages.py b/Pages.py index 5a2969d..0cad454 100644 --- a/Pages.py +++ b/Pages.py @@ -20,6 +20,7 @@ class PageOne(tk.Frame): """ The introduction page to the GUI """ + def __init__(self, parent): global img tk.Frame.__init__(self, parent) @@ -118,23 +119,24 @@ def __init__(self, parent): self.gamer_tag.grid(row=4, column=1) - self.add_btn = Button(self, text='Add Player', command=self.add_player, height = 1, width = 20) + self.add_btn = Button(self, text='Add Player', command=self.add_player, height=1, width=20) self.add_btn.grid(row=0, column=4) - self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players, height = 1, width = 20) + self.add_btn = Button(self, text='Remove Player(s)', command=self.remove_players, height=1, width=20) self.add_btn.grid(row=1, padx=5, column=4) - self.add_btn = Button(self, text='Clear', command=self.clear, height = 1, width = 20) + self.add_btn = Button(self, text='Clear', command=self.clear, height=1, width=20) self.add_btn.grid(row=2, column=4) - self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne), height = 1, width = 20).grid(row=3, column=4) - self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree), height = 1, width = 20) + self.back_btn = Button(self, text='Go back', command=lambda: parent.change_frame(PageOne), height=1, + width=20).grid(row=3, column=4) + self.sub_btn = Button(self, text='Submit', command=lambda: parent.change_frame(PageThree), height=1, width=20) self.sub_btn.grid(row=4, column=4) self.sub_btn["state"] = DISABLED tk.Label(self, text="Sample input to compare:\nPlatform: pc \nRegion: us \nID: OmniOptic-1773", - anchor="w", width = 30, justify=LEFT).grid(row=5, column=2, columnspan = 1) + anchor="w", width=30, justify=LEFT).grid(row=5, column=2, columnspan=1) tk.Label(self, text="How to use: \nSelect a platform and region, \nthen type in the BattleTag of the player." "\nMore than 2 players are allowed.", - anchor="e", width = 30, justify=LEFT).grid(row=5, column=1, columnspan=1) + anchor="e", width=30, justify=LEFT).grid(row=5, column=1, columnspan=1) def validate_tag(self, check_id): """ @@ -173,7 +175,7 @@ def add_player(self): self.ow_tree.insert('', index='end', iid=self.num_players, text="Player {}".format(self.num_players), values=( - self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) + self.battle_id.get(), self.platform_chosen.get(), self.region_chosen.get())) self.gamer_tag.delete(0, END) self.platform_choices.set('Select a platform') @@ -257,7 +259,7 @@ def selected_stats(self, lb): """ selected_stats = lb.widget.curselection() self.parent.compared_stats = ["Name"] - if (selected_stats != ()): + if selected_stats != (): for stat in selected_stats: if self.filter_list[int(stat) + 1] not in self.parent.compared_stats: self.parent.compared_stats.append(self.filter_list[int(stat) + 1]) @@ -293,7 +295,8 @@ def __init__(self, parent): 'Silver Medals': 'medalsSilver', 'Gold Medals': 'medalsGold'} self.sub_game_results = {'Games Won': 'gamesWon', 'GamesLost': 'gamesLost', 'Games Played': 'gamesPlayed'} - self.in_game_stats = {'Barrier DamageDone': 'barrierDamageDone', 'Damage Done': 'damageDone', 'Deaths': 'deaths', + self.in_game_stats = {'Barrier DamageDone': 'barrierDamageDone', 'Damage Done': 'damageDone', + 'Deaths': 'deaths', 'Eliminations': 'eliminations', 'Solo Kills': 'soloKills', 'Objective Kills': 'objectiveKills'} self.best_game_results = {'All Damage Done Most In Game': 'allDamageDoneMostInGame', diff --git a/apicollect.py b/apicollect.py index 7268a65..73e83fd 100644 --- a/apicollect.py +++ b/apicollect.py @@ -1,4 +1,5 @@ import requests + """ Required installments: requests """ @@ -12,6 +13,7 @@ class Overwatch: It sends requests to the Overwatch API online to fetch stats of players in the game. To fetch the results the user needs to input a valid platform, region and battle tag of their account. """ + def __init__(self, platform, region, battle_tag): self.information = [platform, region, battle_tag] # Send a request to the api to get information about the user profile @@ -69,9 +71,10 @@ def get_stat(self, find_filter, game_mode): elif find_filter in ['gameWon', 'gamesLost', 'gamesPlayed']: return self.result_json[game_mode]['careerStats']['allHeroes']['game'][find_filter] elif find_filter in ['allDamageDoneMostInGame', 'barrierDamageDoneMostInGame', 'eliminationsMostInGame', - 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: + 'healingDoneMostInGame', 'killsStreakBest', 'multikillsBest']: return self.result_json[game_mode]['careerStats']['allHeroes']['best'][find_filter] - elif find_filter in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', 'objectiveKills']: + elif find_filter in ['barrierDamageDone', 'damageDone', 'deaths', 'eliminations', 'soloKills', + 'objectiveKills']: return self.result_json[game_mode]['careerStats']['allHeroes']['combat'][find_filter] else: return self.result_json[find_filter] From 72eb055f848c5d5c4dd68350636d2459df59f61a Mon Sep 17 00:00:00 2001 From: Rieley Hega Date: Sun, 11 Apr 2021 23:58:13 -0400 Subject: [PATCH 21/21] Second page updated with test cases --- Pages.py | 7 ++++++- __pycache__/Pages.cpython-39.pyc | Bin 12165 -> 13801 bytes __pycache__/apicollect.cpython-39.pyc | Bin 2394 -> 2988 bytes 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Pages.py b/Pages.py index 0cad454..793038c 100644 --- a/Pages.py +++ b/Pages.py @@ -132,7 +132,12 @@ def __init__(self, parent): self.sub_btn.grid(row=4, column=4) self.sub_btn["state"] = DISABLED - tk.Label(self, text="Sample input to compare:\nPlatform: pc \nRegion: us \nID: OmniOptic-1773", + tk.Label(self, text="Default profiles to test with:\n" + "(pc, us, cats-11481)\n" + "(pc, us, GamersCCCP-1569)\n" + "(pc, us, Morgan#22492)\n" + "(pc, us, justin#2882)\n" + "(pc, us, Justin-23138)", anchor="w", width=30, justify=LEFT).grid(row=5, column=2, columnspan=1) tk.Label(self, text="How to use: \nSelect a platform and region, \nthen type in the BattleTag of the player." "\nMore than 2 players are allowed.", diff --git a/__pycache__/Pages.cpython-39.pyc b/__pycache__/Pages.cpython-39.pyc index caf844e0b117d15dd98bf9103047ef42e5393f7c..de6017fc2855b8f2f3bb7f8f9b955e33b3ed8aad 100644 GIT binary patch delta 3995 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 Vr6JA&n|$cema$Fcz}8Ju{{^1zXlDQb delta 2441 zcmah~Yitx%6y7_#J3HOB+fvH*Mcb)ckPR$Iuso`QLP1`(g`&VBEYqD!ciP>Va%Re- zij`OsgJ{qjh!1{%KTI$ZLW<)1nFzj3)IX!~55I^p{857>KF+z@w2hLuoB8J4bIv{Y z-1C~N1CM87MtONOfIs7;yIWa*KGw+A%)})Rq?s8=D<(6Q(Lg$A2F(z@LuR-qkW~Fh zx6#MDY@StU@Axl>ZxtVUyD@Q^Wx{;{Gy0MUD!bUI=vA)i$qBaV5OHGJqZgJ7EUefhq*? zoVvbr8J$Uo2blOptz}`MMq0(9$ed^hc^cDZfhNw)Y80c9j_EZ~9e?P8-nEaze#6V= z#!9s7!6o;g?$rYbXB1yG>}<{fsKzC%BtbV(tBAT2!AB*a(81cVrDe+*bH)DhhgrAy zwfr8oO)QShVIv|FTa5IH*!*3Ol4gQ{d>&riV-yDST(|7OAy4-lJ?j((4dCt3?!4jc zaiGwy4`%h~X5MExcDp|0>d|!_?RrvAE1O!lWXU27=eP%U#dW53pk+5N^3(3G zn$2diN)}Z#rv9zcqlh1-4Q!*>g*$Js#0{q3U@6#uJJ1N-2Y_G!f*%1sm^ZRKsQ|^* zS1c2nNGhR)sO<{uPl8)>pioEev;OP}RTm*2!)l2P0etM90fWQSm##|!CL(E&4qK|II-j*CKlW5q$V z@IKj!6>U9Vzqr|tWHP3c&14{nOc_)l4}lJbgFSt1wL*Wg2qB2ZLJp4l9~#Q zvY^`=melp4Xt-8Z^_Cphx8y7^^+9Y=ahS!&{%BaPU==QHnpwRQ6{lqJ7F_-)a!sca z+eq-@g!CqQKZ&``t!$I%Zr+E+E;XlSTqAW^(yc`G5bPEu`XSXJ(iTVcRce9Ae(}A& zA@vZF$)GGL(2>TpS$PiwB+Kd$DazWSSbQrswfv@2tkq6G)M*rWQLB`+W)n~wiCu}g z>}7Ez(GY)?cx?z+&Q!E%CEp9Lh_@4UHLu|EcYIvh5@1pM<3Lcv&xxJO=-$b&bO)Y5 zx)^zyfIxwV$v{lj{#g_R#o^XH(?KAaRN*dCJwtF>{MlMpce7n5Q5+EqX0^|FffQxJ z$ul5xaFTK@^Y|4mU1}GZ>x5RWg`gKRy|MljGKcFXvb@F_0xu`iJhpQ7#n6af(uZ+! zH#)B8mr4?6$w6)=gTp2Fl0@I?*zh`9fr|+Kv|aq@_E;fIlcWn>skA_T(@8#-XP=DG4K|_+XU|ryo=zApXSz% z_znL#_CEA@olP$K@u`PR;m^o%BX8M#vg_IvEIQwwqxgLzyf3c)5kc=HD z_D(Zxndq=-IEdY&$O_=6Rh3;4V^vI5RHiWHFRe64>=2PbQF_~D77*XvcI$3zNsvtw z{ddzGA@ffXoF{mV;4^~%@1}n8r4n`VOLBGL1vWyBAMS)tY5Qe@PY5m{;JB4WzaYlv z1Y-zkjRNUn)Qeup!@ndcwG(`efTNw}0#HccI02bRYwl2QapM$qnv2DlO?Le^$n(h0 zrAXkHJ`Oewha}*jk z{6KUSJq;2K$}b>3!a`8+5wyBCJ*eXE_DdGp?zy~*;I=7wBcYy`OOeY5X=+z5i- zbhy51czA|?d-r_fPOR9Qpfz{iIT%007z7=rf=;Mdr=~(x`w(;@6{$Jg=TxlfxW|fP z#r$OcUd66!)4opn;uv6vDMlv8qDY0z zGM_OXX7UUS*5^XIw#VCZ!a}aBFmO_Wby!yT`0y%~!Uk-axwli=r3E8$0BnkQIvTxs$hvHQQkfBO6csKHE>r{oow8Q4WP{><2Z#rfJ|XCc+O>P|DN zZN9$ngl_vbJ_25K`P%((HN44|!k8_w_sg@Z)b4@nl0W;cdi9B~*C+LER~1S1oj-a& jpOocxZYHJ&1**sMYn(znj%t4aJ0=D9 delta 305 zcmZ1@eoII@k(ZZ?0SK0L6elbZV_Fs3lIFaTwlQ&@mB3rIbXW=&xSslLVOUzS=_o>-Ec zvH3G&8Y3ge<|yWwOp?MN8w7v^11A>~8zb9)78VvJAw~h=%{**LjBE@*y<&cww{xsy zoSev|%vz)bR5^JfmkPH7kWp*^Bp4VcAK+4EWSsnjOM#JXGAp;rWFu}3TXv8<8<5~& z