I am new to kivy, I want to create my basic UI for android application,
and I tried to code down below, I first create my boxlayout to separate my UI into three parts: title part, main part, and icon part,
actually my question is about how to size and position my icon image button
<MyLabel#Label>:
color: .8, .9, 0, 1
font_size: 32
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
<MyBoxLayout>:
orientation: 'vertical'
BoxLayout:
size_hint: 1, .1
Label:
text: "Face-Reg"
font_size: 50
color: .8, .9, 0, 1
text_size: self.size
ScrollView:
size_hint: 1, .8
MyLabel:
text: str ('Hello This is My New Project ' * 100)
BoxLayout:
size_hint: 1, .1
Button:
size_hint_x: 0.25
Image:
source: 'icon/server.png'
size:self.texture_size
Button:
size_hint_x: 0.25
Image:
source: 'icon/add.png'
size:self.texture_size
Button:
size_hint_x: 0.25
Image:
source: 'icon/recog.png'
size:self.texture_size
Button:
size_hint_x: 0.25
Image:
source: 'icon/renew.png'
size:self.texture_size
The output screen snapshot is:
1
Four Icon are overlapped together, also the size is not match to the button size
how can I fix that? Thanks
You can adjust the size and pos using those properties of the Image. For example, here is how you might adjust the third Button:
Button:
id: b3
size_hint_x: 0.25
Image:
source: 'icon/recog.png'
allow_stretch: True
keep_ratio: False
size: b3.size
pos: b3.pos
Note the id assigned to the Button. That id is used to assign the same size and position to the Image. The allow_stretch: True property makes the Image stretch to fit the specified size, and the keep_ratio: False allows the image to be stretched unevenly. See the Image documentation for more details.
Related
I wanted to use images to replace buttons on kivy. On youtube what I've seen is people creating an Image widget as a child of the button. But whenever I do this the image becomes a lot smaller than it's native resolution. I've tried resizing it with size_hint but it just doesn't scale. What I've done is just create the the Image widget seperate from the buttons and matched up their size and positions. I'm just curious if this is the only way to go about it or is there a better way to do it.
What I tried to do based on youtube videos:
<MainGrid>:
FloatLayout:
#cols: 1
size: root.width, root.height
Button:
on_release: root.submit_button()
pos_hint: {"x":0.25,"top":0.8}
size_hint: 0.5, 0.2
Image:
source: "arrow1.png"
my "solution":
<MainGrid>:
FloatLayout:
#cols: 1
size: root.width, root.height
Button:
on_release: root.yt_button()
pos_hint: {"x":0.25,"top":0.8}
size_hint: 0.5, 0.2
background_color: 0,0,0,0
Image:
source: "arrow1.png"
pos_hint: {"x": 0, "y": 0.2}
allow_stretch is a better way:
Image:
source: "arrow1.png"
allow_stretch: True
I am having an issue when placing an icon.png as the background_normal of a button within Kivy. When the image is displayed within the button there are black areas that stretch from the sides of the icon. Some icons appear as the they are stretched forwards from the middle as well. All icons used have a transparent background colour.
I have ensured the source image is the same res (80x80px) as the button it is placed within. Also tried setting allow_stretch to False and kee_ration to True. None seem to fix the issue.
This is how the icon should display
This is how it is being displayed within the button(ignore the brown canvas colour)
Below is the .kv section which creates the Button within a BoxLayout and then applies the source image as the background
<SettingsScreen>
name: "Settings"
size: self.width, self.height
BoxLayout:
size: root.width, root.height
cols:1
orientation: 'vertical'
spacing: 2
canvas.before:
Color:
rgba: hex('#D29F7C')
Rectangle:
size: self.size
BoxLayout:
size_hint: (None, None)
size: (1920, 80)
orientation: 'horizontal'
Button:
background_colour: 0, 0, 0, 0
background_normal: r'C:\Users\James\Documents\Coding\Python\Practice Projects\Gardening App\Icons\Home.png'
allow_stretch: False
keep_ratio: True
size_hint: (None, None)
size: (80, 80)
canvas.before:
Color:
rgba: hex('#AB9D92')
Rectangle:
pos: self.pos
size: self.size
bold: True
color: 0.7, 0.7, 0.7, 1
font_hinting: 'normal'
font_size: 40
font_name: 'calibril.ttf'
text: 'Menu'
on_release:
app.root.current = "Menu"
root.manager.transition.direction = 'right'
Issue seems to arise when the image being applied to the background of the button is the same resolution as the button itself. When the image size was decreased to slightly below that of the button the distortion disappeared.
I'm currently working on building a digital planner app, where I want to include some statistics-related features. Obviously, matplotlib is an optimal means of doing that, but I have two problems with it when I try to add more than one plot in a a Kivy ScrollView:
Each plot decreases in size so much that you cannot see what's
actually being displayed;
Kivy ScrollView is not scrolling - unfortunately, very common.
I've tried setting ScrollView's height equal to ScrollView.minimum_height and yet I get no result.
Here's a bit of my Python code:
class StatsWindow(FloatLayout, MDTabsBase):
dates_from, dates_to, plot_scroll = [str(datetime.today()).split()[0]], [str(datetime.today()).split()[0]], ObjectProperty(None)
def add_sp_plot(self, date_from, date_to):
# There were too many lines of data handling and plot creating, so I've only left the KivyPart:
# ------- KIVY part ------- KIVY part ------- KIVY part ------- KIVY part ------- #
self.plot_scroll.plot_layout.clear_widgets()
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf(), size_hint_y=None))
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf(), size_hint_y=None))
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf(), size_hint_y=None))
Here's a bit of my Kivy code:
<StatsWindow>:
name: "stats"
text: "STATS"
icon: "thumbs-up-down"
plot_scroll: plot_scroll
choose_date_to: choose_date_to
choose_date_from: choose_date_from
FloatLayout:
MDLabel:
halign: "center"
size_hint: 1, .1
text: "Choose the dates to view your stats"
font_size: self.width / 17
color: app.theme_cls.primary_color
pos_hint: {"top": .98, "center_x": .5}
BoxLayout:
MDFlatButton:
id: choose_date_from
pos_hint: {"center_x": .25, "top": .88}
text: "from"
size_hint: .4, .1
font_size: self.width / 11
on_release: root.open_date_picker(root.dates_from, self)
MDFlatButton:
text: "|"
size_hint: .1, .1
pos_hint: {"center_x": .5, "top": .88}
MDFlatButton:
id: choose_date_to
font_size: self.width / 11
pos_hint: {"center_x": .75, "top": .88}
text: "to"
size_hint: .4, .1
font_size: self.width / 11
on_release:
root.open_date_picker(root.dates_from, self)
BoxLayout:
MDFlatButton:
size_hint: 1, .1
text: "Load the statistics"
pos_hint: {"center_x": .5, "top": .78}
on_release: root.add_sp_plot(choose_date_from.text, choose_date_to.text)
ScrollView:
id: plot_scroll
do_scroll_y: True
do_scroll_x: False
pos_hint: {"top": .68}
plot_layout: plot_layout
size: root.width, root.height
GridLayout:
id: plot_layout
cols: 1
height: self.minimum_height
Here's the picture of what I get when I run the program:
The ScrollView will only scroll if its child (the GridLayout) is larger than the ScrollView. Also, the line:
height: self.minimum_height
will have no effect unless you add the line:
size_hint_y: None
You can increase the size of the plots by specifying a row_default_height for the GridLayout and eliminating the size_hint_y=None for the FigureCanvasKivyAgg. So, I would suggest specifying your ScrollView as:
ScrollView:
id: plot_scroll
do_scroll_y: True
do_scroll_x: False
pos_hint: {"top": .68}
plot_layout: plot_layout
GridLayout:
id: plot_layout
cols: 1
size_hint_y: None
row_default_height: 500 # any default row height that you desire
height: self.minimum_height
Then, add the plots using:
def add_sp_plot(self, date_from, date_to):
# There were too many lines of data handling and plot creating, so I've only left the KivyPart:
# ------- KIVY part ------- KIVY part ------- KIVY part ------- KIVY part ------- #
self.plot_scroll.plot_layout.clear_widgets()
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf()))
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf()))
self.plot_scroll.plot_layout.add_widget(FigureCanvasKivyAgg(plt.gcf()))
Removing the size_hint_y=None leaves the default value of size_hint_y as 1, so that the plot will take up all the space that the GridLayout allocates to it (the row_default_height).
I want to have a banner on the bottom of my application which scales with varying width. However, I can't get the size of the widget to correspond to the size of the image and because of that, I leave some blank space underneath the banner itself. How can this be done?
Here my try:
FloatLayout:
canvas.before:
Color:
rgb: utils.get_color_from_hex("#6ec4c1")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
cols: 3
pos_hint: {"top": 0.95}
size_hint: 1, 0.05
ImageButton:
source: "images/back_arrow.png"
on_release: app.change_screen("home_screen")
Image:
source: "images/icon.png"
Label:
text: ""
Image:
id: banner
keep_ratio: True
allow_stretch: True
size_hint: 1, None
source: "images/banner.png"
This code does place the picture at the bottom! But ideally, I'd like to have it stay at the bottom with full-screen width and scale in y to fit it. Is this possible?
What I want and it only works for this specific aspect ratio of the screen
When I change the width of the screen I'd like it to scale in y to fit the screen instead it keeps y constant
By default, the size_hint of any Widget is (1,1). which means that your Image will be the same size as its containing FloatLayout. So you can set values for size_hint, or you can set size_hint: None, None and then provide values for size. Also, pos_hint: {"bottom": 1} will not work, since bottom is not a supported key for pos_hint. If you want the Image at the bottom, use pos_hint: {'y':0}, but the default value for pos is (0,0), so you shouldn't even need the pos_hint: {'y':0}.
Also, if you set a size_hint to None without providing the corresponding width or height, then the default width or height (which is 100) will be used.
I think I am finally getting what you want. You can use BoxLayout instead of FloatLayout. The BoxLayout will set the size of its children to fit its available space (see documentation). So, perhaps something like this will work:
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgb: utils.get_color_from_hex("#6ec4c1")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
cols: 3
pos_hint: {"top": 0.95}
size_hint: 1, 0.05
ImageButton:
source: "images/back_arrow.png"
on_release: app.change_screen("home_screen")
Image:
source: "images/icon.png"
Label:
text: ""
Image:
id: banner
keep_ratio: True
allow_stretch: True
# size_hint: 1, None
source: "images/banner.png"
Note that setting size_hint: 1, 0.05 in the GridLayout means that 95% of the BoxLayout will be given to the banner.
How can I insert a line(seperator) between widgets, and also color border for grid views in a KV file:
TextBox is just a TextInput box with max_chars feature.
Current KV file:
<Label#Label>
text_size: self.size
valign: 'middle'
<ContactFrm>
padding: 5,5
orientation: 'vertical'
#row_default_height: '36dp'
#cols:1
#spacing: 0,0
GridLayout:
cols: 4
row_default_height: '32dp'
row_force_default: True
spacing: 10,0
size_hint_y: None
#height:34
Label:
text: 'Name'
size_hint_x: 0.5
TextBox:
id:name
max_chars:35
Label:
text: 'Contact Name'
size_hint_x: 0.5
TextBox:
id:contactname
max_chars:35
GridLayout:
cols: 4
row_default_height: '32dp'
row_force_default: True
spacing: 10,0
size_hint_y: None
#height: 36
Label:
text: 'Mobile 1'
size_hint_x: 0.5
TextBox:
id:mob1
max_chars:35
Label:
text: 'Mobile 2'
size_hint_x: 0.5
TextBox:
id:mob2
max_chars:35
Label:
text: 'Landline'
size_hint_x: 0.5
TextBox:
id:land1
max_chars:35
Label:
text: 'E-mail'
size_hint_x: 0.5
TextBox:
id:email1
max_chars:75
GridLayout:
row_default_height: '32dp'
row_force_default: True
spacing: 10,0
cols: 4
size_hint_y: None
#height: 36
Label:
text: 'Street 1'
size_hint_x: 0.5
TextBox:
id:street1
max_chars:75
Label:
text: 'Street 2'
size_hint_x: 0.5
TextBox:
id:street2
max_chars:75
Label:
text: 'Area'
size_hint_x: 0.5
TextBox:
id:area
max_chars:75
Label:
text: 'City'
size_hint_x: 0.5
TextBox:
id:city
max_chars:35
Label:
text: 'District'
size_hint_x: 0.5
TextBox:
id:district
max_chars:35
Label:
text: 'State'
size_hint_x: 0.5
TextBox:
id:state
max_chars:35
Label:
text: 'Zip Code'
size_hint_x: 0.5
TextBox:
id:zipcode
max_chars:10
BoxLayout:
I am new to both python and kivy, so above code might be a little naive, please advice where all I can improve also. Thank you.
Final Code I used with modifications, so thickness can also be provided:
<Seperator#Widget>:
id: separator
size_hint_y: None
height: 6
thickness: 2
canvas:
Color:
rgb: .24, .65, .94
Rectangle:
#pos: 0, separator.center_y
pos: self.pos[0], separator.center_y
size: separator.width, self.thickness
I am new in Kivy but I think you could add a normal Widget as a separator and draw a rectangle on its canvas.
Something like this gives me a red line - see image below:
Widget:
id: separator
size_hint_y: None
height: 6
canvas:
Color:
rgb: 1., 0., 0.
Rectangle:
pos: 0, separator.center_y
size: separator.width, 2
I think you could use canvas (or canvas.before) in GridLayout to draw a border (using rectangle or two - external with color of border and internal with color of background) but probably you will need to make (somehow) some margin to show that border.
EDIT:
First solution was with constant thickness.
For different thickness you need some calculation.
I add margin to make that calculation.
<Separator#Widget>
size_hint_y: None
thickness: 2
margin: 2
height: self.thickness + 2 * self.margin
color: 1., .0, .0
canvas:
Color:
rgb: self.color
Rectangle:
pos: self.x + self.margin, self.y + self.margin + 1
size: self.width - 2 * self.margin , self.thickness
BTW:
I use +1 in pos because it looks better (but I don't know why).
I add left and right margin.
You can also just set spacing for your grid layout and draw a rectangle as background. Like this:
GridLayout:
spacing: 10
canvas.before:
Color:
rgba: 0.3, 0.69, 0.31, 1.0
Rectangle:
size: self.size
pos: self.pos
That will look something like this: