Python kivy - how to reduce height of TextInput - python

I am using kivy to make a very simple gui for an application. Nothing complex, very simple layout.
Nevertheless I am having a hard time with TextInputs...They always display with full height and I can't manage to make them adjust to a "reasonable" text-height like height.
I am using the kv files style since I find it cleaner and easier to integrate it in an already existing app...I would like to reduce as much as possible the gui-python code of the app.
Here is what I got for the TextInput (useless to add other parts of the gui).
Python code
# textInput.py
from kivy import require
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang.builder import Builder
Builder.load_file('path/to/kv/file/textInput.kv')
require('1.10.0')
class MainScreen(BoxLayout):
pass
class Test(App):
def build(self):
self.title = 'Testing textInput'
return MainScreen()
if __name__ == '__main__':
Test().run()
KV code
# textInput.kv
<MainScreen>
orientation: 'vertical'
# Third section title
Label:
size_hint: (1, .1)
text: 'Setup Connection'
font_size: 25
# Third section Box
BoxLayout:
size_hint: (1, .2)
padding: [100, 0, 100, 0]
BoxLayout:
Label:
size_hint: (.2, 1)
text: 'Host'
TextInput:
height: self.minimum_height
multiline: False
text: 'localhost'
Label:
size_hint: (.2, 1)
text: ''
Label:
size_hint: (.2, 1)
text: 'Port'
TextInput:
size_hint: (.2, 1)
multiline: False
text: '502'
I have tried lot of stuff, in the code here I am trying both to use size_hint and height...but none works..

To set a height of a widget, first set the size_hint_y to None and then you can set the height to whatever you want.
TextInput:
size_hint: (.2, None)
height: 30
multiline: False
text: '502'

in addition to the answer size_hint_x and size_hint_y must be set to None respectively before the height and width attribute can be used i.e size_hint: (None, None) for less typing. If you want to set the width attribute, size_hint_x is set to None and vice-versa.

Related

python kivy Boxlayout not organizing it's children

I'm creating a simple Database-GUI and want to add two lines to a form. each line is a DataField-Object, and contains a label and a TextInput organised by a horizontal Boxlayout. up to here all fine.
The Form-Widget contains also a BoxLayout (Orientaton: "Vertical") organizing the two DataField-Objects by listing them up under each other, but it doesn't work...
My Question: WHY??? and how can I fix it?
dbgui3.py
from kivy import require
require("2.0.0")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty, ObjectProperty
class DataField(Widget):
title = StringProperty()
pass
class Form(Widget):
b = ObjectProperty()
def __init__(self, *rec, **kwargs):
super().__init__()
for df in rec:
self.b.add_widget(DataField(title=df))
class DbGui3(App):
def build(self):
return Form("hello", "world")
if __name__ == '__main__':
DbGui3().run()
dbgui3.kv
<DataField>:
text: txt.text
BoxLayout:
orientation: "horizontal"
size_hint: None, None
size: root.width, 30
canvas:
Color:
rgb: 0.2,0.2,0.2
Rectangle:
size: self.size
Label:
text: root.title
size_hint: None, 1
width: self.texture_size[0]
TextInput:
id:txt
multiline: False
on_text_validate: print("text validated:" + root.text)
<Form>:
b:b
BoxLayout:
id: b
orientation: "vertical"
size_hint: None, None
size: root.width, root.height
canvas:
Color:
rgb: 0.1,0.2,0.3
Rectangle:
size: self.size
The problem is that you are using Widget as a base class for your DataField and Form classes. The Widget class does not take any notice of things like size_hint, pos_hint, and others. It is not intended to be a Layout. I suggest you use BoxLayout as the base for your DataField and some other Layout (perhaps FloatLayout) as the base class for Form. Using this suggestion, your class definitions could be:
class DataField(BoxLayout):
title = StringProperty("example")
class Form(FloatLayout):
pass
Then modifying your kv:
<DataField>:
size_hint: 1, None
height: 30
orientation: "horizontal"
Label:
size_hint: None, None
size: self.texture_size[0]*1.3, root.height
text: root.title
TextInput:
multiline: False
on_text_validate: print(root.title)
<Form>:
BoxLayout:
orientation: "vertical"
size_hint: None, None
size: root.width/2, root.height/2
DataField:
title: "hello"
DataField:
title: "world"
I think this will do what you want.

How to make round edges in a MDCard KivyMD

I am doing an App in kivy using kivyMD but I Want to insert a MDcard, the thing is that I want the MDCard look like this:
But it looks like this:
I know it can be with border_radius but I dont know how to do it,
here is my code:
PY:
import kivy
from kivymd.app import MDApp
from kivymd.uix.card import MDCard
class Home(MDCard):
pass
class Manage(MDApp):
title = 'QUICKP'
def build(self):
return Home()
if __name__ == '__main__':
Manage().run()
KV:
<Home>
MDCard:
size_hint: None, None
size: "280dp", "180dp"
pos_hint: {"center_x": .5, "center_y": .5}
You do not need to modify the card.py file nor do you have to use canvas you just have to place the following in your kivy code
border_radius: 20
radius: [15]
In border_radius you put the border limit that you will be able to use and in radius you put the border level that your mdcard will have.
People advise to use canvas its OK, but it increase your coding and make it very complex. Just go to the Kivymd>uix>card.py line 631 change the default from 3dp to for example 20dp or whatever you want. then go back to your code and type radius: [] and insert your desire number from 20 to 0.
Done!!!
#BernardoOlisan You can use this directly
MDCard:
size_hint: None, None
size: "280dp", "180dp"
pos_hint: {"center_x": .5, "center_y": .5}
elevation: 15
radius: 10
MDLabel:
text: 'Your title'
halign: 'center'
pos_hint: {"center_x": .5, "center_y": .5}
It works for sure
I had the same problem, and there is a border_radius property for MDCards, but it does not work. But i have solved this with this code:
<MyCard>:
orientation: 'vertical'
size_hint: 0.1, 1
canvas.before:
Color:
rgba: app.theme_cls.primary_color
RoundedRectangle:
radius: [10]
size: self.size
pos: self.pos
FloatLayout:
size: self.size
pos: self.pos
pos_hint: {"x": -0.1, "y": -0.6}
And here is a part from .py file:
class Plan(RectangularElevationBehavior, RectangularRippleBehavior, FloatLayout):
ripple_scale = 1.4
text = StringProperty()
text_label = StringProperty()
So, it creates a MyCard(FloatLayout class) with Canvas in it, which inherits from FloatLayout, RippleBehaviour and ElevationBehaviour. And then you can add to that FloatLayout in it to manage content of it. But if it looks strange because of the position, try playing with pos_hint-s.

How to fix the position of a Kivy layout when the screen resolution changes as the program is open?

I have built a user interface with Kivy that appears correctly when the program starts up, but if I plug in a new monitor (or drag to an extended monitor), everything disappears under the window, but I can see part of my work when I maximize the window. How do I position my program to the start of the window?
I have tried to match the main layout top value to the window top value every second, and I have tried to reset the position of the main layout every second.
My kivy file
#:import inch kivy.metrics.inch
<Questionaire>:
#column_gl: ColumnGL
outer_column_gl: OuterColumnGL
cols: 2
GridLayout:
id: OuterColumnGL
cols: 1
size_hint_x: None
width: inch(2)
GridLayout:
id: ColumnGL
cols: 2
size_hint_y: .9
Button:
size_hint_x: None
width: inch(.1)
Button:
text: 'stuff'
Button:
size_hint_y: .1
text: 'more stuff'
My attempt to fix it
def fix_screen(*args):
self.y = 0
Clock.schedule_interval(fix_screen, .5)
This is what comes up when I first open the program.
This is what comes up as soon as I drag my window to an extended monitor (Everything appears to have disappeared).
Here is my maximized window on the extended monitor (The y position is wrong).
Using size_hint_x or size_hint_x allows you to set the size of your widgets relative to their parent widgets. Using ''pos_hint: {'x': val, 'y': val}'' will set the position of the widget to their parent widgets. Since size_hint, and pos_hint both are relative to their parent widgets, the values for the x and y are in a range from 0-1.
I would recommend utilizing size_hint_x: 0-1 rather than width for your buttons so they will automatically adjust to a changing resolution. I will come up with a sample to help you out.
Sizing and position are best done in the kv language whether you use builder or a .kv file. The added class and function are not needed to have reactive widgets. Let me know if you need more clarification or have any other questions about kivy.
Again I would recommend this following your widgets if you would like them to autoscale:
size_hint_x: 0.00-1.00
size_hint_y: 0.00-1.00
pos_hint: {'x': 0.00-1.00, 'y': 0.00-1.00}
An example that should show you how it works, although I doubt you need all the extra imports as this was to show consistency when changing resolutions:
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
Config.set('input', 'mouse', 'mouse,multitouch_on_demand') #Prevent red dots from populating the screen with right clicks
Config.set('graphics','resizable',0) #Self-explanatory, prevents you from resizing the window
Config.write() #Writes the Config settings for the application
Builder.load_string("""
<One>:
GridLayout:
cols: 2
size_hint_x: .5
pos_hint: {'x': 0, 'y': 0}
GridLayout:
id: OuterColumnGL
cols: 1
size_hint_x: .2
GridLayout:
id: ColumnGL
cols: 2
size_hint_y: .9
Button:
size_hint_x: .3
Button:
text: 'stuff'
Button:
size_hint_y: .1
text: 'more stuff'
Button:
text: 'Change Res'
size_hint_x:.2
size_hint_y: .2
pos_hint: {'x': .75, 'y': .05}
on_release: root.enlarge()
<Two>:
GridLayout:
cols: 2
size_hint_x: .5
pos_hint: {'x': 0, 'y': 0}
GridLayout:
id: OuterColumnGL
cols: 1
size_hint_x: .2
GridLayout:
id: ColumnGL
cols: 2
size_hint_y: .9
Button:
size_hint_x: .3
Button:
text: 'stuff'
Button:
size_hint_y: .1
text: 'more stuff'
Button:
text: 'Change Res'
size_hint_x:.2
size_hint_y: .2
pos_hint: {'x': .75, 'y': .05}
on_release: root.shrink()
""")
class One(Screen):
def enlarge(self):
Window.size = (500, 600)
sm.current = 'two'
class Two(Screen):
def shrink(self):
Window.size = (300, 400)
sm.current = 'one'
sm = ScreenManager()
sm.add_widget(One(name='one'))
sm.add_widget(Two(name='two'))
class SampleApp(App):
def build(self):
Window.size = (300, 400)
Window.left = 750
Window.top = 40
return sm
if __name__ == '__main__':
SampleApp().run()

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.

Kivy - base application has strange alignment

I am trying to build a basic Kivy app. After adding the basic elements, and running the app, all of the elements are crammed into the bottom left corner. It shows up like this on android and Linux.
Main.py:
from kivy.app import App
from kivy.uix.widget import Widget
class SublimeLauncher(Widget):
pass
class SublimeLauncherApp(App):
def build(self):
return SublimeLauncher()
if __name__ == "__main__":
SublimeLauncherApp().run()
sublimelauncher.kv:
#:kivy 1.2.0
<SublimeLauncher>:
FloatLayout:
BoxLayout:
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
I first tried it with just the BoxLayout, but read somewhere the root widget is always as big as the app. How do I declare the size of the app? Or the layout? How would you go about doing something like a dialog box?
Maybe I am missing something very basic, but I can't seem to figure it out.
Edit: here is what I am seeing..
Your layout has a default size of 100x100 pixels. You can try to color it to see how much space does it take:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
kv = '''
<SublimeLauncher>:
BoxLayout:
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
class SublimeLauncher(Widget):
pass
class SublimeLauncherApp(App):
def build(self):
return SublimeLauncher()
if __name__ == "__main__":
SublimeLauncherApp().run()
Setting non-default size:
kv = '''
<SublimeLauncher>:
BoxLayout:
size: 250, 250
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
Taking full space:
kv = '''
<SublimeLauncher>:
BoxLayout:
size: root.size
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
size: self.size
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open. \\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
'''
Builder.load_string(kv)
I recently wrote a post of a little trick I use when I am programming interfaces. The trick will let you see a border around all the widgets (layouts included) you add to the screen. This would be the result for your code:
It takes advantage of inheritance and the Kivy rules to overwrite the base class of all widgets. You just have to add:
<Widget>:
canvas.after:
Line:
rectangle: self.x+1,self.y+1,self.width-1,self.height-1
at the beginning of this file:
<SublimeLauncher>:
FloatLayout:
BoxLayout:
orientation: 'vertical'
spacing: 10
Label:
text: "Enter the path to the folder to open.\nPress OK if you would like to open without a directory"
TextInput:
id: folderpath
Button:
text: 'OK'
As your root widget is not a layout (you made SublimeLauncher inherit Widget), it doesn't set its children size/positions. So your FloatLayout have the defaults, since you don't override them manually either.
pos: 0, 0
size: 100, 100
And these defaults of course constraints the child, since FloatLayout by constraint their size based on their size_hint property.
You want to give them more space, as Nykakin pointed out.
Also, as your text is bigger than the Label (you didn't set halign and text_size either) its texture is centered on the center of the Label, and so some part of it is out of screen. You want to have a look at kivy/examples/widgets/textalign.py

Categories

Resources