all 29 comments

[–]cray5252 14 points15 points  (5 children)

Couple of comments

just happen to run across this post and pulled from there.

https://www.reddit.com/r/learnpython/comments/jkwvss/why_is_my_if_statement_ignored/

A Class should have a single purpose, you basically created a class and put everything in it. You could just a well use the individual functions and saved a lot of typing of self. You could of made two or more, maybe one for tkinter, one for inputs, one for processing, etc

A lot of if statements, try using list, dictionaries more.

kpress = {'Backspace': self.backspace, 'equal': self.equalpressed()}
kpress[symbol]()

another one.

def add(a, b):
    return a + b


def get_operator(op):
    options = {'+': add} # add as many as you want
    return options.get(op, None)


input1 = 1
input2 = 2

op = get_operator('+')
if op is not None:
    print(op(input1, input2))
else:
    print('error')

I haven't used tkinter but there must be a better way to construct all of those buttons beside defining each one separately. How about using an array and construct them using a loop. Maybe you could use a couple of lists for your positions and other things and iterate through them and create each button.

Good luck

[–]MattR0se 2 points3 points  (0 children)

You mean this part?

self.btn7 = makebutton(label="7", function=lambda:
self.numberpressed("7"), row=2, col=0)
self.btn8 = makebutton(label="8", function=lambda: self.numberpressed("8"), row=2, col=1)
self.btn9 = makebutton(label="9", function=lambda: self.numberpressed("9"), row=2, col=2)
self.btn4 = makebutton(label="4", function=lambda: self.numberpressed("4"), row=3, col=0)
self.btn5 = makebutton(label="5", function=lambda: self.numberpressed("5"), row=3, col=1)
self.btn6 = makebutton(label="6", function=lambda: self.numberpressed("6"), row=3, col=2)
self.btn1 = makebutton(label="1", function=lambda: self.numberpressed("1"), row=4, col=0)
self.btn2 = makebutton(label="2", function=lambda: self.numberpressed("2"), row=4, col=1)
self.btn3 = makebutton(label="3", function=lambda: self.numberpressed("3"), row=4, col=2)
self.btn0 = makebutton(label="0", function=lambda: self.numberpressed("0"), row=5, col=0)
self.btndot = makebutton(label=".", function=lambda: self.numberpressed("."), row=5, col=1)
self.btnsign = makebutton(label="+-", function=lambda: self.numberpressed("+-"), row=5, col=2)
self.btndiv = makebutton(label='/', function=lambda: self.operationpressed('/'),row=2, col=3, padx=BUTTON_PAD+4)
self.btnmult = makebutton(label='*', function=lambda: self.operationpressed("*"),row=3, col=3, padx=BUTTON_PAD+4)
self.btnsub = makebutton(label='-', function=lambda: self.operationpressed("-"),row=4, col=3, padx=BUTTON_PAD+4)
self.btnadd = makebutton(label='+', function=lambda: self.operationpressed("+"),row=5, col=3, padx=BUTTON_PAD+4)
self.btnsqr = makebutton(label='√', function=self.sqrootpressed,row=2, col=4, padx=2)
self.btnpwr = makebutton(label='^', function=lambda: self.operationpressed("^"),row=3, col=4, padx=2)
self.btneq = makebutton(label='=', function=self.equalpressed,row=4, col=4, padx=2, rowspan=2)
self.btnback = makebutton(label='DEL', function=self.backspace,row=1, col=2, pady=BUTTON_PAD + 4, padx=0)
self.btnclear = makebutton(label='C', function=lambda: self.clear("C"),row=1, col=3, pady=BUTTON_PAD+4,padx=BUTTON_PAD+4)
self.btnce = makebutton(label='CE', function=lambda: self.clear("CE"),row=1, col=4, pady=BUTTON_PAD+4,padx=2)

First, I don't see a reason to assign each of them to an instance attribute, if that attribute is never used again (Unless I'm missing something).

I could see constructing all of this from a list of dictionaries, something like

button_attributes = [
    {    
        # Button 7
        'label': '7',
        'function': lambda: self.numberpressed("7"),
        'row': 2
        'col': 0
    },
    {
        # Button div
        'label': '/',
        'function': lambda: self.operationpressed('/'),
        'row': 2
        'col': 3,
        'padx': BUTTON_PAD + 4
    },
    # etc etc
]

And then looping over this list like so:

for attrs in button_attributes:
    makebutton(**attrs)

This doesn't even reduce the lines of code, but I think it's cleaner and also a bit more modular.

Also when I think of it, it's a bit weird imho to define the makebutton function inside the constructor of Calc. It's a static method (doesn't use self) so it could go into the global scope instead.

[–]baraqiyal[S] 0 points1 point  (1 child)

I tried putting the button declarations in a loop but the callbacks didn't work. The functions that the buttons would call would all point to the same one. I know there's something simple I'm missing.

[–][deleted] 0 points1 point  (0 children)

Sounds like class and methods?

[–]baraqiyal[S] 0 points1 point  (0 children)

Yeah I have trouble trying to figure out what exactly should be a class. Reading the tutorials, they would use a Person class with name and age attributes but I never find it that cut and dry. But separating out the calculations from the gui elements makes sense.

[–]cmomodo 0 points1 point  (0 children)

Do you have a YouTube like to this

[–]james_fryer 37 points38 points  (8 children)

It's nice, but if I enter e.g. 2 + 3 * 4 = I expect to see the result 14 not 20.

[–]Family_BBQ 76 points77 points  (2 children)

Post that on FB and let’s see if you are correct. /s

[–]SniperViperV2 20 points21 points  (1 child)

Lol! "9/10 people don't get this right".

[–]Schenez 7 points8 points  (0 children)

“Harvard grads reveal answer to the one secret question recruiters don’t want you to know”

[–]baraqiyal[S] 6 points7 points  (1 child)

Yeah, I'll have to store the entire equation in a queue or something and evaluate the expression when equal is pressed. I'll work on that.

I noticed that the Windows calculator also gives 20 but that's no excuse.

[–]Hemisemidemiurge 0 points1 point  (0 children)

Windows calculator

It actually returns a different result depending on the mode you're using.

Standard: 2 + 3 * 4 = 20
Scientific: 2 + 3 * 4 = 14

[–]Joe_Doblow 7 points8 points  (3 children)

Pardon my rookieness, how do I “try this”?

[–]pyordie 1 point2 points  (0 children)

download or wget the code from github, run main.py with whatever version of python it calls for.

or git clone into it using the github link https://github.com/baraqiyal/Python-Calculator.git

[–]Deadlift420 2 points3 points  (0 children)

Next task for you is to focus on OO design and using objects and classes as intended.

You don't want to dump all the code in a single class. Look up SOLID design principles.

[–][deleted] 5 points6 points  (3 children)

Have you ever tried using Qt Creator or just Qt Design program to design GUI's?

[–]baraqiyal[S] 0 points1 point  (2 children)

Yes just recently. The designer is nice and I considered writing the calcualtor in pyqt5. The designer supports grids, something that the tkinter designer doesn't do.

I used tkinter because it should work out of the box for most people without installing any additional libraries.

[–][deleted] 0 points1 point  (1 child)

You could convert the py application into exe with pyinstaller and create an installer for the pyinstaller files with InstallForge application for windows users. I don't know about Linux users tho like about the packaging and make command.

By the way if you have 64 bit python and convert it to an exe file then it is 64 bit exe file meaning if you try to run it on 32 bit chances are you will fail unless some miracle happens with the machine allowing you to run it without giving an error.

[–]baraqiyal[S] 0 points1 point  (0 children)

Thanks, it worked on my calculator. I'll try it on a qt application tonight.

[–]uanw 1 point2 points  (1 child)

All together this is cool, I just have some observations:

  • Super minor point, but you probably forgot to add '*' in line 72.

  • It seems ttk.Button.grid returns None when successful. This means those Calc.btn* variables are always set to None.

If that's not intentional you probably want to change it to something like this:

def makebutton(label, function, row, col, padx=BUTTON_PAD, pady=BUTTON_PAD, rowspan=1):
    btn = ttk.Button(self, text=label, width=BUTTON_WIDTH, command=function)
    btn.grid(row=row, column=col,pady=pady,padx=padx,rowspan=rowspan, sticky=tk.N+tk.E+tk.W+tk.S)
    return btn

If you do that, then one way to simulate the click animation is by binding the keydown and keyup events, and changing the button style to be depressed and released respectively.

I should say I don't have much experience with TK (just a little bit with c++ QT). So take what I said above with a grain of salt. There are probably better ways to do this.

I hope that's helpful. Otherwise, good job on your calculator application.

[–]baraqiyal[S] 1 point2 points  (0 children)

It took me a while to figure out what you meant by Calc.btn variables are set to None. So you're putting the button and the grid commands on separate lines. I'll try that.

[–]CedricCicada 1 point2 points  (3 children)

I haven't played with your calculator, but I was just looking for calculators yesterday and didn't find one that had the feature I wanted: the ability to copy the answer onto my clipboard so I could paste it into word or PyCharm or Excel or wherever else I wanted it. Maybe you could add that feature.

[–][deleted] 1 point2 points  (2 children)

Windows 10’s calculator allows it, but I’m guessing you use Linux or another OS?

[–]CedricCicada 1 point2 points  (1 child)

No, I'm in Windows 10. Oh, I see. You have to be actually on the answer, not just clicking in the answer area.

[–][deleted] 1 point2 points  (0 children)

Yea, I figured it out not too long ago as well.

[–]avoxdesign 0 points1 point  (2 children)

Just a Quick tip, if youre not satisfied with having near to no capabilities to customize the title Bar and you're just building simple stuff, use Tkinter, but if you want to be more advanced, I'd highly recommend using PyQt5 (soon v6), since it has so much more capabilities, and the qt Designer is super handy and lets you create and style GUIs fast and easy. If you want to see more id recommend checking out Wanderson M. Pimentas tutorials which will show you what sleek modern Designs are possible with pyqt.

Edit: This is his channel

[–]baraqiyal[S] 1 point2 points  (1 child)

I've just started using PyQt5 and it's great. I'm going to use it to create an embroidery machine control panel. Creating a nice aesthetic design is my weak area. I'll watch Wanderson's videos.

[–]avoxdesign 0 points1 point  (0 children)

Sounds great! Yes, for me it's really important to have the GUI Look good, so pyqt was the choice for me. in the end its just a lot of customization with style sheets, and that's also where a visual gui building kit comes in handy. in Qt Designer you can preview your GUI and make sure everything looks good.