Skip to content
This repository was archived by the owner on Aug 24, 2024. It is now read-only.

Commit b789e64

Browse files
authored
Merge pull request #9 from ghanteyyy/main
Re-designed UI ...
2 parents 01ab7e5 + f995edf commit b789e64

17 files changed

+220
-343
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__/
-3.49 KB
Binary file not shown.
-1.44 KB
Binary file not shown.
-1.03 KB
Binary file not shown.
-822 Bytes
Binary file not shown.
-5.47 KB
Binary file not shown.
-4.34 KB
Binary file not shown.

data/commands.py

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
'''
44

55

6-
import collections
76
from tkinter import messagebox
87
import matplotlib.pyplot as plt
98

@@ -21,71 +20,65 @@ def default_state(entry_widgets, styles):
2120
entry_widgets[2].set(0)
2221

2322

24-
def add_command(entry_widgets, _vars, styles):
23+
def add_command(entry_widgets, text_widgets, styles):
2524
'''Store item_name, values and explode in respective variables'''
2625

2726
entry_get = entry_widgets[0].get().strip()
2827
values_get = entry_widgets[1].get().strip()
2928
split_value_get = values_get.split('.')
3029
explode_get = entry_widgets[2].get()
3130

32-
pie_items_var, values_var, explode_var = _vars
33-
3431
if entry_get in ['', 'Items']:
3532
messagebox.showerror('Invalid Name', 'Provide valid item name')
3633

37-
elif entry_get in _vars[0]:
34+
elif entry_get in text_widgets[0].get('1.0', 'end-2c').split('\n'):
3835
messagebox.showerror('Exists', f'{entry_get} already exists in the register')
3936

40-
elif not split_value_get[0].isdigit() and not split_value_get[1].isdigit():
37+
elif values_get in ['', 'Values'] or not split_value_get[0].isdigit() or (len(split_value_get) == 2 and not split_value_get[1].isdigit()):
4138
messagebox.showerror('Invalid Values', 'Values was expected in number')
4239

4340
elif explode_get not in [1, 2]:
4441
messagebox.showerror('Invalid Explode', 'You must select Enable or Disable in Explode option')
4542

4643
else:
47-
pie_items_var.append(entry_get)
48-
values_var.append(float(values_get))
44+
default_state(entry_widgets, styles)
45+
insert_to_text_widget(text_widgets, entry_get, values_get, explode_get)
4946

50-
if explode_get == 1:
51-
explode_var.append(0.1)
5247

53-
else:
54-
explode_var.append(0)
48+
def insert_to_text_widget(text_widgets, *values):
49+
'''Inserting data from self.explode, self.pie_items and self.pie_items_values in their own text_widget'''
5550

56-
messagebox.showinfo('Added', 'Values are added')
57-
default_state(entry_widgets, styles)
51+
pie_items = text_widgets[0].get('1.0', 'end-1c') + values[0]
52+
pie_values = text_widgets[1].get('1.0', 'end-1c') + values[1]
53+
pie_explode = text_widgets[2].get('1.0', 'end-1c')
5854

55+
if values[2] == 1:
56+
pie_explode += 'Enabled'
5957

60-
def insert_to_text_widget(text_widgets, _vars):
61-
'''Inserting data from self.explode, self.pie_items and self.pie_items_values in their own text_widget'''
58+
else:
59+
pie_explode += 'Disabled'
6260

6361
for widget in text_widgets:
6462
widget.config(state='normal')
6563
widget.delete('1.0', 'end')
6664

67-
pie_items, pie_values, pie_explode = _vars
68-
pie_explode = ['Enabled' if explode else 'Disabled' for explode in pie_explode]
69-
70-
for index, values in enumerate(zip(pie_items, pie_values, pie_explode)):
71-
item, values, explode = values
72-
73-
text_widgets[0].insert('1.0', f'{item}\n')
74-
text_widgets[1].insert('1.0', f'{values}\n')
75-
text_widgets[2].insert('1.0', f'{explode}\n')
65+
text_widgets[0].insert('1.0', f'{pie_items}\n')
66+
text_widgets[1].insert('1.0', f'{pie_values}\n')
67+
text_widgets[2].insert('1.0', f'{pie_explode}\n')
7668

7769
for widget in text_widgets:
7870
widget.config(state='disabled', cursor='arrow')
7971

8072

81-
def make_chart(_vars):
73+
def make_chart(text_widgets):
8274
'''Make pie-chart as per the user's data'''
8375

84-
items, values, explode = _vars
85-
count = len(set(collections.Counter(items).values())) # Getting count of items and calculating its length
76+
items = text_widgets[0].get('1.0', 'end-2c').split('\n')
77+
values = [float(value) for value in text_widgets[1].get('1.0', 'end-2c').split('\n') if value]
78+
explode = [0.1 if value == 'Enabled' else 0 for value in text_widgets[2].get('1.0', 'end-2c').split('\n')]
8679

87-
if count > 1:
88-
messagebox.showerror('ERROR', 'Some items have same names.')
80+
if len(items) != len(values) != len(explode):
81+
messagebox.showerror('ERROR', 'There is incomplete values either in ITEMS or VALUES or EXPLODE')
8982

9083
elif items:
9184
figure, pie_chart = plt.subplots()
@@ -103,16 +96,13 @@ def make_chart(_vars):
10396
messagebox.showerror('No data', 'No data were inputed to make pie-charts')
10497

10598

106-
def clear(_vars, text_widgets=None, styles=None):
99+
def clear(text_widgets):
107100
'''Clear data from the register'''
108101

109-
if _vars[0]:
110-
if messagebox.askyesno('Clear Register?', 'Do you really want to clear REGISTER?'):
111-
for _var in _vars:
112-
_var.clear()
102+
if messagebox.askyesno('Clear Register?', 'Do you really want to clear REGISTER?'):
103+
for widget in text_widgets:
104+
widget.config(state='normal')
105+
widget.delete('1.0', 'end')
106+
widget.config(state='disabled')
113107

114-
messagebox.showinfo('Cleared', 'All values are cleared from the REGISTER')
115-
default_state(text_widgets, styles)
116-
117-
else:
118-
messagebox.showinfo('Clear Register', "No items added yet. How about adding some items?")
108+
messagebox.showinfo('Cleared', 'All values are cleared from the REGISTER')

data/include.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ def resource_path(relative_path):
1818
base_path = sys._MEIPASS # PyInstaller creates a temporary directory and stores path of that directory in _MEIPASS
1919

2020
except AttributeError:
21-
base_path = os.path.abspath(".")
21+
base_path = os.path.split(os.path.abspath("."))[0]
2222

23-
return os.path.join(base_path, relative_path)
23+
return os.path.join(base_path, 'pics', relative_path)
2424

2525

2626
def initial_position(window, title):
@@ -35,7 +35,7 @@ def initial_position(window, title):
3535
window.geometry(f'{width}x{height}+{screen_width - width // 2}+{screen_height - height // 2}')
3636

3737
window.resizable(0, 0)
38-
window.iconbitmap(resource_path('..\\pics\\icon.ico'))
38+
window.iconbitmap(resource_path('icon.ico'))
3939
window.title(title)
4040

4141
window.deiconify()

data/main.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
'''
2+
The main GUI window.
3+
'''
4+
5+
import tkinter as tk
6+
import tkinter.ttk as ttk
7+
import link
8+
import include
9+
import commands
10+
11+
12+
class UI:
13+
def __init__(self):
14+
self.prev_widget = None
15+
self.master = tk.Tk()
16+
self.left_frame = tk.Frame(self.master, bg='white')
17+
18+
self.image_frame = tk.Frame(self.left_frame, bg='white')
19+
self.image_obj = tk.PhotoImage(file=include.resource_path('PCC_Logo.png'))
20+
self.image_label = tk.Label(self.image_frame, image=self.image_obj, cursor='hand2', bg='white')
21+
self.image_label.bind('<Button-1>', lambda e: link.open_link(self.master))
22+
self.image_label.pack()
23+
self.image_frame.pack()
24+
25+
self.entries_frame = tk.Frame(self.left_frame, bg='white')
26+
self.items_style, self.value_style = ttk.Style(), ttk.Style()
27+
self.items_style.configure('I.TEntry', foreground='grey')
28+
self.value_style.configure('V.TEntry', foreground='grey')
29+
self.item_entry = ttk.Entry(self.entries_frame, justify=tk.CENTER, width=35, style='I.TEntry')
30+
self.value_entry = ttk.Entry(self.entries_frame, justify=tk.CENTER, width=35, style='V.TEntry')
31+
32+
self.radio_button_style = ttk.Style()
33+
self.radio_button_style.configure('R.TRadiobutton', background='white')
34+
self.explode_frame = tk.LabelFrame(self.left_frame, text='Explode', bg='white')
35+
self.radio_button_var = tk.IntVar()
36+
self.explode_radio_button_enable = ttk.Radiobutton(self.explode_frame, text='Enable', variable=self.radio_button_var, value=1, cursor='hand2', style='R.TRadiobutton')
37+
self.explode_radio_button_disable = ttk.Radiobutton(self.explode_frame, text='Disable', variable=self.radio_button_var, value=2, cursor='hand2', style='R.TRadiobutton')
38+
self.explode_radio_button_enable.pack(side=tk.LEFT, ipadx=15, ipady=5)
39+
self.explode_radio_button_disable.pack(side=tk.LEFT)
40+
41+
self.item_entry.pack(ipady=2, pady=3)
42+
self.value_entry.pack(ipady=2, pady=3)
43+
self.entries_frame.pack(pady=3)
44+
self.explode_frame.pack(ipady=2, pady=3)
45+
46+
for widget, text in {self.item_entry: 'Items', self.value_entry: 'Values'}.items():
47+
widget.insert(tk.END, text)
48+
49+
self.styles_list = {self.items_style: 'I.TEntry', self.value_style: 'V.TEntry'}
50+
self.pie_entries = (self.item_entry, self.value_entry, self.radio_button_var)
51+
52+
self.buttons_frame = tk.Frame(self.left_frame, bg='white')
53+
self.add_value_button = tk.Button(self.buttons_frame, text='Add Values', bg='white', activebackground='white', cursor='hand2', relief=tk.GROOVE, command=lambda: commands.add_command(self.pie_entries, self.text_widgets, self.styles_list))
54+
self.clear_button = tk.Button(self.buttons_frame, text='Clear Register', bg='white', activebackground='white', cursor='hand2', relief=tk.GROOVE, command=lambda: commands.clear(self.text_widgets))
55+
self.make_pie_chart_button = tk.Button(self.buttons_frame, text='Make Pie-Chart', bg='white', activebackground='white', cursor='hand2', relief=tk.GROOVE, command=lambda: commands.make_chart(self.text_widgets))
56+
57+
self.add_value_button.pack(ipadx=71, ipady=2, pady=3)
58+
self.clear_button.pack(ipadx=64, ipady=2, pady=3)
59+
self.make_pie_chart_button.pack(ipadx=59, ipady=2, pady=3)
60+
61+
self.buttons_frame.pack()
62+
63+
self.right_frame = tk.Frame(self.master, bg='white')
64+
self.register_frame = tk.Frame(self.right_frame, bg='white')
65+
66+
self.items_ = Widgets(self.register_frame, 'ITEMS', 15)
67+
self.values_ = Widgets(self.register_frame, 'VALUES')
68+
self.explode_ = Widgets(self.register_frame, 'EXPLODE')
69+
70+
self.text_widgets = [self.items_.text_widget, self.values_.text_widget, self.explode_.text_widget]
71+
72+
self.scrollbar = tk.Scrollbar(self.explode_.text_widget_frame, orient="vertical", command=self.multiple_yview)
73+
self.scrollbar.pack(side=tk.LEFT, fill='y')
74+
75+
for widgets in self.text_widgets:
76+
widgets.config(yscrollcommand=self.scrollbar.set)
77+
78+
self.register_frame.pack()
79+
80+
self.var = tk.IntVar()
81+
self.checkbutton_style = ttk.Style()
82+
self.checkbutton_style.configure('CH.TCheckbutton', background='white')
83+
self.button_frame = tk.Frame(self.right_frame, bg='white')
84+
self.enable_editing_button = ttk.Checkbutton(self.button_frame, text='Enable Editing Mode', variable=self.var, cursor='hand2', style='CH.TCheckbutton', command=self.enable_editing_command)
85+
self.enable_editing_button.pack(pady=10)
86+
self.button_frame.pack()
87+
88+
self.master.bind('<Button-1>', self.master_bindings)
89+
self.item_entry.bind('<FocusIn>', self.entry_bindings)
90+
self.value_entry.bind('<FocusIn>', self.entry_bindings)
91+
self.explode_radio_button_enable.bind('<FocusIn>', self.entry_bindings)
92+
self.master.after(0, lambda: include.initial_position(self.master, 'Pie Chart Creator'))
93+
94+
# Showing url when hovered to image and removing it after 250 ms when cursor gets removed from the top of image
95+
self.url_label = tk.Label(self.master, text='http://github.com/NMrocks/Pie-Chart-Creator', fg='green')
96+
self.image_frame.bind('<Enter>', lambda e: self.url_label.place(relx=0, x=10, y=105, rely=0))
97+
self.image_frame.bind('<Leave>', lambda e: self.master.after(250, self.url_label.place_forget()))
98+
99+
self.left_frame.pack(side=tk.LEFT)
100+
self.right_frame.pack(padx=1, side=tk.LEFT)
101+
self.master.config(bg='white')
102+
self.master.mainloop()
103+
104+
def master_bindings(self, event=None):
105+
'''When user clicks anywhere outside of entry boxes and buttons'''
106+
107+
widget = event.widget
108+
widgets = [self.item_entry, self.value_entry]
109+
entries_widgets = {self.item_entry: 'Items', self.value_entry: 'Values'}
110+
entries_styles = {self.item_entry: (self.items_style, 'I.TEntry'), self.value_entry: (self.value_style, 'V.TEntry')}
111+
112+
for wid in entries_widgets:
113+
if not wid.get().strip() and widget != self.prev_widget:
114+
wid.delete(0, tk.END)
115+
wid.insert(tk.END, entries_widgets[wid])
116+
style, style_name = entries_styles[wid]
117+
style.configure(style_name, foreground='grey')
118+
119+
if widget not in widgets:
120+
if isinstance(widget, tk.Text) and widget.cget('state') == 'normal':
121+
return
122+
123+
self.master.focus()
124+
125+
def entry_bindings(self, event=None):
126+
'''When user clicks in or out of the entries widget'''
127+
128+
widget = event.widget
129+
entries_widgets = {self.item_entry: 'Items', self.value_entry: 'Values'}
130+
entries_styles = {self.item_entry: (self.items_style, 'I.TEntry'), self.value_entry: (self.value_style, 'V.TEntry')}
131+
132+
if widget in entries_widgets:
133+
if widget.get().strip() == entries_widgets[widget]:
134+
self.prev_widget = widget
135+
widget.delete(0, tk.END)
136+
style, style_name = entries_styles[widget]
137+
style.configure(style_name, foreground='black')
138+
139+
entries_widgets.pop(widget)
140+
entries_styles.pop(widget)
141+
142+
for wid in entries_widgets:
143+
if not wid.get().strip():
144+
wid.delete(0, tk.END)
145+
wid.insert(tk.END, entries_widgets[wid])
146+
style, style_name = entries_styles[wid]
147+
style.configure(style_name, foreground='grey')
148+
149+
def enable_editing_command(self):
150+
'''When user clicks the enable editing checkbutton'''
151+
152+
if self.var.get() == 1:
153+
for widget in self.text_widgets:
154+
widget.config(state='normal', cursor='xterm')
155+
156+
else:
157+
for widget in self.text_widgets:
158+
widget.config(state='disabled', cursor='arrow')
159+
160+
def multiple_yview(self, *args):
161+
'''Creating commands of y-view for all the TEXT widget'''
162+
163+
for widgets in self.text_widgets:
164+
widgets.yview(*args)
165+
166+
167+
class Widgets:
168+
def __init__(self, frame, value, width=12):
169+
self.frame = tk.Frame(frame, bg='white')
170+
self.label = tk.Label(self.frame, text=value, bg='white')
171+
self.text_widget_frame = tk.Frame(self.frame, bg='white')
172+
173+
if not width:
174+
width = 15
175+
176+
self.text_widget = tk.Text(self.text_widget_frame, width=width, height=19, highlightthickness=1,
177+
highlightbackground="silver", highlightcolor="silver", cursor='arrow', state='disabled')
178+
179+
self.label.pack()
180+
self.text_widget_frame.pack()
181+
self.frame.pack(side=tk.LEFT)
182+
self.text_widget.pack(side=tk.LEFT)
183+
184+
185+
if __name__ == '__main__':
186+
UI()

0 commit comments

Comments
 (0)