I am using pydev on eclipse luna. My kv file is as follows:
<LoginForm>:
userid: userid
password: password
size_hint_x: 0.5
size_hint_y: None
height: 200
orientation: 'vertical'
pos_hint: {'center_x': 0.5,'center_y':0.5}
minimum_height: 100
minimum_width: 100
#User ID
Label:
text: 'User ID'
font_size: 20
size_hint_x: None
TextInput:
id: userid
font_size: 20
#User PW
Label:
text: 'Password'
font_size: 20
TextInput:
id: password
password: True
font_size: 20
Button:
text: 'Login'
My python code is:
from kivy.app import App;
from forms.login import LoginForm;
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
class LoginForm(BoxLayout):
def __init__(self, **kwargs):
super(LoginForm, self).__init__(**kwargs)
class StartApp(App):
def build(self):
Window.size = (480, 800)
return LoginForm()
#return StartApp();
if __name__ == '__main__':
StartApp().run()
Output:
The code is working correctly, however, my issue is that there is still some gap at left which is not present for other controls. I want User ID to be completely left aligned (in the above pic it is left aligned, but some space is still left).
Could you please advice/correct me on where I went wrong?
The Label isn't left-aligned because you haven't actually set that, by disabling the size_hint_x it just takes the default width of 100 pixels and the text appears in its centre.
You have two options for declaring the label.
Label:
text: 'User ID'
font_size: 20
size_hint_x: None
width: self.texture_size[0]
This will set the width of the Label to the exact size of the texture containing the image of the text. However, I think it's probably preferable to do the following:
Label:
text: 'User ID'
font_size: 20
text_size: self.size
halign: 'left'
valign: 'middle'
This way, rather than messing with the widget size/position you set the text_size (this controls the bounding box of the text texture) and the built in text alignment options take care of the rest.
In this case, the results of these should be similar if not identical.
Related
I am building a simple Kivy app with a couple of screens. The first screen has a couple of buttons which, when clicked, move to the second screen. The second screen has a text input widget and a button inside a Float Layout. The layout is loaded as a root widget by an explicit call to the kv file through Builder.
Everything was working fine and I added a 'focus: True' tag in the text input attributes. The app worked fine and I could type in the text input field with focus set as True. However, the text input field suddenly stopped working without any change in code or layout. I was not sure and searched Google for a couple of probable solutions, none of which worked:
Removed the 'focus: True' attribute and reloaded the app but the text input field still did not respond. I was unable to type anything from my keyboard.
Another post pointed out that the kv file was being loaded twice resulting in erratic behaviour. I tried to remove the explicit Builder file call and returned the root widget (Screen Manager) in the main code. However, it messed up my entire app and only showed a black empty screen.
Can you please advise as to what I may be doing wrong? The code is provided below:
Python Code:
from kivy.config import Config
Config.set('kivy','window_icon','sivaicon.png')
Config.set('graphics', 'resizable', True)
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.lang.builder import Builder
class SivaLoginScreen(Screen):
def twitter_authentication(self):
App.get_running_app().root.current='verify_screen'
def linkedin_authentication(self):
App.get_running_app().root.current='verify_screen'
class SivaVerifyScreen(Screen):
pass
class SivaTabbedScreen(Screen):
pass
class SivaScreenManager(ScreenManager):
pass
class ImageButton(ButtonBehavior, Image):
pass
# Tell Kivy to directly load a file. If this file defines a root widget, it will be returned by the method.
root_widget = Builder.load_file('siva.kv')
class SivaApp(App):
def build(self):
# Initialize root widget
return root_widget
if __name__ == '__main__':
# Run application
SivaApp().run()
kv file:
SivaScreenManager:
SivaLoginScreen:
SivaVerifyScreen:
SivaTabbedScreen:
<ImageButton>:
keep_ratio: True
<SivaLoginScreen>:
name: 'login_screen'
canvas.before:
Color:
rgba: 195/255, 60/255, 35/255, 1
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
size: root.width, root.height
Image:
id: login_logo_siva
source: 'images/sivalogo1.png'
keep_ratio: True
size_hint: 0.3, 0.3
pos_hint: {'center_x':0.5, 'center_y':0.75}
Label:
id: login_label_siva
pos: self.x*0.5-4, self.y*0.5+15
markup: True
font_name: 'roboto/Roboto-Medium.ttf'
text: '[color=#FDFD98]S.[/color][color=#B29DD9]I[/color][color=#FDFD98].[/color][color=#77DD77]V[/color][color=#FDFD98].[/color][color=#779ECB]A[/color]'
font_size: '40sp'
Label:
id: login_label_slogan1
pos: self.x*0.5-3, self.y*0.5-6
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]SLOGAN TEXT[/color]'
font_size: '13sp'
Label:
id: login_label_slogan2
pos: self.x*0.5-3, self.y*0.5-20
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]HEADLINE TEXT[/color]'
font_size: '13sp'
BoxLayout:
id:login_button_layout
orientation: 'horizontal'
size_hint: 0.2, 0.2
pos_hint: {'center_x':0.5, 'center_y':0.25}
ImageButton:
id: twitter_button
source: {'normal': 'images/twitter-96.png', 'down': 'images/twitter-96.png'} [self.state]
on_release: root.twitter_authentication()
ImageButton:
id: linkedin_button
source: {'normal': 'images/linkedin-96.png', 'down': 'images/linkedin-96.png'} [self.state]
on_release: root.linkedin_authentication()
<SivaVerifyScreen>:
name: 'verify_screen'
canvas.before:
Color:
rgba: 195/255, 60/255, 35/255, 1
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
size: root.width, root.height
Label:
id: verify_label
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: 'Paste the verification code'
font_size: '16sp'
pos_hint: {'center_x':0.5, 'center_y':0.7}
size_hint: 1, 0.4
TextInput:
id: verify_input
multiline: False
font_size: '30sp'
pos_hint: {'center_x':0.5, 'center_y':0.55}
size_hint: 0.5, 0.1
ImageButton:
id: verify_button
source: {'normal': 'images/lock-96.png', 'down': 'images/lock-96.png'} [self.state]
pos_hint: {'center_x':0.5, 'center_y':0.35}
size_hint: 0.5, 0.5
<SivaTabbedScreen>:
name: 'tabbed_screen'
FloatLayout:
size: root.width, root.height
Label:
pos: self.x*0.5, self.y*0.5
text: 'SECOND SCREEN'
font_size: '50sp'
Please advise. I am helplessly stuck. :(
Thanks in advance
Okay so this was the problem: Some of my widgets were overlapping each other thereby rendering the widgets underneath as unresponsive. In my case, a button widget was overlapping my textinput widget due to which I was unable to enter text in the textinput widget.
I used the Kivy inspector tool to identify the extent of the widgets' dimensions:
python3 main.py -m inspector
Use Ctrl+e to launch the inspector while the app is running and click on each widget to check its size, position and parent. I reduced the button widget's size and converted the float layout into a stacked box layout and this resolved the issue.
Is it possible to have a grid like layout inside a Label or a Button in kivy.
I have an app that takes in a CSV file with product information and I would like to populate MainScreen with rows from a CSV file.
Each row should look like this:
In the end the Label or Button should be pressable to open a pop up window for confirmation screen for quantity of the product and verify.
Is it even possible or am I approaching it from the wrong angle?
I do not have any code yet to populate the MainScreen with rows but this is how it looks so far.
To clarify. At this moment I don't need help with importing CSV files, but with the method to display it, that matches the above criteria(picture)
Code so far is as follows:
ATmain.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import StringProperty
Window.clearcolor = (1,1,1,1)
Window.size = (270, 480)
class LoginScreen(Screen):
input = StringProperty("")
class MainScreen(Screen):
username = StringProperty('')
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("app.kv")
class ATApp(App):
presentation = Builder.load_file("app.kv")
def build(self):
return presentation
if __name__ == '__main__':
ATApp().run()
app.kv:
# File name: main.py
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:kivy 1.10.1
ScreenManagement:
transition: FadeTransition()
LoginScreen:
id: login
MainScreen:
username: login.input
<LoginScreen>:
name: "login"
canvas:
Color:
rgba: [1,1,1]
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
rows:2
cols:1
background_color: 1,1,1,1
Label:
size_hint: 0.3, 0.05
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.4}
text:"Kasutaja"
color: 0,0,0,1
TextInput:
id: input
size_hint: (0.3, None)
height: 30
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.3}
multiline: False
Button:
id: confirm_login
text: "Login"
size_hint: 0.15, 0.07
pos_hint: {"x": 0.5 - 0.15/2, "center_y": 0.2}
background_color: 0.9,0.9,0.9,1
on_press: self.background_color = (1,0,0,1)
on_release: root.input = input.text; app.root.current = "main"
<MainScreen>:
name: "main"
canvas:
Rectangle:
pos: self.pos
size: self.size
Label:
id:name
text: root.username
color: (0,0,0,1)
size_hint_y: None
height: 30
size_hint_x: 1
pos_hint: {"right": 1, "top": 1}
BoxLayout:
orientation: "vertical"
size_hint_y: None
size_hint_x: 1
pos_hint_x: None
pos_hint_y: 1
Button:
text: "Item1"
color: (0,0,0,1)
height: self.height
size_hint_y: None
size_hint_x: 1
pos_hint: {"right": 1, "top": 0}
I would be very greatful if anyone could as much as point me in the right direction!
The kivy hack way will be to simply use a GridLayout or any layout for that matter then give your layout button properties so it is clickable like so :
from kivy.behaviors import ButtonBehavior
#then make a clickable grid
class GridButton(GridLayout, ButtonBehaviour):
def __init__(self, **kwargs):
super().__init__(**kwargs)
#Then do whatever you want to do
Another way to do it I guess would be to use the on_touch_down callback and check if the touch is within the widget's bounds
I'm in the process of converting an application from pure Python, to using kivy for screen handling. I'm a kivy newbie!
I'm attempting to replicate a screen which displays current date and time, on two lines, with different sizes for the two lines. I use two different [size=?] markups in the string to be displayed, but the two lines are always displayed at the same size (the second size specified) - how can I get them to be different sizes?
I have seen suggestions that this could be achieved using html, but fear that would be horribly inefficient.
Code is:
<C>:
BoxLayout:
orientation: 'vertical'
BoxLayout:
Button:
text:
'[size=48]' + app.date + '[/size]' + \
'\n[size=96]' + app.time + '[/size]'
background_color: (0, 0, 0, 0)
halign: 'center'
markup: True
on_press: app.stop()
Status:
id: stat
I used your code and the lines had a different font size. Therefore the problem must be outside of the code you provided.
py:
from kivy.app import App
from kivy.properties import StringProperty
class MyApp(App):
date = StringProperty('2017-09-30')
time = StringProperty('Now')
if __name__ == '__main__':
MyApp().run()
kv:
BoxLayout:
orientation: 'vertical'
BoxLayout:
Button:
text:
'[size=48]' + app.date + '[/size]' + \
'\n[size=200]' + app.time + '[/size]'
background_color: (0, 0, 0, 0)
halign: 'center'
markup: True
on_press: app.stop()
Alternatively, you can use the following kv-file:
Button:
on_press: app.stop()
BoxLayout:
pos: self.parent.pos
size: self.parent.size
orientation: 'vertical'
Label:
text: app.date
font_size: 48
Label:
text: app.time
font_size: 96
To generate sth which also behaves more like a button in kv, changes the background on press.
I was trying to look at different examples online to solve this issue but Still cannot figure out. I have an app that calls a popup class. The popup has an input field that does some manipulation to the text in the input field. The manipulated data is stored in a variable inside of the popup class. Now how can the parent widget access the data obtained from this widget. Here is a short example of the code.
KV
<ScreenManagement>:
ScreenManager:
id: manager
size_hint_y: 93
Screen:
name: "Case_info_screen"
id: sc1
FloatLayout:
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 10
canvas.before:
Color:
rgb: 0.17, 0.17, 0.17 # your color here
Rectangle:
pos: self.pos
size: self.size
Label:
text_size: self.size
font_size: 20
valign: 'middle'
height: "75dp"
size_hint_y: None
color: 1,1,1,1
size_hint_x: 75
text: " Case Info"
RelativeLayout:
size_hint_x: 25
Button:
text_size: self.size
halign: 'center'
valign: 'middle'
size_hint: 0.70, 0.6
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: 'Automatic Filler'
on_press: root.formfiller()
BoxLayout:
size_hint_y: 5
spacing: 35
LabelCases:
text: ' Name: '
width: '125dp'
size_hint_x: None
TextInput:
id: first_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'First Name'
TextInput:
id: last_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'Last Name'
<Formfillerpop>:
title: 'Automatic Filler'
size_hint: None, None
size: 600, 600
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: 20
text: 'Please Paste your text'
markup: True
TextInput:
id: sentence
size_hint_y: 65
BoxLayout:
size_hint_y: 10
orientation: 'horizontal'
Button:
text: 'Analyze'
on_press: root.on_analyze(sentence.text)
Button:
text: 'Close'
on_press: root.closepop()
Python:
class Formfillerpop(Popup):
selection = StringProperty
id = ObjectProperty
def on_analyze(self, selection):
analyze = TextExtractor(selection)
names = analyze.name()
def closepop(self):
self.dismiss()
class ScreenManagement(FloatLayout):
def formfiller(self, *args):
Formfillerpop().open()
class IOApp(App):
def build(self):
return ScreenManagement()
if __name__ == '__main__':
IOApp().run()
Ultimately I want to take the txt from names in the popup and then autopopulate the first name and last name in the main app with the analyzed data
Sorry if this is basic. I am fairly new to Kivy.
You can access popup content using its content property. You can use it to read text property of read underlying TextInput. For example this code binds this property to local popup_text StringProperty, which means that any change in the popup text input will be reflected there:
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string('''
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Hello world'
BoxLayout:
text_input: text_input
orientation: 'vertical'
TextInput:
id: text_input
Button:
text: 'dismiss'
on_press: root.dismiss()
''')
class CustomPopup(Popup):
pass
class TestApp(App):
popup_text = StringProperty()
def build(self):
l = BoxLayout()
l.add_widget(Button(
text='show_popup', on_press=self.show_popup
))
l.add_widget(Button(
text='print popup text', on_press=self.print_popup_text
))
return l
def show_popup(self, *args):
p = CustomPopup()
p.content.text_input.bind(text=self.setter('popup_text'))
p.open()
def print_popup_text(self, *args):
print(self.popup_text)
if __name__ == '__main__':
TestApp().run()
Hy, the problem is that with the current code, which is at this point preety much nothing but a text editor, when ever I try to make a scrollable label in the kv language and call it on the main screen at the push of a button, I get no error, theres just nothing there. I should mention that the text is taken from a stored file, and the only version that works is with a regular label. This is the code, I know its a bit long but its preety easy to understand so stay with me. Any sort of input is greatly apreciated and I thank you for taking the time.
#kivy.require("1.8.0")
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Line
from kivy.uix.gridlayout import GridLayout
kv = '''
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManager:
transition: FadeTransition()
MainScreen:
AddScreen:
AppendScreen:
<ScatterTextWidget>:
orientation: 'vertical'
TextInput:
id: main_input
font_size: 14
size_hint_y: None
height: root.height - botones_layout.height
font_color: [0.1,0.3,0.9,1]
focus: True
foreground_color: [0.2,0.5,0.9,1]
cursor_color: [0,0,1,1]
BoxLayout:
id: botones_layout
orientation: 'horizontal'
height: 30
Button:
id: home_button
text: "Back Home"
Button:
id: save_button
text: "Save to file"
on_press: root.saveToFile("Archive.txt", main_input.text)
<AppendTextWidget>:
orientation: 'vertical'
TextInput:
text: root.text
id: main_input
font_size: 14
size_hint_y: None
height: root.height - botones_layout.height
font_color: [0.1,0.3,0.9,1]
focus: True
foreground_color: [0.2,0.5,0.9,1]
cursor_color: [0,0,1,1]
BoxLayout:
id: botones_layout
orientation: 'horizontal'
height: 30
Button:
id: home_button
text: "Back Home"
on_release: app.root.current = "main"
Button:
id: save_button
text: "Save"
on_press: root.append(main_input.text)
#This does not work <--- <--- <---
<ScrollableLabel>:
Label:
text: root.text
font_size: 15
text_size: self.width, None
color: [0,255,0,1]
padding_x: 20
size_hint_y: None
pos_hint: {"left":1, "top":1}
height: self.texture_size[1]
<MainScreen>:
name: "main"
FloatLayout:
# This does work
Label:
text: root.text
font_size: 15
text_size: self.width, None
color: [0,255,0,1]
padding_x: 20
size_hint_y: None
pos_hint: {"left":1, "top":1}
height: self.texture_size[1]
ActionBar:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: "Text"
with_previous: False
ActionOverflow:
ActionButton:
text: "New"
on_release: app.root.current = "add"
ActionButton:
text: "Update"
on_press: root.clicked()
ActionButton:
text: "Add"
on_release: app.root.current = "append"
<AddScreen>:
name: "add"
FloatLayout:
ScatterTextWidget
<AppendScreen>:
name: "append"
FloatLayout:
AppendTextWidget
'''
class ScatterTextWidget(BoxLayout):
def saveToFile(self,name,text):
f = open(name, "w")
f.write("\n\n\n" + " " + ">>>" + text + "test"*500)
f.close()
class AppendTextWidget(BoxLayout):
text = StringProperty("")
def append(self,text):
with open("Archive.txt", "a") as f:
f.write("\n" + " " + ">>>" + text)
f.close()
class ScrollableLabel(ScrollView):
text = StringProperty('')
pass
class MainScreen(Screen):
text = StringProperty("")
def clicked(self):
with open("Archive.txt", "r") as f:
contents = f.read()
self.text = contents
pass
class AddScreen(Screen):
pass
class AppendScreen(Screen):
pass
class MyApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
MyApp().run()
Why it works:
Your text in MainScreen is updated from file, then passed to Label and the text is loaded. ScrollableLabel.text stays unchanged.
Why it doesn't work as you expect:
There's no communication between your classes, therefore only text changed is an actual self.text = MainScreen.text
How to make it work:
Either use something on a global range, i.e. variable in your App class, then a = App.get_running_app() and access variable through a.<variable> or use __init__ to initialize your ScrollableLabel inside the MainScreen and pass it the text
So it's basically a duplicate of this and that one is a duplicate of an older unsimplified question.