5

I am trying to bind the popup.dismiss() function to a button inside a BoxLayout in the Kivy popup.

I keep getting an error saying:

None Type' object has no attribute 'bind'.

I have been looking for an answer for 2 days and cant seem to find what i am looking for. Any help would be appreciated.

Also if you have any tips for my code would be appreciated as i am a novice and i'm sure there are plenty of mistakes.

I haven't added the .kv code as i don't think it is applicable to the issue i have at the moment.

Code Snippet:

import kivy
kivy.require('1.9.1')

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from KivyCalendar import CalendarWidget
from KivyCalendar import DatePicker
from kivy.properties import ObjectProperty, OptionProperty
from kivy.uix.listview import ListItemButton
from kivy.uix.modalview import ModalView
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput

import sqlite3
import datetime


class LogSheet(TabbedPanel):

    def __init__(self, **kwargs):
        super(LogSheet, self).__init__(**kwargs)
        #self.register_event_type('popup_1')
        sq = sqlite3
        wd = Widget
        md = ModalView
        lb = Label
        op = OptionProperty
        bt = Button


    def popup_1(self):
            box = BoxLayout(orientation = 'vertical', padding = (10))
            box.add_widget(Label(text = "Are you sure you want to save data? \n Once saved cannot re-edit!!!!"))
            btn1 = box.add_widget(Button(text = "YES TO SAVE"))
            btn2 = box.add_widget(Button(text = "NO TO GO BACK"))

            btn1.bind(on_press = popup.dismiss)
            btn2.bind(on_press = hypochlorinator_1)

            popup = Popup(title='Check if Correct', title_size= (30), 
                          title_align = 'center', content = box,
                          size_hint=(None, None), size=(400, 400), auto_dismiss = True)
            popup.open() 

    def hypochlorinator_1(self):

        dd1 = self.date_data.text
        vd1 = self.volt_data.text
        ad1 = self.amp_data.text
        ld1 = self.load_data.text

        conn = sqlite3.connect('logsheet.db')
        c = conn.cursor()

        def create_table():
            c.execute('''CREATE TABLE IF NOT EXISTS logSheets(id INTEGER 
PRIMARY KEY,
            date DATETIME, volts REAL, amps REAL, setpoint REAL)''')


        def data_entry():

            c.execute('''INSERT INTO logSheets (date, volts, amps, setpoint) 
            VALUES (?, ?, ?, ?)''', (dd1, vd1, ad1, ld1))

            conn.commit()

        create_table()
        data_entry()
        c.close()
        conn.close()


class LogSheetApp(App):

    def build(self):
        return LogSheet()

lsApp = LogSheetApp()
lsApp.run()

Error message:

File "C:\Users\Kids\Documents\Visual Studio 2015\Projects\KivyTuts2\logsheet.kv", line 294, in <module>
  on_press: root.popup_1()
File "C:\Users\Kids\Documents\Visual Studio 2015\Projects\KivyTuts2\logsheet.py", line 87, in popup_1
  btn1.bind(popup.dismiss)
AttributeError: 'NoneType' object has no attribute 'bind'
FJSevilla
  • 3,733
  • 1
  • 13
  • 20
Aiden
  • 133
  • 2
  • 15

1 Answers1

5

You have:

btn1 = box.add_widget(Button(text = "YES TO SAVE"))
btn2 = box.add_widget(Button(text = "NO TO GO BACK"))

btn1 and btn2 are the return of add_widget method, that is, they are None. You must instantiate the button first and then use add_widget method:

btn1 = Button(text = "YES TO SAVE")
btn2 = Button(text = "NO TO GO BACK")
box.add_widget(btn1)
box.add_widget(btn2)

Now, btn1 and btn2 are instances of Button, and they have bind method.

You can also pass on_press argument to the constructor:

box.add_widget(Button(text = "YES TO SAVE",  on_press=popup.dismiss))
box.add_widget(Button(text = "NO TO GO BACK",  on_press=self.hypochlorinator_1))

Your fuction should be:

def popup_1(self):
    box = BoxLayout(orientation = 'vertical', padding = (10))
    box.add_widget(Label(text = "Are you sure you want to save data? \n Once saved cannot re-edit!!!!"))
    btn1 = Button(text = "YES TO SAVE")
    btn2 = Button(text = "NO TO GO BACK")
    box.add_widget(btn1)
    box.add_widget(btn2)

    popup = Popup(title='Check if Correct', title_size= (30), 
                  title_align = 'center', content = box,
                  size_hint=(None, None), size=(400, 400),
                  auto_dismiss = True)

    btn1.bind(on_press = popup.dismiss)
    btn2.bind(on_press = self.hypochlorinator_1)
    popup.open()

or:

def popup_1(self):
    box = BoxLayout(orientation = 'vertical', padding = (10))
    box.add_widget(Label(text = "Are you sure you want to save data? \n Once saved cannot re-edit!!!!"))
    popup = Popup(title='Check if Correct', title_size= (30), 
                  title_align = 'center', content = box,
                  size_hint=(None, None), size=(400, 400),
                  auto_dismiss = True)
    box.add_widget(Button(text = "YES TO SAVE",  on_press=popup.dismiss))
    box.add_widget(Button(text = "NO TO GO BACK",  on_press=self.hypochlorinator_1))
    popup.open()

Output:

enter image description here

Edit: hypochlorinator_1 should receive an extra argument:

def hypochlorinator_1(self, instance):
FJSevilla
  • 3,733
  • 1
  • 13
  • 20
  • Thank you very much for this. Was exactly what i was looking for. – Aiden Jun 24 '17 at 04:22
  • Yes, needed the instance added. I am still trying to get my head around how that works. Where does this instance come from and why is it needed? – Aiden Jun 24 '17 at 04:26
  • @Aiden `bind` method passes the object that makes the call. In this case, it is the `btn2` object . This is very useful if you have a callback that is used by several widgets. Thanks to this, you can identify who invoked the fuction. https://kivy.org/docs/api-kivy.event.html#kivy.event.EventDispatcher.bind – FJSevilla Jun 24 '17 at 04:38
  • Thanks for the explanation. Much appreciated. – Aiden Jun 25 '17 at 10:57