2

I have coded a (very) simple calculator script using tkinter on python 3.3. When I run the script through IDLE, it seems to work fine; however, when I run it by simply double clicking on the .py file, it doesn't work. The cmd window pops up for half a second before disappearing again.

I tried launching it through the command prompt, using "python calculator.py", but that didn't work either. However, typing "python" to bring up the python interpreter within cmd, and then importing calculator worked fine.

Having googled the problem and looking at a few similar stackOverflow questions, I decided that none of them really solve this problem. This isn't the first time, a week or so ago I coded a python security plugin for my USB stick which took passwords and checked them against hashes etc etc, and installed python on the USB stick. That stopped working the other day, and when I opened it with PythonW, nothing happened, and I had to consistently open it with IDLE and launch it from there.

I have enclosed the code for my calculator - I realize that it is inefficient and quite badly coded, but I haven't cleaned it up yet.

from tkinter import *
class calculator:
    def __init__(self):
        self.root = Tk()
        self.menu = Menu(self.root)
        self.menu.add_command(label="Quit", command=self.root.destroy) 
        self.root.config(menu=self.menu)
        self.root.title("Calculator")
        self.display = Entry(self.root)
        self.display.grid(row=1, column=0, columnspan=5)
        self.dot = False
        self.equalsdone = False
        Label(self.root).grid(row=2, column=0)
        Button(self.root, text="1", width=5, foreground="blue", command=lambda: self.addNumber("1")).grid(row=4, column=0)
        Button(self.root, text="2", width=5, foreground="blue", command=lambda: self.addNumber("2")).grid(row=4, column=1)
        Button(self.root, text="3", width=5, foreground="blue", command=lambda: self.addNumber("3")).grid(row=4, column=2)
        Button(self.root, text="4", width=5, foreground="blue", command=lambda: self.addNumber("4")).grid(row=5, column=0)
        Button(self.root, text="5", width=5, foreground="blue", command=lambda: self.addNumber("5")).grid(row=5, column=1)
        Button(self.root, text="6", width=5, foreground="blue", command=lambda: self.addNumber("6")).grid(row=5, column=2)
        Button(self.root, text="7", width=5, foreground="blue", command=lambda: self.addNumber("7")).grid(row=6, column=0)
        Button(self.root, text="8", width=5, foreground="blue", command=lambda: self.addNumber("8")).grid(row=6, column=1)
        Button(self.root, text="9", width=5, foreground="blue", command=lambda: self.addNumber("9")).grid(row=6, column=2)
        Button(self.root, text="0", width=5, foreground="blue", command=lambda: self.addNumber("0")).grid(row=7, column=1)
        Button(self.root, text=".", width=5, command=lambda: self.addNumber(".")).grid(row=7, column=0)
        Button(self.root, text="=", width=12, command=lambda: self.Equals()).grid(row=8, column=2, columnspan=2)
        Button(self.root, text="(", width=5, foreground="red", command=lambda: self.addNumber("(")).grid(row=8, column=0)
        Button(self.root, text=")", width=5, foreground="red", command=lambda: self.addNumber(")")).grid(row=8, column=1)
        Button(self.root, text="X", width=5, foreground="red", command=lambda: self.addNumber("x")).grid(row=4, column=3)
        Button(self.root, text="÷", width=5, foreground="red", command=lambda: self.addNumber("÷")).grid(row=5, column=3)
        Button(self.root, text="-", width=5, foreground="red", command=lambda: self.addNumber("-")).grid(row=6, column=3)
        Button(self.root, text="+", width=5, foreground="red", command=lambda: self.addNumber("+")).grid(row=7, column=3)
        Button(self.root, text="C", width=5, command=lambda:self.clear("all")).grid(row=3, column=3)
        Button(self.root, text="Del.", width=5, command=lambda:self.clear("1")).grid(row=3, column=2)
    def clear(self, amount):
        if amount == "all":
            self.display.delete(0, END)
        elif amount == "1":
            if self.equalsdone == True:
                self.equalsdone = False
                y = self.display.get()
                yAct = y[1:]
                self.display.delete(0, END)
                self.display.insert(0, yAct)
                self.display.delete(len(yAct)-1, END)
            else:
                z = len(self.display.get())
                self.display.delete(z-1, END) 
    def addNumber(self, number):
        if self.equalsdone == True:
            self.equalsdone = False
            if number == "x" or  number == "÷" or  number == "+" or  number == "-":
                y = self.display.get()
                yAct = y[1:]
                self.display.delete(0, END)
                self.display.insert(0, yAct)
                self.display.insert(END, number)
            else:
                self.display.delete(0, END)
                self.display.insert(0, number)
        elif number == ".":
            if self.dot == True:
                pass
            else:
                self.dot = True
                self.display.insert(END, number)
        elif number == "x" or number == "-"or number == "+"or number == "÷":
            self.dot = False
            self.display.insert(END, number)
        else:
            self.display.insert(END, number)     
    def doEquation(self, operator):
        def setwaiting(operator):
            if operator == "x":
                self.waitingx = True
            if operator == "÷":
                self.waitingd = True
            if operator == "+":
                self.waitingp = True
            if operator == "-":
                self.waitingt = True
        if self.waiting == False:
            self.waiting = True
            setwaiting(operator)
        elif self.waitingx == True:
            self.waitingx = False
            setwaiting(operator)
            self.no1f = float(self.no1)
            self.no2f = float(self.no2)
            x = self.no1f*self.no2f
            self.no1 = str(x)
            self.no2 = ""
            print(self.no1)
        elif self.waitingd == True:
            self.waitingd = False
            setwaiting(operator)
            self.no1f = float(self.no1)
            self.no2f = float(self.no2)
            x = self.no1f/self.no2f
            self.no1 = str(x)
            self.no2 = ""
            print(self.no1)
        elif self.waitingt == True:
            self.waitingt = False
            setwaiting(operator)
            self.no1f = float(self.no1)
            self.no2f = float(self.no2)
            x = self.no1f-self.no2f
            self.no1 = str(x)
            self.no2 = ""
            print(self.no1)
        elif self.waitingp == True:
            self.waitingp = False
            setwaiting(operator)
            self.no1f = float(self.no1)
            self.no2f = float(self.no2)
            x = self.no1f+self.no2f
            self.no1 = str(x)
            self.no2 = ""
            print(self.no1)
        else:
            setwaiting(operator)
    def Equals(self):
        self.length = len(self.display.get())
        self.equation = self.display.get()
        self.waiting = False
        self.no1 = ""
        self.no2 = ""
        self.lena = 0
        self.waitingx = False
        self.waitingd = False
        self.waitingt = False
        self.waitingp = False
        for item in self.equation:
            self.lena += 1
            if item == "x":
                self.doEquation(operator="x")
            elif item == "÷":
                self.doEquation(operator="÷")
            elif item == "-":
                self.doEquation(operator="-")
            elif item == "+":
                self.doEquation(operator="+")
            else:
                if self.waiting == False:
                    self.no1 += item
                elif self.waiting == True:
                    self.no2 += item
            if self.lena == self.length:
                self.doEquation(operator=False)
        self.display.delete(0, END)
        self.display.insert(0, "=" + self.no1)
        self.equalsdone = True
calculator()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Cailean Wilkinson
  • 1,420
  • 2
  • 19
  • 32
  • What error did you get using `python calculator.py`? – Aya Apr 20 '13 at 17:06
  • 2
    You must add `self.root.mainloop()` at the end of `__init__` method: http://stackoverflow.com/questions/8683217/tkinter-when-do-i-need-to-call-mainloop – kalgasnik Apr 20 '13 at 17:13

2 Answers2

2

You need to call the mainloop method of the root window. IDLE does this automatically for you (or as a side effect of how it's implemented; I'm not sure which). In your case you would probably want to put this as the last statement in your __init__ method of the calculator class.

mainloop is fundamental to a working Tkinter application. It is what listens to events from the keyboard, mouse and operating system and forwards them to the appropriate callbacks. Without this event loop no events will be processed, and if no events are processed the window can't draw itself on the screen.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
0

IDLE runs file.py in the editor as if the user ran python -i file.py in the console. The -i option keeps the program alive so you can interact with it. So you must either file.py in the console with -i, if you want to interact with it after it runs, or add root.mainloop to keep the program alive.

Terry Jan Reedy
  • 18,414
  • 3
  • 40
  • 52