2

I'm facing the following problem - Whenever I try to make an event listener to any of my buttons I get the following error:

    self.button_compute.Bind(wx.EVT_BUTTON, self.on_click)
    AttributeError: 'BMICalculator' object has no attribute 'button_compute'

I tried the suggested solution in this thread: AttributeError: 'module' object has no attribute 'PyScrolledWindow' in wxPython ,but it didn't work for me.

The program is for calculating the BMI and here's the code:

import wx

class BMICalculator(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, "BMI calculator", (600, 800))
        panel = wx.Panel(self)
        self.Centre()
        #Creating the buttons and text fields
        static_text_height = wx.StaticText(panel, -1, "Height", (170, 10))
        height = wx.SpinCtrl(panel, -1, pos=(164, 40), size=(60, -1))
        static_text_weight = wx.StaticText(panel, -1, "Weight", (170, 100))
        weight = wx.SpinCtrl(panel, -1, pos=(164, 130), size=(60, -1))

        button_compute = wx.Button(panel, label="Compute", pos=(110, 180), size=(60, -1))
        button_cancel = wx.Button(panel, label="Cancel", pos=(210, 180), size=(60, -1))

        result_text = wx.StaticText(panel, -1, "Enter your height and weight and press compute", (68, 220))
        #Adding the events for the buttons (Where I get the error)
        self.button_compute.Bind(wx.EVT_BUTTON, self.on_click)

        self.button_cancel.Bind(wx.EVT_CLOSE, self.click_close)

    def compute_BMI(height, weight):
        #BMI = x KG / (y M *  y M)
        height_m = height/100
        BMI = weight/(height_m *  height_m)
        return BMI

    def click_close(self, event):
        self.Close(True)

    def on_click(self, event):
        result_text.SetValue(compute_BMI(height.GetValue(), weight.GetValue()))

def main():
    app = wx.App()
    frame = BMICalculator(None, -1)
    frame.Show()
    app.MainLoop()
    enter code here

if __name__ == '__main__':
    main()

Any help will be appreciated!

1
  • It looks like most of your errors could be cleared up with a better understanding of class attributes vs instance attributes. Here's a quick tutorial I found on the subject. (lots of missing "self.") Commented Apr 11, 2017 at 19:20

1 Answer 1

2

When you create button_compute you leave it as a local variable to the function. When you try to bind the event, you then try to read from an instance attribute that you haven't created yet. You actually do this in many cases, but your script is erring out on the first one. Add self.xxx to your assignments to make instance attributes rather than local variables to the function.

import wx

class BMICalculator(wx.Frame):
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id, "BMI calculator", (600, 800))
        self.panel = wx.Panel(self)
        self.Centre()
        #Creating the buttons and text fields
        self.static_text_height = wx.StaticText(self.panel, -1, "Height", (170, 10))
        self.height = wx.SpinCtrl(self.panel, -1, pos=(164, 40), size=(60, -1))
        self.static_text_weight = wx.StaticText(self.panel, -1, "Weight", (170, 100))
        self.weight = wx.SpinCtrl(self.panel, -1, pos=(164, 130), size=(60, -1))

        self.button_compute = wx.Button(self.panel, label="Compute", pos=(110, 180), size=(60, -1))
        self.button_cancel = wx.Button(self.panel, label="Cancel", pos=(210, 180), size=(60, -1))

        self.result_text = wx.StaticText(self.panel, -1, "Enter your height and weight and press compute", (68, 220))
        #Adding the events for the buttons (Where I get the error)
        self.button_compute.Bind(wx.EVT_BUTTON, self.on_click)

        self.button_cancel.Bind(wx.EVT_CLOSE, self.click_close)

    def compute_BMI(height, weight):
        #BMI = x KG / (y M *  y M)
        height_m = height/100
        BMI = weight/(height_m *  height_m)
        return BMI

    def click_close(self, event):
        self.Close(True)

    def on_click(self, event):
        self.result_text.SetValue(self.compute_BMI(self.height.GetValue(), self.weight.GetValue()))

def main():
    app = wx.App()
    frame = BMICalculator(None, -1)
    frame.Show()
    app.MainLoop()
    #enter code here

if __name__ == '__main__':
    main()
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for replying. I tried your solution, but I keep getting the same error :/
The program works when I comment out the two buttons
@SamuelLJackson that's because you then skip everywhere that you use these values, but the idea is you want to use them right?
@SamuelLJackson I would strongly suggest doing some reading on class vs instance attributes and python namespace organization. I have edited everywhere I think needs the instance attribute, but I cannot test because I have Qt not wx
If you create as a local variable, the widget will be created as normal but later on you will have no reference to access it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.