Im trying to save data from one page of my app into a .json file. There are 2 checkboxes and one text input area. I only wish to save one or the other as not all of them need to be saved. Just the selected one.
Ive tried reading the kivy docs, and ive tried various examples from here and on the web, and i still cannot save my data as intended into a json file.
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.properties import ListProperty, ObjectProperty
from kivy.uix.checkbox import CheckBox
from kivy.uix.button import Button
from kivy.storage.jsonstore import JsonStore
from kivy.clock import Clock
class MyScreenManager(ScreenManager):
pass
class FirstScreen(Screen):
pass
class Who(Screen):
def __init__(self, **kwargs):
super(Who, self).__init__(**kwargs)
self.store = JsonStore("who.json")
Clock.schedule_once(lambda *args: self.load())
def save(self):
self.store.put('who',
mum = self.mum.checkbox,
dad = self.dad.checkbox,
other = self.other.text)
def load(self):
if self.store.exists('who'):
who = self.store.get('who')
w = [("mum", self.mum), ("dad", self.dad), ("other", self.other)]
for key, ti in v:
val = who.get(key)
if val:
ti.text = val
root_widget = Builder.load_file("test.kv")
runTouchApp(root_widget)
and my kv doc looks like this:
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import StringProperty kivy.properties.StringProperty
#:import ObjectProperty kivy.properties.ObjectProperty
#:import Label kivy.uix.label.Label
#:import Window kivy.core.window.Window
#:import ListProperty kivy.properties.ListProperty
#:import CheckBox kivy.uix.checkbox.CheckBox
#:import TextInput kivy.uix.textinput.TextInput
#:import Button kivy.uix.button.Button
#:import BoxLayout kivy.uix.boxlayout.BoxLayout
#:import GridLayout kivy.uix.gridlayout.GridLayout
#:import CheckBox kivy.uix.checkbox.CheckBox
MyScreenManager:
transition: FadeTransition()
Who:
FirstScreen:
<Who>:
name: 'who'
mum: mum
dad: dad
other: other
GridLayout:
cols: 2
row_force_default: True
row_default_height: '50dp'
Label:
text: 'Mum'
font_size: 30
CheckBox:
id: mum
on_press: root.save(mum.active, mum.text)
Label:
text: 'Dad'
font_size: 30
CheckBox:
id: dad
on_press: root.save(dad.active, dad.text)
Label:
text: 'Someone Else'
font_size: 30
TextInput:
id: other
multiline: False
font_size: 30
Button:
text: 'Book'
font_size: 30
valign: 'middle'
on_press: root.save()
Button:
text: 'Cancel'
font_size: 30
valign: 'middle'
on_press: root.manager.current = 'first'
<FirstScreen>:
name: 'first'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Go Back'
font_size: 40
BoxLayout:
Button:
text: 'Back To Who'
font_size: 40
on_press: root.manager.current = 'who'
The outcome usually revolves around this:
File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.getattr
AttributeError: 'CheckBox' object has no attribute 'text'
Expected outcome is obviously saved json data. I need to be able to select one or the other or even all at once. I have tried all I can find. My cat is scared of me. I need help. Thank you.
Related
I am trying to write in a text file after getting an input through TextInput in kivy. The problem is the data gets saved only after i close the app but i want the data to get saved as soon as I leave the specific screen and go to another screen. I am trying to input in add_staff and get it saved in the app through save() function.
import kivymd
import kivy
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
Builder.load_string('''
<MenuScreen>:
nm:nm_input
BoxLayout:
TextInput:
id:nm_input
Button:
text: 'Add New Staff'
on_press: root.manager.current = 'add_staff'
Button:
text: 'View Staff Profile'
Button:
text: 'Salary report'
<Add_new_staff>:
nam: str(name_input)
job: job_input
GridLayout:
cols: 2
Label:
text: 'Name'
TextInput:
id: name_input
multiline: False
Label:
text: 'Job'
TextInput:
id: job_input
Label:
text: 'Salary'
TextInput:
Label:
text: 'Date of Joining'
TextInput:
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Button:
text: 'Save'
on_press: root.save(name_input.text, job_input.text);root.manager.current = 'menu'
''')
class MenuScreen(Screen):
pass
class Add_new_staff(Screen):
def save(self, name, job):
fob = open('testi.txt','a')
fob.write(name + "\n")
fob.write(job)
fob.close()
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(Add_new_staff(name='add_staff'))
return sm
def lo(self,nm):
f=open('log.txt','a')
f.write(nm)
f.close()
if __name__ == '__main__':
TestApp().run()
Here is my kivyfile.kv
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
AnchorLayout:
anchor_x: "left"
anchor_y: "top"
BoxLayout:
cols:2
orientation: 'vertical'
size_hint: None, None
size: self.minimum_size
Button:
text: "Button 1"
size_hint: (None,None)
width:200
height:30
Button:
text: "Button2"
size_hint: (None,None)
width:200
height:30
TextInput:
id: url
multiline: False
size_hint: (None,None)
width:200
height:30
TextInput:
id: url2
multiline: False
size_hint: (None,None)
width:200
height:30
Here is my .py file:
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv=Builder.load_file('kivyfile.kv')
class Downloader(App):
def build(self):
return kv
if __name__ == '__main__':
Downloader().run()
What I am trying to achive, is to get a BoxLayout at the top left corner, which has two columns - Button and TextInput NEXT TO it. However, it only does all components one under each other. I have also a future question on how to add another BoxLayout NEXT TO the previous BoxLayout that I have. As in - how to make it be on the right side of existing BoxLayout, how to position it.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.button import Button
Window.size = (500,700)
Builder.load_file('calc.kv')
class MyLayout(Widget):
pass
class App(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
App().run()
this is my calc.py please help me to solve the problem
#:kivy 2.0.0
BoxLayout:
orientation:"vertical"
size: root.width, root.height
TextInput:
id: clac_input
text: "0"
halign: "right"
font_size : 65
size_hint: (1, .15)
GridLayout:
cols:4
rows:5
Button:
size_hint: (.2, .2)
font_size: 32
text: "%"
this is my calc.kv
From what I'm seeing the app is not returning any screens for your widgets to show on. I've changed a bit of your code to what I believe is correct that solves the issue.
.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
from kivy.uix.button import Button
Window.size = (500,700)
Builder.load_file('calc.kv')
class MyLayout(Widget):
pass
class Screen1(Screen):
pass
class WindowManager(ScreenManager):
pass
class App(App):
def build(self):
return WindowManager()
if __name__ == "__main__":
App().run()
calc.kv
<WindowManager>:
Screen1
<Screen1>:
BoxLayout:
orientation:"vertical"
size: root.width, root.height
GridLayout:
cols:4
rows:5
TextInput:
id: clac_input
text: "0"
halign: "right"
font_size : 65
size_hint: (1, .15)
Button:
size_hint: (.2, .2)
font_size: 32
text: "%"
I am trying to create a simple Chatbot application UI using Kivy and Python but I'm stuck at the very first stage.
How do I access the TextInput widget inside the BoxLayout to fetch it's contents?
I read that the function on_text_validate() is called whenever you press 'Enter' on the TextInput. However this code down below doesn't seem to be functioning.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import Screen, ScreenManager, FadeTransition
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
from kivy.lang import Builder
Builder.load_string('''
#:import AnchorLayout kivy.uix.anchorlayout
#:import Layout kivy.uix.layout
<ChatBotScreen>:
BoxLayout:
orientation: 'vertical'
ScrollView:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
botOutput: root.botOutput
ScrollView:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
userInput: root.userInput
TextInput:
id: ti_userinput
multiline: False
''')
class ChatBotScreen(Screen):
userInput = StringProperty()
botOutput = StringProperty()
def on_text_validate(self):
text_input_userInput = self.ids['ti_userinput'].text
self.ids['ti_userinput'].text = ''
print(text_input_userInput)
def UserInput(self):
pass
def BotOutput(self):
pass
sm = ScreenManager(transition=FadeTransition())
sm.add_widget(ChatBotScreen(name='mainchat'))
class MyApp(App):
def build(self):
return sm
Please guide me.
The problem in your case is that on_text_validate is not a method of the Screen class, but of TextInput, so you will never call on_text_validate of the ChatBotScreen class, what you can do is invoke that method from the on_text_validate event of the TextInput:
Builder.load_string('''
#:import AnchorLayout kivy.uix.anchorlayout
#:import Layout kivy.uix.layout
<ChatBotScreen>:
BoxLayout:
orientation: 'vertical'
ScrollView:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
botOutput: root.botOutput
ScrollView:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
userInput: root.userInput
TextInput:
id: ti_userinput
multiline: False
on_text_validate: root.on_text_validate()
''')
class ChatBotScreen(Screen):
userInput = StringProperty()
botOutput = StringProperty()
def on_text_validate(self):
text_input_userInput = self.ids['ti_userinput'].text
self.ids['ti_userinput'].text = ''
print(text_input_userInput)
sm = ScreenManager(transition=FadeTransition())
sm.add_widget(ChatBotScreen(name='mainchat'))
class MyApp(App):
def build(self):
return sm
For the sake of brevity I'll explain my problem before posing the code. Here it goes:
I have a Screen class in Kivy that holds two widgets, a GridLayout and an Image. The latter is fine, but the buttons are extremely oversized:
And here's my main.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.factory import Factory
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
from kivy.config import Config
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
import configparser
Builder.load_file('kv\MainMain.kv')
#read configurations
config = configparser.RawConfigParser()
config.read('config.ini')
#read config values
width = config.getint('Default', 'MAX_WINDOW_WIDTH')
height = config.getint('Default', 'MAX_WINDOW_HEIGHT')
border = config.getint('Default', 'BORDERLESS')
#apply config values
Config.set('graphics','width', width)
Config.set('graphics', 'height', height)
Config.set('graphics', 'borderless', border)
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
#create screen manager
class ScreenManager(ScreenManager):
pass
#create background widget
class BackGround(Image):
pass
#image buttons
class MainButtons(GridLayout):
pass
#create main screen:
class MainScreen(Screen):
pass
#create main app
class MainMainApp(App):
def build(self):
return MainScreen()
#register class
Factory.register(MainScreen, cls=MainScreen)
#run
if __name__ == '__main__':
MainMainApp().run()
And here's my kv file:
<ScreenManager>:
id: screen_manager
MainScreen:
id: main_screen
name: 'MainScreen'
manager: screen_manager
ReadScreen:
id: read_screen
name: 'ReadScreen'
manager: screen_manager
<MainScreen>:
BackGround:
id: back_ground
source: 'images\\app_background.jpg'
size: root.width, root.height
MainButtons:
cols: 1
pos: root.width / 2 - 100, root.height / 4
size: 20, 10
Button:
id: button_read
text: "Read"
on_press: root.callback_read()
Button:
id: button_add
text: "Add"
Button:
id: button_manage
text: "Manage"
I'm really swamped on this one. Thanks for your help.
You can use size_hint for this.
Here is an example
The pyhton file:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen,ScreenManager
Builder.load_file("my.kv")
class MainButtons(GridLayout):
pass
class MainScreen(Screen):
pass
class MainMainApp(App):
def build(self):
self.sm = ScreenManager()
self.sm.add_widget(MainScreen(name="main"))
return self.sm
if __name__ == '__main__':
MainMainApp().run()
and kivy file:
<MainScreen>:
MainButtons:
cols: 1
rows: 4
Label:
font_size: "40sp"
text: "Something"
Button:
size_hint: (1,0.1)
text: "Read"
Button:
size_hint: (1,0.1)
text: "Add"
Button:
size_hint: (1,0.1)
text: "Manage"
And output will be:
And if you want the buttons to be smaller in width, you add ´size_hint_x: None´ to your kv file, like this.
<MainScreen>:
MainButtons:
cols: 1
rows: 4
Label:
font_size: "40sp"
text: "Something"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Read"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Add"
Button:
size_hint: (1,0.1)
size_hint_x:None
text: "Manage"
Output will now be: