How do I switch between Kivy screens on different .py files - python

I have currently got 3 python files. 1 which is where all the main initialisation methods happen, one for a sign in page and one for a sign up page. I cannot get the sign up button on the login page to take me to the sign up page however. Please can someone help. I have tried to change the sm.current inside of the login.py file but that did not work either.
Here is the main.py file:
# Fitness App Main Code
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager
from LogInWindow import LogInWindow # importing the class from Login.py
from SignUpWindow import SignUpWindow
class WindowManager(ScreenManager): # creating a class that deals with screen management
pass
sm = WindowManager() # setting a variable to the window manager class
screens = [LogInWindow(name="Login_window"), SignUpWindow(name="Signup_window")] # setting an array of lists
for screen in screens: # going through all of the screens
sm.add_widget(screen) # adding the screen widget to each
sm.current = "Login_window" # setting current window to login
class FitnessApp(App): # the class that runs the app
def build(self):
App.title = "Fitness App" # setting the app title
Window.size = (1080, 720) # setting window size
return sm # running the app by returning the current window
if __name__ == '__main__': # The value of __name__ attribute is set to “__main__” when module is run as main program
FitnessApp = FitnessApp()
FitnessApp.run()
Here is the login.py file
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from database import get_details
def switch_to_signup():
from main import sm
sm.current_screen = "Signup_window"
class LogInWindow(Screen): # creating LogInWindow class
kv = Builder.load_file("LogInWindow.kv") # loading the kivy file which has all the
def __init__(self, **kwargs): # defining an init method
super().__init__(**kwargs) # giving the subclass the same parameter signature as the parent
def validate_user(self): # creating a function to validate the user
username_input_kivy = self.ids.username_field # setting the input to a variable
password_input_kivy = self.ids.password_field # setting the input to a variable
info = self.ids.info # setting the input to a variable
username_input = username_input_kivy.text # getting the text from an input and putting it into a variable
password_input = password_input_kivy.text # getting the text from an input and putting it into a variable
if username_input == '' or password_input == '': # checking if the fields are empty
info.text = '[color=#FF0000]Username And / Or Password Required[/color]' # red error message
else:
user_details = get_details(username_input)
username = user_details[0] # set the username to the 1st value
users_password = user_details[1] # set the password to the 2nd value
if username_input == username and password_input == users_password: # checking if they are correct
info.text = '[color=#00FF00]Logged In successfully!!![/color]' # green success message
else:
info.text = '[color=#FF0000]Invalid Username and/or Password[/color]' # red error message
and here is the relevant kivy button:
Button:
text: "Don't have an account? Sign Up Here!" ## setting the text to the sign up
font_size:20 ## changing font size
size_hint_y: None ## setting size hint to none so it can be set to anything
height: 60 ## setting height to 60
background_color: (0, 0, 0, 1) ## setting background colour
background_normal: '' ## changing the background_normal to nothing
on_release: root.switch_to_signup() ##will change to put it to sign up screen
There is almost nothing in the signup.py file but I will include it incase that helps.
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
class SignUpWindow(Screen): # creating LogInWindow class
kv = Builder.load_file("SignUpWindow.kv") # loading the kivy file which has all the
def __init__(self, **kwargs): # defining an init method
super().__init__(**kwargs) # giving the subclass the same parameter signature as the parent
Any help would be greatly appreciated

In your kv file you can always access the App using the keyword app. See the documentation.
So, in your kv, change the Button to:
Button:
text: "Don't have an account? Sign Up Here!" ## setting the text to the sign up
font_size:20 ## changing font size
size_hint_y: None ## setting size hint to none so it can be set to anything
height: 60 ## setting height to 60
background_color: (0, 0, 0, 1) ## setting background colour
background_normal: '' ## changing the background_normal to nothing
on_release: app.root.current = "Signup_window" ##will change to put it to sign up screen
Of course, this assumes that the name of the SignUpWindow is "Signup_window".

Related

i'm trying to make a password generater gui app using python and kivy but it doesn't work

hi i'm trying to make an app that generates a password when clicking the button "generate" using python (for the logic) and kivy(for the gui) and i think that i did everything right but when i click the genrate button ,the app stops for a bit and then return working but the text content which was originaly empty doesn't change into a random password,the box just remains empty.
so guys plz help me.the python code is here:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.properties import ObjectProperty
import requests
import random
class float_layout(Widget):
passw= ObjectProperty(None)
btn = ObjectProperty(None)
password = StringProperty("")
def change(self,password):
word_site = "https://www.mit.edu/~ecprice/wordlist.10000"
signs = ["__","_","**",":","::",";",";;","&","&&","***","-","--","---","***","&&&"]
sign = random.choice(signs)
response = requests.get(word_site)
WORDS = response.content.splitlines()
number = random.randint(0,len(WORDS))
addition1 = random.randint(0,100000)
word= WORDS[number].decode('utf-8')+sign+str(addition1)
word = StringProperty(word)
return password == word
class GenApp(App):
def build(self):
return float_layout()
if __name__=="__main__":
GenApp().run()
here is the kivy code:
#:kivy 1.0
<float_layout>
passw:passw
btn:btn
FloatLayout:
size: root.width,root.height
TextInput:
id:passw
text:root.password
size_hint:0.5,0.1
pos_hint:{"x":0.25,"top":0.5}
multiline:False
Button:
id:btn
text:"Generate"
size_hint:0.5,0.1
pos_hint:{"x":0.25,"top":0.41}
background_color:0.3, 0.5, 0.7, 1
on_press:root.change(root.password)
Image:
source: r'C:\Users\Med\Desktop\photoshop\password_gen.png'
pos_hint:{"x":0,"top":1.2}
here is an image of the app:
[1]: https://i.stack.imgur.com/Wkh22.png
Just replace:
return password == word
with:
self.password = word
# return password == word
The return password == word will return either True or False depending on whether word is the same as the root.password. And the return value is not used anyway.
The text of the TextInput is already set to use whatever is in root.password, so you can just set that property.
Also, there is no need to pass in the current password value.

Kivy: How to change the attribute's value like text of label from current screen in another screen

I tried to change the text of another screen from current screen. But it didn't work
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
from kivy.lang.builder import Builder
Builder.load_string("""
<Input_Screen>:
input: input
BoxLayout:
orientation : "vertical"
TextInput:
id: input
text: "Changed"
Button:
text: "Enter"
on_press : root.clicked()
<Display_Screen>:
nice: nice
BoxLayout:
orientation : "vertical"
Label:
id: nice
text: "NotChanged"
""")
class Input_Screen(Screen):
input = ObjectProperty(None)
def clicked(self):
Display_Screen().change()
class Display_Screen(Screen):
nice = ObjectProperty(None)
def change(self):
print(self.nice.text) #Checking the Current text of The Label
print(Input_Screen().input.text) #Checking What do we want to change
self.nice.text = Input_Screen().input.text
print(self.nice.text) #Checking if it has change or not
MyApp().sm.current = "Ds" #Changing Screen to Display_Screen
print(self.nice.text) #Checking if it has change or not
class MyApp(App):
sm = ScreenManager()
def build(self):
self.sm.add_widget(Input_Screen(name="Is"))
self.sm.add_widget(Display_Screen(name="Ds"))
return self.sm
MyApp().run()
What I get in My console:
NotChanged #Checked the Current text of The Label
Changed #Checked What do we want to change
Changed #Checked if it has change or not
Changed #Checked if it has change or not
It says that my Label's text has been changed but when it goes to the next screen it hasn't been changed.
Display_Screen
Anyone knows whats the problem? Help me please
Whenever you use a construction like ClassName(), you are creating a new instance of ClassName. You are doing this in your change() method and in your clicked() method. Whenever you do that, you are referencing that new instance, and not the instance that is in your GUI.
To fix that, change:
def clicked(self):
Display_Screen().change()
to:
def clicked(self):
self.manager.get_screen('Ds').change()
and in your change() method, replace:
Input_Screen()
with:
self.manager.get_screen('Is')
and replace"
MyApp()
with:
App.get_running_app()

Kivy - How to change the colour of every text input if a condition is met

I am trying to create some themes in kivy. My program currently has 4 classes/screens. I have manged to be able to change the background colour of all the screens if a condition is met. I have tried to change the colour of all the text input's so intead of white, they are black. This is my code so far
Python:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import *
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
class WeatherRoot(ScreenManager, BoxLayout):
pass
class RegisterPage(Screen, BoxLayout):
pass
class WeatherApp(App):
pass
def iii(time):
print("h")
x = 1
if x == 1:
Window.clearcolor = (1, 1, 1, 0)
TextInput.background_color = (1,1,1,0)
pass
if __name__ == "__main__":
Clock.schedule_once(iii)
WeatherApp().run()
Kivy:
WeatherRoot:
<WeatherRoot>:
RegisterPage:
<RegisterPage>:
BoxLayout:
padding: [100, 50, 100, 50]
TextInput:
font_size: 30
TextInput:
font_size: 30
The code to change the TextInput colour isn't working.
The background is white but the text-input isn't black as you can see
How would I be able to change the colour of the TextInput and properties widgets in general (e.g. the text colour of all labels), if a condition is met, with python code?
Thanks in advance
Note - It doesn't work with foreground_color or any of the colour settings like that.
It seems that the concept of object/instance and classes does not differ. By using TextInput.background_color = (1,1,1,0) you add or modify the "background_color" property of the TextInput class, not of the objects/instances created based on the TextInput class.
If you want to modify the property of the TextInputs (a.k.a instances/objects created based on the TextInput class) you must access those objects using the kivy methods through the parents:
def iii(time):
x = 1
if x == 1:
Window.clearcolor = (1, 1, 1, 0)
root = App.get_running_app().root # WeatherRoot instance
screen = root.screens[0] # RegisterPage instance
box_layout = screen.children[0] # BoxLayout instance
for child in box_layout.children: # childs of box_layout
if isinstance(child, TextInput): # verify that the child is a TextInput
child.background_color = (1,1,1,0)
I think you have extrapolated that in the case of Window it behaves similar to TextInput, but they are not the same since the first one is an instance of the WindowBase class, it is not a class unlike the second.

"AttributeError: 'NoneType' object has no attribute 'bind' " after using FlatButton in kv file

I'm trying to implement FlatButton in my kv but I keep getting the same error that is AttributeError: 'NoneType' object has no attribute 'bind. It works fine with Button alone.
from flat_kivy.flatapp import FlatApp
from kivy.uix.touchripple import TouchRippleBehavior
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import (StringProperty, NumericProperty, ObjectProperty,
ListProperty, DictProperty, BooleanProperty)
class Login(Screen):
pass
class MainScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
theRoot = Builder.load_string('''
ScreenManager:
Login:
<Login>:
FlatButton:
text: 'Click Here'
size_hint: (.4,.25)
''')
class TouchRippleApp(FlatApp):
def build(self):
return theRoot
if __name__ == '__main__':
TouchRippleApp().run()
This is the FlatButton code in Flat_Kivy. I'm stuck at this problem.
class FlatButtonBase(GrabBehavior, LogBehavior, TouchRippleBehavior,
ThemeBehavior):
color = ListProperty([1., 1., 1.])
color_down = ListProperty([.7, .7, .7])
border_size = ListProperty([0, 0, 0, 0])
text = StringProperty('')
alpha = NumericProperty(1.0)
style = StringProperty(None, allownone=True)
color_tuple = ListProperty(['Grey', '500'])
font_color_tuple = ListProperty(['Grey', '1000'])
ripple_color_tuple = ListProperty(['Grey', '1000'])
font_ramp_tuple = ListProperty(None)
font_size = NumericProperty(12)
eat_touch = BooleanProperty(False)
def on_color(self, instance, value):
self.color_down = [x*.7 for x in value]
class FlatButton(FlatButtonBase, ButtonBehavior, AnchorLayout):
pass
class RaisedFlatButton(RaisedStyle, FlatButton):
pass
Perhaps an easier way to do this altogether is create your FlatButton class in the .kv language (inside your string you're loading with Builder.load_string)
Try adding this to your kv string:
<FlatButton#Button>: # create a class "FlatButton" that inherits the kivy Button
background_normal: "" # Get rid of the kivy Button's default background image
background_down: "" # Get rid of the kivy Button's default background image when clicked
# Set the background color to transparent if no action is happening to the button
# If the button is clicked, it will change it to fully white
background_color: (1,1,1,0) if self.state == 'normal' else (1,1,1,1)
and then you can remove all the code relating to your FlatButton class on the python side, with the exception of creating a base class for the kv to work with. E.g. all you need in the python code is
class FlatButton():
pass

Get value from kivy text input in kv during build

I have three questions/problems:
given below configuration of app/app kv file why do I have to call self.build() in ButtonsFactory class. If i remove it, i get black screen, probably because there is no root element in kv file, yet if i tried making MainView root element i end up with black screen as well.
second question, is it possible to set in my someapp.kv file minimum height for custom buttons? They should never be less than X.
last but for me most important why I am unable to get text property of TextInput from kv file, in class function get_list_of_files()? What would be best way to fix this? Global variable which hardcode this value in python code? Moving Builder before python code (embedd kv as string)?
last question...buttons "fill" scrollview_id instead of preserve size and be scrollable inside this view, I'd like them to stop self adjusting size.
someapp.py file
from kivy.app import App
from kivy.factory import Factory
from kivy.properties import ObjectProperty, StringProperty
# views
from kivy.uix.modalview import ModalView
# layouts
from kivy.uix.boxlayout import BoxLayout
import os
# defined in kv file.
class HeaderContainer(BoxLayout): pass
class ButtonsContainer(BoxLayout): pass
class MainView(ModalView): pass
class ButtonsFactory(BoxLayout):
target_location = StringProperty(None)
def __init__(self, *args, **kwargs):
super(ButtonsFactory, self).__init__(*args, **kwargs)
self.build() # Question 1: is that neccessary? (i think not, but black screen without it, why?)
def build(self):
self.orientation = "vertical"
for file_name in self.get_list_of_files():
btn = Factory.CustomButton()
with open(file_name, 'r') as test_file:
btn.file_name = test_file.readline().strip()[1:20]
btn.nice_name = file_name # Question 2: is it possible to set minimum height for kivy button? (havent found in api)
self.add_widget(btn)
# print ("1.!!!!!!", self.target_location) == NONE
#classmethod
def get_list_of_files(cls):
# print "2.!!!!!!", repr(cls.target_location) == <kivy.properties.StringProperty object at 0x7f1dd7596e20>
dir_ = "/tmp" #dir_ = cls.target_location
try:
files = [os.path.join(dir_, name) for name in os.listdir(dir_)
if os.path.isfile(os.path.join(dir_, name))]
except (OSError, IOError):
files = []
return files
class SomeApp(App):
def on_pause(self):
pass
def on_resume(self):
pass
def build(self):
return MainView()
if __name__ == '__main__':
SomeApp().run()
and someapp.kv file
#:kivy 1.8.0
#:import platform platform
<CustomButton#Button>:
file_name: ''
nice_name: ''
text: root.nice_name + "\n" + root.file_name
halign:'center'
size_hint:(1, 0.1)
<HeaderContainer>:
id: header_layout
size_hint:(1, 0.1)
orientation:'horizontal'
# 2-nd-try # target_location: textinput_target_location.text
# I was trying here to pass by ObjectProperty (or StringProperty) but unfortunately failed.
TextInput:
size_hint:(0.7, 1)
id: textinput_target_location
multiline: False
hint_text: "path where stress files are stored, default /sdcard/appdir"
text: "/tmp" if platform.machine() in ["x86_64", "i686", "i386"] else "/sdcard/appdir/" # arm "arm7l", but also other arm's
#on_text: my_callback_to_reload_dir_contents()
Button:
size_hint:(0.2, 1)
id: read_target_location
text: "read target_location directory"
#on_release: my_callback_to_reload_dir_contents()
<ButtonsContainer>:
size_hint:(1, 0.9)
orientation:'vertical'
ScrollView:
id: scrollview_id
orientation: 'vertical'
ButtonsFactory
<MainView>:
BoxLayout:
# 1-st-try # target_location: HeaderContainer.target_location
id: main_layout
padding:10
spacing: 5
orientation:'vertical'
HeaderContainer
# n-th-try # target_location: HeaderContainer.target_location
ButtonsContainer
I'll try to address your questions:
1) Looking at your code, the ButtonsFactory is just a BoxLayout, which is a container for holding other widgets. The self.build function creates CustomButton widgets and puts them in the container. If you don't call self.build, nothing gets added to the container and you have an empty (blank) BoxLayout.
2) This is a little more complicated as the hight is usually controlled by what container is holding your widget. You can manually set height of widgets by setting the size_hint property to None and specifying the height.
3) I would never use global variables if they can be avoided. In this case, if all you need is access to the text content of the TextInput, I would bind it to a StringProperty attached to a widget you can access or the App object itself (which can be accessed anywhere in .kv as app.<property>.
4) Again, the height is controlled by the container the widgets are in (a BoxLayout). You can manually control their size by setting size_hint to None on the widgets.
Another problem is that you are putting a BoxLayout (your ButtonsFactory) inside a ScrollViewer. The BoxLayout will resize itself to fit exactly inside the ScrollViewer so it will not scroll. You will need to override this behavior by clearing size_hint. See this SO question for details.

Categories

Resources