0

I'm still new to kivy and still relatively new to Python. I have main. py. I plan to have WindowGUI take a number of inputs from main.py and display them in its textbox. Here is what I have:

from os import curdir
from posixpath import dirname
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout  # one of many layout structures
from kivy.uix.textinput import TextInput  # allow for ...text input.
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.spinner import Spinner
from kivy.uix.dropdown import DropDown
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import ObjectProperty
kivy.require('2.0.0')

class MainGUI(Screen):
    encoder = ObjectProperty()
    mileage = ObjectProperty()
    voltage = ObjectProperty()
    power = ObjectProperty()
    camera = ObjectProperty()
    engaged = ObjectProperty()
    idle = ObjectProperty()
    log = ObjectProperty()
    clear = ObjectProperty()
    status = ObjectProperty(None)

    def __init__(self, saySomething): 
        super().__init__() #Go up to __init__ of App
        self.saySomething = saySomething
    
    def power_option(self):
        self.power.text = "Power"
    
    def print_status(self):
        self.ids.Status_screen.text = self.saySomething
        return self.ids.Status_screen.text

class CameraGUI(Screen):
    def __init__(self, **kwargs): #kwargs is just a variable. it could be "banana" or "apple"
        super().__init__() #Go up to __init__ of App

class GUIManager(ScreenManager):
    pass

kv = Builder.load_file('newWindow.kv')

class WindowGUI(App):
    def __init__(self):
        super().__init__()
        # self.say = say
        print("TRY ME!!!!")
        
    
    def build(self):
        self.title = 'IamHero'
        return kv
    
if __name__ == '__main__':
   myWindowGUI = WindowGUI()
   myMainGUI = MainGUI('I am hero!')
   myWindowGUI.run()

###########################_newWindow.kv_#############################

GUIManager:
    MainGUI:
    CameraGUI:

<MainGUI>:
    name: "main"

    status: Status_screen
    GridLayout:
        cols: 2
        size: root.width, root.height #covers entire window
        padding: 15
        
        GridLayout:
            cols:1
            spacing: 10
            GridLayout:
                cols:2
                size_hint: .25,.1  
                Label:
                    id: Engaged
                    text: "Engaged"   
                Label:
                    id: Idle
                    text: "Idle"
            TextInput:
                # size_hint: 1
                id: Status_screen
                multiline: True
                readonly: True
                background_color: .6, .7, 0, 1
                text: root.print_status()
                #on_text: root.print_status()
               
            GridLayout:
                cols:2
                size_hint: .25,.1  
                Button:
                    id: Log
                    text: "Log status"
                    # size_hint_x: .5
                Button:
                    id: Clear
                    text: "Clear"

However, I got the following error:

 Traceback (most recent call last):
   File "c:/Users/Jojo/#RaspberryPi4/Test/WindowGUI.py", line 57, in <module>
     kv = Builder.load_file('newWindow.kv')
   File "C:\Users\Jojo\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 306, in load_file
     return self.load_string(data, **kwargs)
   File "C:\Users\Jojo\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 408, in load_string
     self._apply_rule(
   File "C:\Users\Jojo\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 659, in _apply_rule
     child = cls(__no_builder=True)
 TypeError: __init__() got an unexpected keyword argument '__no_builder'

Any ideas about what I did wrong?

zaraku27
  • 15
  • 6

1 Answers1

0

You cannot require a positional argument in the __init__() of a class that you intend to use in kv. Your __init__() for MainGUI:

def __init__(self, saySomething):

requires an argument for saySomething. An easy way around that is to just make saySomething into a StringProperty of MainGUI. Then you don't even need to implement an __init__():

class MainGUI(Screen):
    encoder = ObjectProperty()
    mileage = ObjectProperty()
    voltage = ObjectProperty()
    power = ObjectProperty()
    camera = ObjectProperty()
    engaged = ObjectProperty()
    idle = ObjectProperty()
    log = ObjectProperty()
    clear = ObjectProperty()
    status = ObjectProperty(None)
    saySomething = StringProperty('Hi')

    # def __init__(self, saySomething):
    #     super().__init__() #Go up to __init__ of App
    #     self.saySomething = saySomething

Then you can set the value of saySomething just like any other property in the kv:

<MainGUI>:
    name: "main"

    status: Status_screen
    saySomething: 'I am hero!'

or in python you can do:

MainGUI(saySomething='I am hero!')

Also, the line:

myMainGUI = MainGUI('I am hero!')

(which will no longer work) is creating an instance of MainGUI that is unused. So that line of code can be deleted.

John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • I have my main.py which will pass variables to `MainGUI`. Your solution doesn't seem to allow me to achieve that...or am I missing something here? I still need to create an instance of the class if I want to pass anything to it right? – zaraku27 Jun 02 '21 at 02:32
  • The `Builder.load_file('newWindow.kv')` creates the instance of `MainGUI` that you see in your `App`. If you create another instance of `MainGUI`, it will not have any association with the instance that appears in your GUI. So, you need to get a reference to the already existing instance, something like: `mainGUI = self.root.get_screen('main')` (if run in an `App` method). Then you can do `mainGUI.saySomething = 'Abba Dabba Doo'`. – John Anderson Jun 02 '21 at 02:41
  • Ok. So I put `MainGUI = self.root.get_screen('main')` and `MainGUI.saySomething = 'Abba Dabba Doo'` in `def __init__(self):` of `class WindowGUI(App)` and have `saySomething = StringProperty()` in `MainGUI`. What do I do then to `def print_status(self):`? I have `text: root.print_status()` in the kv file – zaraku27 Jun 02 '21 at 03:24
  • You can eliminate the `print_status()` method and put `text: root.saySomething` in the `kv`. Also, setting `MainGUI = anything` is a bad idea because `MainGUI` is a class. Keep your class names and variable names separate. – John Anderson Jun 02 '21 at 13:17
  • Cool. I corrected `MainGUI` to `mainGUI` in the `def __init__(self):` of class `WindowGUI(App)`. Now I got this error: `AttributeError: 'NoneType' object has no attribute 'get_screen'` referring to `mainGUI = self.root.get_screen('main')` – zaraku27 Jun 02 '21 at 18:00
  • Are you putting that code in a method of the `WindowGUI` `App`? – John Anderson Jun 02 '21 at 18:17
  • Yes. Where should I move them to? – zaraku27 Jun 02 '21 at 21:15
  • It should be in a method of the `WindowGUI` `App`, but not in `__init__()` or `build()` methods, because the `root` is not yet set in those methods. If you want to put it in the `build()` method, then use `mainGUI = kv.get_screen('main')`. But if you are trying to do that in `__init__()` or `build()` just set set `saySomething` in the `newWindow.kv` as shown in my answer. – John Anderson Jun 02 '21 at 23:17