how to enable/disable editing in TextInput using kivy in python - python

I have a piece of code. (1) The TextInput value should be shown , but first it should not be editable, after clicking the corresponding CheckBox, the TextInput will be editable.
(2) Using the iteration, the Label and the TextInput should get the value. The value at Label and TextInput should not be hard coded(although it's there in my code, #FJSevilla helped me for this one).
(3) However, the values of Label and TextInput are stored in a variable in json format. something like this(you can consider like key,value pair in map) [ variable = '{"a" : " Goc" , "b" : "Coc", "c" : "Dow" } ']
(you can see diagram for more clearance).
I appreciate the help.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
BoxLayout:
padding: 50, 50, 50, 50
orientation: 'horizontal'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 1
Label:
text: 'a'
Label:
text: 'b'
Label:
text: 'c'
BoxLayout:
spacing: 50
orientation: 'vertical'
TextInput:
text: 'Goc'
TextInput:
text: 'Coc'
TextInput:
text: 'Dow'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.40
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.60
Button:
text: 'save'
Button:
text: 'save'
Button:
text: 'save'
""")
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()

First of all, thank you for providing an app which was easy to work with.
I tried to implement what you were looking for except the JSON. I am using a simple list, it should be straightforward to extend my code for a JSON.
Instead of using colums, I am using rows which makes it easier to link together the properties of the label textinput and checkbox.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.lang import Builder
ROWS = ['Goc', 'COC', 'EEE']
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
Table:
padding: 50, 50, 50, 50
orientation: 'vertical'
<Row>:
spacing: 50
#orientation: 'vertical'
size_hint_x: 1
txt: txtinpt.text
Label:
text: root.txt
TextInput:
id: txtinpt
text: root.txt
disabled: not CheckBox.active
CheckBox:
id:CheckBox
text: 'CheckBox'
active: False
Button:
text: 'save'
""")
class Table(BoxLayout):
def __init__(self, **kwargs):
super(Table, self).__init__(**kwargs)
for row in ROWS:
self.add_widget(Row(row))
class Row(BoxLayout):
txt = StringProperty()
def __init__(self, row, **kwargs):
super(Row, self).__init__(**kwargs)
self.txt = row
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()

Related

Kivy ScrollView in ScreenManager

I am trying to create several scrollable main screens that are connected with ScreenManager
However, when I try, I get the following error:
Only one root object is allowed by .kv
This happens when I add the WindowsManager in the kv file.
Can anyone advice me with how to resolve this?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
class WindowManager(ScreenManager):
pass
class MenuPage(Screen):
pass
class MainPage(Screen):
pass
class Sections(BoxLayout):
label_text = StringProperty()
kv = Builder.load_file('main text')
class Scrollable(App):
def build(self):
return kv
def on_start(self):
self.root.ids.sv_box.add_widget(Sections(label_text=''))
Scrollable().run()
**kv file**
WindowsManager:
MainPage:
MenuPage:
BoxLayout:
orientation: 'vertical'
ScrollView:
do_scroll_y: True
BoxLayout:
orientation: 'vertical'
id: sv_box
size_hint_y: None
height: self.minimum_height
<Sections>:
orientation: 'vertical'
size_hint_y: None
height: 800
BoxLayout:
size_hint: (1,.5)
Button:
text: 'Menu'
size_hint: (.3,1)
BoxLayout:
Label:
text: 'Time'
```
According to kivy documentation a .kv file must contain only one root widget at most. In other words you can not have more than one class in the left most indentation level (except for dynamic classes) in kvlang.
In your posted code of .kv file there are two classes (WindowsManager and BoxLayout) at left(most) with same indentation level.
As from your code it's not clear which one of these two is the root widget, I assumed WindowsManager to be the root and moved the BoxLayout stuff under MainPage. Thus your modified main text.kv file now looks like,
WindowManager: # WindowsManager
MainPage:
BoxLayout:
orientation: 'vertical'
ScrollView:
do_scroll_y: True
BoxLayout:
orientation: 'vertical'
id: sv_box
size_hint_y: None
height: self.minimum_height
MenuPage:
<Sections>:
orientation: 'vertical'
size_hint_y: None
height: 800
BoxLayout:
size_hint: (1,.5)
Button:
text: 'Menu'
size_hint: (.3,1)
BoxLayout:
Label:
text: 'Time'

Kivy Python: buttons and classes for multiple screens

I have a problem with my Kivy Python Code. I have 2 screens: 1st is to navigate to the second screen and on the 2nd screen there is a button to add text to a scrollview...navigating is working but it does not add any text to the scrollview...I think I need some help here! AttributeError: 'super' object has no attribute 'getattr'
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock, mainthread
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.lang import Builder
Builder.load_string("""
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
""")
# Declare both screens
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self,**kwargs):
super().__init__(**kwargs)
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='mainmenu'))
sm.add_widget(Screen2(name='screen2'))
return sm
def add_text(self):
self.root.ids.label.text += f"Some new Text\n"
self.root.ids.scroll_view.scroll_y = 0
def exit_software(self):
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()
Thank you very much in advance!
The error occurred because self.root.ids gets access to widgets located in the root widget of the main class. To access the secondary screen elements, you need to add it to the main class (in your case, in ScreenManager) and set its id. Also, you have a lot of imported excess, so that it is clearly visible, I advise you to use Pycharm or something like that.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
kv = """
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
ScreenManager:
MenuScreen:
id: menu_scr
Screen2:
id: scr_2
"""
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
return Builder.load_string(kv)
def add_text(self):
self.root.ids.scr_2.ids.label.text += f"Some new Text\n"
self.root.ids.scr_2.ids.scroll_view.scroll_y = 0
#staticmethod
def exit_software():
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()

Python/Kivy : Remove space using python

I am using python-2.7 and kivy. I am trying to hide TextInput with blank space.
At this time i am using opacity property for hiding Textinput
self.row.abc.opacity = 0
Using this code TextInput is hiding but blank space not removed. Can someone tell me how to remove blank space or another better solution for hiding Textinput with blank space.
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, StringProperty, ObjectProperty
Window.size = (450, 425)
class display(Screen):
def __init__(self, **kwargs):
super(display, self).__init__(**kwargs)
def add_more(self):
self.ids.rows.add_row()
class Row(BoxLayout):
button_text = StringProperty("")
id = ObjectProperty(None)
col_data = ListProperty(["", ""])
class Rows(BoxLayout):
orientation = "vertical"
row_count = 0
def __init__(self, **kwargs):
super(Rows, self).__init__(**kwargs)
self.add_row()
def add_row(self):
self.row_count += 1
self.row = Row(button_text=str(self.row_count))
self.row.abc.opacity = 0
self.row.col_data[1] = 'Test1'
self.add_widget(self.row)
class test(App):
def build(self):
return self.root
if __name__ == '__main__':
test().run()
test.kv
<Row>:
abc: abc
#state1 : state1
orientation: "horizontal"
spacing: 0, 5
Button:
text: root.button_text
size_hint_x: .2
TextInput:
id : abc
size_hint_x: .8
text : root.col_data[0]
TextInput:
size_hint_x: .8
text : root.col_data[1]
display:
BoxLayout:
orientation: "vertical"
padding : 20, 20
BoxLayout:
orientation: "horizontal"
Button:
size_hint_x: .2
text: "+Add More"
valign: 'bottom'
on_press: root.add_more()
BoxLayout:
orientation: "horizontal"
Label:
size_hint_x: .2
text: "SN"
valign: 'bottom'
Label:
size_hint_x: .8
text: "Value1"
valign: 'bottom'
Label:
size_hint_x: .8
text: "Value2"
valign: 'bottom'
Rows:
id: rows

Can I move from one TextBox to another TextBox by pressing the enter button on the keyboard?

I have two files test.py and test.kv.
I want to move from one TextBox to another TextBox by pressing the enter key. How can this be accomplished?
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty
Window.size = (500, 330)
class TestScreen(Screen):
popup = ObjectProperty(None)
class Test(App):
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
if __name__ == '__main__':
Test().run()
test.kv
#:kivy 1.10.0
TestScreen:
GridLayout:
cols: 2
padding : 30,30
spacing: 10, 10
row_default_height: '40dp'
Label:
text: 'Name'
TextInput:
id: name
Label:
text: 'Class'
TextInput:
id: clas
Button:
text: 'Ok'
Button:
text: 'Cancel'
Since you want to use Enter to change the focus, I guess you do not want a multiline texinput. Therefore, one option would be use on_text_validate event:
on_text_validate
Fired only in multiline=False mode when the user hits ‘enter’. This will also unfocus the textinput.
In your kv file you can do something like:
#:kivy 1.10.0
TestScreen:
GridLayout:
cols: 2
padding : 30,30
spacing: 10, 10
row_default_height: '40dp'
Label:
text: 'Name'
TextInput:
id: name
multiline: False
on_text_validate: clas.focus = True # <<<<<<<<<<<
Label:
text: 'Class'
TextInput:
id: clas
multiline: False
Button:
text: 'Ok'
Button:
text: 'Cancel'

flexible number of objects in kivy scrollview

I am trying to use input on one screen to make a list on a second screen using kivy. The basic idea is that a paragraph is broken up into words, which are then displayed on another page. Below is a minimum example.
What is happening is that the words are getting squished together, and there's no scrolling.
In main.py:
from kivy.app import App
from kivy.app import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
class InputScreen(Screen):
wordList = ObjectProperty()
def getwords(self):
self.wordList=[]
s = self.ids.textInput.text.split()
for w in s:
for punctuation in [',','.','!','?']:
w.strip(punctuation)
self.wordList.append(w)
return None
class WordLabel(Label):
pass
class WordScreen(Screen):
wordList = ObjectProperty()
def updateWords(self):
self.ids.scrollContainer.clear_widgets()
wordGrid = GridLayout(cols=2,size_hint_y=None)
wordGrid.bind(minimum_height=wordGrid.setter('height'))
for w in self.wordList:
wordGrid.add_widget(Label(text=w))
wordGrid.add_widget(Label(text='property of word'))
self.ids.scrollContainer.add_widget(wordGrid)
class testScreenManager(ScreenManager):
pass
class testApp(App):
def build(self):
sm = testScreenManager()
return sm
if __name__=='__main__':
testApp().run()
In test.kv:
<testScreenManager>
InputScreen:
id: inputScreen
name: 'input'
WordScreen:
id: wordScreen
name: 'word'
wordList: inputScreen.wordList
<InputScreen>:
GridLayout:
cols: 1
TextInput:
id: textInput
hint_text: 'Input paragraph'
BoxLayout:
orientation: 'horizontal'
size_hint_y: .2
Button:
text: 'Analyze paragraph'
on_press: root.getwords()
Button:
text: 'See word list'
on_press:
root.getwords()
root.manager.transition.direction = 'left'
root.manager.current = 'word'
BoxLayout:
orientation: 'horizontal'
size_hint_y: .2
Label:
id: wordCountResult
text: ''
<WordScreen>:
on_enter: root.updateWords()
BoxLayout:
orientation: 'vertical'
BoxLayout:
id: rowLabels
orientation: 'horizontal'
size_hint_y: .2
Label:
text: 'Words not at grade level:'
size_hint_x: .5
Label:
text: 'Grade Level'
size_hint_x: .5
ScrollView:
id: scrollContainer
size_hint: (None,None)
size: (self.parent.width,self.parent.height - rowLabels.height - buttonRow.height)
Button:
id: buttonRow
size_hint_y: .2
text: 'Back'
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'input'
<WordLabel>:
size_hint_y: None
height: '29sp'
I've tried using size_hint_y=.6 for the ScrollView, and swapping height and minimum_height in the wordGrid.bind(minimum_height=wordGrid.setter('height')).
What I thought was going to happen, is that the ScrollView container will be the height of the window minus the height used by two other widgets. Inside the ScrollView, WordGrid is longer (the height is bound to the minimum height necessary for all children) and so the scrolling is used to see all the items. I must not be understanding some fact about heights/sizes of ScrollView, WordGrid, and WordGrid's children. Anyone have some insight?
In this part of the code:
for w in self.wordList:
wordGrid.add_widget(Label(text=w))
wordGrid.add_widget(Label(text='property of word'))
the Label by default will have size_hint_y=1. Instead, size_hint_y=None is necessary. A height can be set, as is done in the WordLabel class - which was what the OP (by me) meant to do.
Thanks to related question Kivy ScrollView - Not Scrolling for helping me to realize the error.

Categories

Resources