Python kivy, how to use __init__ for classes with screen manager? - python

I want to get instances of the attributes in each class, such as the users password and email, but I also want to be able to get the add_widget to come up with only the name, yet:
Here is my code so far
from kivy.uix import Screen, ScreenManager
class WindowManager(ScreenManager):
pass
sm = WindowManager()
In login window
class LoginWindow(Popups, Screen, FloatLayout, BoxLayout):
def __init__(self, email, password, checkBox, **kwargs):
self.email = email
self.password = password
self.checkBox = checkBox
super(self, **kwargs).__init__()
self.name = "login"
And in main app window
sm.add_widget(LoginWindow(name="login"))
#actual phone app class
class PhoneAssistantApp(App):
def __init__(self):
super(self).__init__()
def build(self):
if LoginWindow.checkBox == True:
sm.current = "main"
else:
sm.current = "login" #user sent to login page whenever program is ran
return sm
if __name__ == "__main__":
PhoneAssistantApp().run()
But it comes up with error:
line 352, in <module>
sm.add_widget(LoginWindow(name="login"))
TypeError: __init__() missing 3 required positional arguments: 'email', 'password', and 'checkBox'
My login window in my kv file is simply:
<LoginWindow>:
name: "login" #name used to know where to send
email: email #links to object property in py file class
password: password #links to object property in py file class
checkBox: checkBox #links to boolean property in py file class
I believe the error is in my main program, as I'm trying to figure out how to fit both the attributes instances in with the kivy.
First I had my sm.add_widget and classes names in the App class, like
class PhoneAssistantApp(App):
def __init__(self, **kwargs):
super(self, **kwargs).__init__()
self.screens = ((LoginWindow(name="login"), CreateAccountWindow(name="Create))
self.sm = ScreenManager()
def build(self):
for screen in self.screens:
self.sm.add_widget(screens)
if LoginWindow.checkBox == True:
self.sm.current = "main"
else:
self.sm.current = "login" #user sent to login page whenever program is ran
return self.sm
if __name__ == "__main__":
PhoneAssistantApp().run()
And
class PhoneAssistantApp(App):
def __init__(self, **kwargs):
super(self, **kwargs).__init__()
self.screens = ((LoginWindow(name="login"), CreateAccountWindow(name="Create))
def build(self):
for screen in self.screens:
sm.add_widget(screens)
if LoginWindow.checkBox == True:
sm.current = "main"
else:
sm.current = "login" #user sent to login page whenever program is ran
return sm
if __name__ == "__main__":
PhoneAssistantApp().run()
Yet taking it away didn't get rid of the problem. In addition, getting rid of the **kwargs likely didn't help much either.
It worked fine until I added the init into the classes.
I'm using visual studio code, where before I added the init hovering over name in above would display 'name=[literal]"login', yet now only displays 'name = "any"'
However, when hovering over name in the login class in my new code, it also returned 'name = [literal]login'.
Rather, I want to be able to use the name without having to indent the other attributes into my sm.add_widget.
While I did try putting the attributes in to see what would work, I tended to put:
sm.add_widget(LoginWindow(name="login", email=LoginWindow.email, password=LoginWindow.password, checkBox=LoginWindow.checkBox))
As I simply wanted the instances of the attributes, but I don't think that's what I should do as it only got me error.
line 352, in <module>
sm.add_widget(LoginWindow(name="login", email=LoginWindow.email, password=LoginWindow.password, checkBox=LoginWindow.checkBox))
AttributeError: type object 'LoginWindow' has no attribute 'email'
Thanks to anyone who'd be able to help out.

When you define a method as you have:
def __init__(self, email, password, checkBox, **kwargs):
all those arguments are required whenever an instance of LoginWindow is created. Your code:
sm.add_widget(LoginWindow(name="login"))
does not provide those required arguments, thus you get that error. You can instead use optional arguments by using keywords. See the documentation.

Related

How to create Test cases in python?

I am wrote application in python and I need to write test for app, I want to create some test, which will use inside my application, how can I do this?
I am new in Python and I want to know some automation test to use.
I have this code in main.py, this is a login function
"loginBtn", which is located in LoginWindow, I want to test this function for my application, how can I do this?
class LoginWindow(Screen):
email = ObjectProperty(None)
password = ObjectProperty(None)
def loginBtn(self):
if db.validate(self.email.text, self.password.text):
ProfileWindow.current = self.email.text
self.reset()
sm.current = "main"
else:
invalidLogin()

Accessing a widget with a specific id from a different class

I am struggling to find a way to access a widget by its id in another class.
Here comes a code example that will make it easy for you to understand.
class LoginScreen(Screen):
def login(self, username, password):
if user_exists(username, password):
self.manager.current = "login_success"
class LoginSuccess(Screen):
pass
.kv
<LoginSuccess>
Label:
id: greeting
text: "" #this should be "Hey, "+username
I have access to username in the login method of the LoginScreen class, but I need to use that variable in the LoginSuccess class.
How can I do that
Still missing a bit of information (the name property of your LoginSuccess Screen). In your login() method try:
self.manager.get_screen("the_name_of_your_LoginSuccess_Screen").ids.greeting.text = "Hey, "+username

Kivy how to use FileBrowser properly inside of a popup

I am looking for a way to create a popup box with a filebrowser inside of it by clicking a button from the main app screen. The below snippet is the class that is called when the upload button is clicked from the main app. It will render the popup with the file browser, but the on_* kwargs do not run the respective methods.
class UploadPopup:
def __init__(self, short_text='heading'):
browser = FileBrowser(select_string='Select', cancel_state='down')
browser.bind(on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled,
on_submit=self._fbrowser_submit)
self.popup = Popup(
title=short_text,
content=browser, size_hint=(0.9, 0.9),
auto_dismiss=False
)
self.popup.open()
def _fbrowser_canceled(self, instance):
print('cancelled, Close self.')
self.popup.dismiss()
def _fbrowser_success(self, instance):
print(instance.selection)
self.popup.dismiss()
def _fbrowser_submit(self, instance):
print(instance.selection)
self.popup.open()
Any ideas??
Where ever you are calling UploadPopup(), you need to save a reference to it, so that it does not get garbage collected. For example, you might want to do self.pop = UploadPopup() in your main app.
Also, in your event handling methods, you probably want to replace self.popup.open() with self.popup.dismiss().
I have already accepted an answer, but would like to expand on that a bit. #john-anderson was correct in that garbage collection was collecting the instantiation. I was originally doing this...
class MainScreen(Screen):
...
#staticmethod
def upload(self):
this = UploadPopup()
...
class UploadPopup():
....
see original post
....
In order to resolve this issue I had to instantiate in the init method of my MainScreen class add an open method to the UpdatePopup class and call that method when the button was clicked.
class MainScreen(Screen):
def __init__(self):
self.upload_popup = UploadPopup()
...
#staticmethod
def upload(self):
self.upload_popup.start()
...
class UploadPopup:
def __init__(self, short_text='heading'):
browser = FileBrowser(select_string='Select', cancel_state='down')
browser.bind(on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled,
on_submit=self._fbrowser_submit)
self.popup = Popup(
title=short_text,
content=browser, size_hint=(0.9, 0.9),
auto_dismiss=False
)
def start(self):
self.popup.open()
....

trouble with scope related variables

Hello fellow programmers, I'm developing a simple interface application in Python that will enable easy and intuitive entry of inventory forms in an access database.
I currently have a function as follows:
def spawnerror(self, errormsg):
self.running = False
content = Button(text=errormsg)
popup = Popup(title='ERROR!', content=content, auto_dismiss=False)
content.bind(on_press=popup.dismiss)
popup.open()
And I have appropriate error handling done, and the application uses this function as intended. For example, if someone doesn't enter in a required field, it calls this function and spawns an error page with an error and informs the user.
My issue that I run into is that, it needs to set the class variable running to False, because at the end of the main function "submit" it checks for that and if self.running == False, then it needs to skip the execution of data entry in the access database.
Why is this function not setting the class variable of running to false?
Solution - using App.get_running_app()
In the example, a class attribute, running is defined as BooleanProperty. In the spawnerror() function, it uses App.get_running_app() function to get an instance of App class and then access variable, running.
Note
If running, spawnerror() function and submit() function are in different classes then work out the relation of the classes and pass a direct reference between them.
Example
main.py
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ObjectProperty
class RootWidget(BoxLayout):
instance = ObjectProperty(None)
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.instance = App.get_running_app()
self.spawnerror('Testing')
def spawnerror(self, errormsg):
self.instance.running = False
content = Button(text=errormsg)
popup = Popup(title='ERROR!', content=content, auto_dismiss=False)
content.bind(on_press=popup.dismiss)
popup.open()
class TestApp(App):
running = BooleanProperty(True)
def build(self):
print("\nbuild:")
self.display_attributes()
return RootWidget()
def on_stop(self):
print("\non_stop:")
self.display_attributes()
def display_attributes(self):
print("\tApp.running =", self.running)
if __name__ == "__main__":
TestApp().run()
Output

Python / Kivy Initial Variable Assignment

I'm relatively new to Python and OOP, and going through the Kivy documentation and found some syntax I was not used to seeing. I am not really sure how to search for the answer since I don't know what to call this type of syntax, so I'll illustrate with the code itself.
Here is the code from the kivy docs:
import kivy
kivy.require('1.0.5')
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty
class Controller(FloatLayout):
'''Create a controller that receives a custom widget from the kv lang file.
Add an action to be called from the kv lang file.
'''
label_wid = ObjectProperty()
info = StringProperty()
def do_action(self):
self.label_wid.text = 'My label after button press'
self.info = 'New info text'
class ControllerApp(App):
def build(self):
return Controller(info='Hello world')
if __name__ == '__main__':
ControllerApp().run()
When the above code runs
return Controller(info='Hello world')
I understand that it is setting a value for Controller().info (or controller_object_instance.info within the kivy.app.build() code), but I don't understand how this string assignment to the variable 'info' works, since I would think you would need an init() function at the top of the class to accept this assignment. Since there is no init() within the Controller() class, why doesn't
Controller(info='Hello world')
throw an error? How does the above line of code know to properly assign the value 'Hello world' to its own attribute 'info'? Is there some init() function inherited from App and this can someone be used or does it have something to do with these two lines of code?
label_wid = ObjectProperty()
info = StringProperty()
Any help appreciated. Just looking for a way to search for this more on my own, and I'm stuck on what topic to search for.
When you created the class Controller, you wanted to inherit the class FloatLayout.
This means, whenever you create a Controller object, you create a FloatLayout which you extended. So the __init__ function from FloatLayout at executes.
Look at this example:
class Animal:
def __init__(self,**kwargs):
self.info = kwargs.get("info")
class Dog(Animal):
pass
obj = Dog(info="Hello world")
print(obj.info)
Now you want to create a Dog, but a dog is also an Animal, so you want to inherit all it's methods and attributes.
So if you pass info as an argument when creating an instance of Dog, it will be passed to Animal's __init__ function.

Categories

Resources