├── .gitignore ├── README.md ├── assets ├── calculation-icon-2161110.png ├── calculation-icon-2161110_1280.png ├── calculation-icon-2161110_640.png ├── icon.gif ├── icon.png └── pyCalc_usage.gif └── pyCalc ├── gui.py ├── icons.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *.cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # SageMath parsed files 79 | *.sage.py 80 | 81 | # Environments 82 | .env 83 | .venv 84 | env/ 85 | venv/ 86 | ENV/ 87 | 88 | # Spyder project settings 89 | .spyderproject 90 | .spyproject 91 | 92 | # Rope project settings 93 | .ropeproject 94 | 95 | # mkdocs documentation 96 | /site 97 | 98 | # mypy 99 | .mypy_cache/ 100 | 101 | # Sublime Text Project files 102 | *.sublime-project 103 | *.sublime-workspace 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## pyCalc 2 | 3 | A simple calculator made using `tkinter`. 4 | 5 | ## Features : 6 | 7 | #### Version1.0 8 | 9 | * Cross-platform 10 | * easy to use 11 | * supports common mathematical functions like 12 | 13 | | `+` | `-` | `*` | `/` | 14 | |:-:|---|---|---| 15 | | `exp` | `x!` | `^2` | `%` | 16 | 17 | * Supports `undo` and `AC` 18 | 19 | ## Usage: 20 | 21 | ![Usage](https://raw.githubusercontent.com/prodicus/pyCalc/master/assets/pyCalc_usage.gif) 22 | 23 | ## Executable: 24 | 25 | #### v1.0.0 26 | 27 | You can download the executable for 28 | 29 | * `*nix` based systems and `Mac` users: [Download executable for *nix/Mac](https://github.com/prodicus/pyCalc/releases) 30 | 31 | **OR** 32 | 33 | You can do a `git-clone` of the repository 34 | 35 | ```bash 36 | $ git clone https://github.com/prodicus/pyCalc.git 37 | $ cd pyCalc/src 38 | $ chmod +x main.py 39 | $ ./main.py 40 | ``` 41 | 42 | ## To-do 43 | 44 | * [x] refactoring for adding `classes` 45 | * [ ] adding other mathematical functions (eg: `log`, `ln` et el) 46 | * [ ] increasing the font for the GUI 47 | * [ ] Adding a `.exe` release for windows based systems.(currently has executable for `*nix` based systems) 48 | 49 | ## Contributing 50 | 51 | Feel free to contribute 52 | 53 | 1. Fork it. 54 | 2. Create your feature branch (`git checkout -b my-new-awesome-feature`) 55 | 3. Commit your changes (`git commit -am 'Added feature'`) 56 | 4. Push to the branch (`git push origin my-new-awesome-feature`) 57 | 5. Create new Pull Request 58 | 59 | ## License : 60 | 61 | MIT License [http://prodicus.mit-license.org/](http://prodicus.mit-license.org/) © Tasdik Rahman 62 | 63 | ## Donation 64 | 65 | If you have found my little bits of software being of any use to you, do consider helping me pay my internet bills :) 66 | 67 | 68 | | PayPal | Donate via PayPal! | 69 | |:-------------------------------------------:|:-------------------------------------------------------------:| 70 | | Gratipay | Support via Gratipay | 71 | | Patreon | Support me on Patreon | 72 | | £ (GBP) | Donate via TransferWise! | 73 | | € Euros | Donate via TransferWise! | 74 | | ₹ (INR) | Donate via instamojo | 75 | -------------------------------------------------------------------------------- /assets/calculation-icon-2161110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/calculation-icon-2161110.png -------------------------------------------------------------------------------- /assets/calculation-icon-2161110_1280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/calculation-icon-2161110_1280.png -------------------------------------------------------------------------------- /assets/calculation-icon-2161110_640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/calculation-icon-2161110_640.png -------------------------------------------------------------------------------- /assets/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/icon.gif -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/icon.png -------------------------------------------------------------------------------- /assets/pyCalc_usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tasdikrahman/pyCalc/0fcf329ba3d423c029a0d6e338eace44e3fa28cd/assets/pyCalc_usage.gif -------------------------------------------------------------------------------- /pyCalc/gui.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | try: 4 | import tkinter as tk 5 | from tkinter import ttk 6 | except ImportError: 7 | # Python 2 8 | import Tkinter as tk 9 | import ttk 10 | 11 | import parser 12 | import base64 13 | from icons import icon_string 14 | 15 | 16 | class TkGUI(tk.Tk): 17 | FONT_LARGE = ("Calibri", 12) # selects the font of the text inside buttons 18 | FONT_MED = ("Calibri", 10) 19 | 20 | # Max rows and columns in the GUI 21 | MAX_ROW = 4 22 | MAX_COLUMN = 5 23 | i = 0 24 | NEW_OPERATION = False 25 | 26 | def __init__(self): 27 | try: 28 | super(TkGUI, self).__init__() 29 | except TypeError: 30 | # Python 2 31 | tk.Tk.__init__(self) 32 | 33 | self.title('Calculator') 34 | self.resizable(width=False, height=False) 35 | 36 | # Configure default theme 37 | style = ttk.Style(self) 38 | style.theme_use('clam') 39 | 40 | # Configure icon 41 | icon_data = base64.b64decode(icon_string) 42 | self.icon = tk.PhotoImage(data=icon_data) 43 | self.tk.call('wm', 'iconphoto', self._w, self.icon) 44 | 45 | for row in range(self.MAX_ROW): 46 | self.columnconfigure(row,pad=3) 47 | 48 | for column in range(self.MAX_COLUMN): 49 | self.rowconfigure(column,pad=3) 50 | 51 | self.display = tk.Entry(self, font=("Calibri", 13)) 52 | self.display.grid(row=1, columnspan=6, sticky=tk.W + tk.E) 53 | 54 | self._init_ui() 55 | 56 | def _init_ui(self): 57 | one = tk.Button( 58 | self, text="1", command=lambda: self.get_variables(1), font=self.FONT_LARGE) 59 | one.grid(row=2, column=0) 60 | two = tk.Button( 61 | self, text="2", command=lambda: self.get_variables(2), font=self.FONT_LARGE) 62 | two.grid(row=2, column=1) 63 | three = tk.Button( 64 | self, text="3", command=lambda: self.get_variables(3), font=self.FONT_LARGE) 65 | three.grid(row=2, column=2) 66 | 67 | four = tk.Button( 68 | self, text="4", command=lambda: self.get_variables(4), font=self.FONT_LARGE) 69 | four.grid(row=3, column=0) 70 | five = tk.Button( 71 | self, text="5", command=lambda: self.get_variables(5), font=self.FONT_LARGE) 72 | five.grid(row=3, column=1) 73 | six = tk.Button( 74 | self, text="6", command=lambda: self.get_variables(6), font=self.FONT_LARGE) 75 | six.grid(row=3, column=2) 76 | 77 | seven = tk.Button( 78 | self, text="7", command=lambda: self.get_variables(7), font=self.FONT_LARGE) 79 | seven.grid(row=4, column=0) 80 | eight = tk.Button( 81 | self, text="8", command=lambda: self.get_variables(8), font=self.FONT_LARGE) 82 | eight.grid(row=4, column=1) 83 | nine = tk.Button( 84 | self, text="9", command=lambda: self.get_variables(9), font=self.FONT_LARGE) 85 | nine.grid(row=4, column=2) 86 | 87 | cls = tk.Button(self, text="AC", command=self.clear_all, 88 | font=self.FONT_LARGE, foreground="red") 89 | cls.grid(row=5, column=0) 90 | zero = tk.Button( 91 | self, text="0", command=lambda: self.get_variables(0), font=self.FONT_LARGE) 92 | zero.grid(row=5, column=1) 93 | result = tk.Button(self, text="=", command=self.calculate, 94 | font=self.FONT_LARGE, foreground="red") 95 | result.grid(row=5, column=2) 96 | 97 | plus = tk.Button( 98 | self, text="+", command=lambda: self.get_operation("+"), font=self.FONT_LARGE) 99 | plus.grid(row=2, column=3) 100 | minus = tk.Button( 101 | self, text="-", command=lambda: self.get_operation("-"), font=self.FONT_LARGE) 102 | minus.grid(row=3, column=3) 103 | multiply = tk.Button( 104 | self, text="*", command=lambda: self.get_operation("*"), font=self.FONT_LARGE) 105 | multiply.grid(row=4, column=3) 106 | divide = tk.Button( 107 | self, text="/", command=lambda: self.get_operation("/"), font=self.FONT_LARGE) 108 | divide.grid(row=5, column=3) 109 | 110 | # adding new operations 111 | pi = tk.Button(self, text="pi", command=lambda: self.get_operation( 112 | "*3.14"), font=self.FONT_LARGE) 113 | pi.grid(row=2, column=4) 114 | modulo = tk.Button( 115 | self, text="%", command=lambda: self.get_operation("%"), font=self.FONT_LARGE) 116 | modulo.grid(row=3, column=4) 117 | left_bracket = tk.Button( 118 | self, text="(", command=lambda: self.get_operation("("), font=self.FONT_LARGE) 119 | left_bracket.grid(row=4, column=4) 120 | exp = tk.Button(self, text="exp", 121 | command=lambda: self.get_operation("**"), font=self.FONT_MED) 122 | exp.grid(row=5, column=4) 123 | 124 | # To be added : 125 | # sin, cos, log, ln 126 | undo_button = tk.Button( 127 | self, text="<-", command=self.undo, font=self.FONT_LARGE, foreground="red") 128 | undo_button.grid(row=2, column=5) 129 | fact = tk.Button( 130 | self, text="x!", command=lambda: self.factorial("!"), font=self.FONT_LARGE) 131 | fact.grid(row=3, column=5) 132 | right_bracket = tk.Button( 133 | self, text=")", command=lambda: self.get_operation(")"), font=self.FONT_LARGE) 134 | right_bracket.grid(row=4, column=5) 135 | square = tk.Button( 136 | self, text="^2", command=lambda: self.get_operation("**2"), font=self.FONT_MED) 137 | square.grid(row=5, column=5) 138 | 139 | def factorial(self, operator): 140 | """Calculates the factorial of the number entered.""" 141 | number = int(self.display.get()) 142 | fact = 1 143 | try: 144 | while number > 0: 145 | fact = fact*number 146 | number -= 1 147 | self.clear_all() 148 | self.display.insert(0, fact) 149 | except Exception: 150 | self.clear_all() 151 | self.display.insert(0, "Error") 152 | 153 | def clear_all(self, new_operation=True): 154 | """clears all the content in the Entry widget.""" 155 | self.display.delete(0, tk.END) 156 | self.NEW_OPERATION = new_operation 157 | 158 | def get_variables(self, num): 159 | """Gets the user input for operands and puts it inside the entry widget. 160 | 161 | If a new operation is being carried out, then the display is cleared. 162 | """ 163 | if self.NEW_OPERATION: 164 | self.clear_all(new_operation=False) 165 | self.display.insert(self.i, num) 166 | self.i += 1 167 | 168 | def get_operation(self, operator): 169 | """Gets the operand the user wants to apply on the functions.""" 170 | length = len(operator) 171 | self.display.insert(self.i, operator) 172 | self.i += length 173 | 174 | def undo(self): 175 | """removes the last entered operator/variable from entry widget.""" 176 | whole_string = self.display.get() 177 | if len(whole_string): ## repeats until 178 | ## now just decrement the string by one index 179 | new_string = whole_string[:-1] 180 | self.clear_all(new_operation=False) 181 | self.display.insert(0, new_string) 182 | else: 183 | self.clear_all() 184 | self.display.insert(0, "Error, press AC") 185 | 186 | def calculate(self): 187 | """Evaluates the expression. 188 | 189 | ref : http://stackoverflow.com/questions/594266/equation-parsing-in-python 190 | """ 191 | whole_string = self.display.get() 192 | try: 193 | formulae = parser.expr(whole_string).compile() 194 | result = eval(formulae) 195 | self.clear_all() 196 | self.display.insert(0, result) 197 | except Exception: 198 | self.clear_all() 199 | self.display.insert(0, "Error!") 200 | 201 | def run(self): 202 | """Initiate event loop.""" 203 | self.mainloop() 204 | -------------------------------------------------------------------------------- /pyCalc/icons.py: -------------------------------------------------------------------------------- 1 | # Base64 encoded icon.gif 2 | # utf-8 character set 3 | 4 | icon_string = """R0lGODlhEAAQAMZCADZyyzhzzDp0zDt1zD94zUB5zUB5zkF5zkJ6zkN6zkN7zkN7z0R7zkR7z0R8 5 | z0V8z0d+0Eh+0Eh/0Eh/0Ul/0Ep/0E6D0k+D0lCE0lSH01WI01iK1FmK1VmL1FqL1VuM1WOR12aT 6 | 2GaU2GeU2GiU2GyX2XCb23Sd3HSe3Hae3Haf3Hif3Hyi3Xyj3X2j3n6k3n+l3n+l34Cm3oOn34Oo 7 | 34So4Ims4Z675sTW8MXW8NHf9N3n9uDp9+bt+Onw+vP2/Pf6/fz9/v////////////////////// 8 | //////////////////////////////////////////////////////////////////////////// 9 | //////////////////////////////////////////////////////////////////////////// 10 | /////////////////////////////////////////////////////////////////////////yH+ 11 | EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAH8ALAAAAAAQABAAAAeWgH+Cg4SFgw+IiYqIhA8NB5CR 12 | kIyDDBgxLpmaMRAOhAQvBgqjowUhHQmfLAuQDRUSCCQbqYMELBM2MxcgHweytIK2CyY1EREWBiOz 13 | qg4sKw0yFCUwHgiqETQwHCo5QkI3A58vEYgYIkI4PD/WgwoZKScoJy9APkE7AI0OCfwJDS09dGhg 14 | J2gRIgMBBCx40MjgIkMQCwUCADs=""" -------------------------------------------------------------------------------- /pyCalc/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from gui import TkGUI 4 | 5 | app = TkGUI() 6 | app.run() --------------------------------------------------------------------------------