I have my simple python code:
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.relativelayout import RelativeLayout
Builder.load_file('Matrixkivy.kv')
class MyLayout(Widget):
pass
class MatrixCalc(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
MatrixCalc().run()
And simple .kv code:
<MyLayout>
GridLayout:
size_hint: root.width, root.height
Button:
text: "Button1"
Button:
text: "Button2"
I want to get a GridLayout which is of size of the entire app and two buttons, which both take half of it. However, app displays all things that the app contain in the bottom left corner. How to fix that?
The main problem is that you are using the base Widget class as a container. You can do that, but the Layout classes already have the code to handle things like size_hint and pos_hint. One fix for your code is to replace:
class MyLayout(Widget):
pass
with:
class MyLayout(FloatLayout):
pass
You should also remove the line:
size_hint: root.width, root.height
Size_hint values should be numbers typically in the range 0-1. And add a line that defines either rows or cols for the GridLayout, so your kv could look like:
<MyLayout>
GridLayout:
cols: 1
Button:
text: "Button1"
Button:
text: "Button2"
Since you are using GridLayout as a child of MyLayout, you can just make MyLayout extend GridLayout, and then you can eliminate the GridLayout line from your kv. With this approach, your MyLayout class would look like:
class MyLayout(GridLayout):
pass
and the corresponding kv:
<MyLayout>
cols: 1
Button:
text: "Button1"
Button:
text: "Button2"
Related
I'm following a tutorial on youtube and when I run the code, the window shows the labels half off the screen on the left-bottom side. I uploaded a screenshot of the window.
The .kv file is:
<MyGrid>
GridLayout:
cols: 1
GridLayout:
cols: 2
Label:
text: "Name: "
TextInput:
multiline:False
Label:
text: "Email: "
TextInput:
multiline:False
Button:
text: "Submit"
And the py file is:
from kivy.app import App
from kivy.uix.widget import Widget
class MyGrid(Widget):
pass
class MyApp (App):
def build(self):
return MyGrid()
if __name__ == "__main__":
MyApp().run()
You are trying to use the base Widget class as a container, but it was not designed for that use. Try just using some Layout class as the base for MyGrid, like this:
class MyGrid(FloatLayout):
pass
Note that this will result in a GUI that is a FloatLayout that contains a GridLayout which contains another GridLayout. If that is not your intention, consider changing the base class of MyGrid to GridLayout and eliminate one or two of the contained GridLayouts.
How can I display two labels side-by-side in a Kivy StackLayout?
Consider the following code
#!/usr/bin/env python3
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.app import App
KV = """
StackLayout:
orientation: 'lr-tb'
Label:
text: "Hello"
Label:
text: "World"
"""
class MyApp(App):
def build(self):
return Builder.load_string( KV )
MyApp().run()
I'm trying to make two text labels appears side-by-side. Originally I was using a BoxLayout and GridLayout, but I found that those would make the width of each widget coorespond to the width of the app. Whereas I want:
The first label to be only as-wide as it needs to be for the text it contains
The second label to be placed immediately next to first label, where the only gap between the text is the layout's spacing.
Unfortunately, the above code doesn't even display a second label -- it's just totally not there. Why?
How can I display two labels right next to each-other, without kivy adding additional spacing or mysteriously not displaying my second label at all when using the StackLayout?
To make this work as expected, you have to:
override size_hint to None and
set the size of the widget to its texture_size (which is the actual pixels needed to render the font -- but you may actually want to pad this with some pixels)
For example
#!/usr/bin/env python3
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.app import App
KV = """
StackLayout:
orientation: 'lr-tb'
Label:
text: "Hello"
size: self.texture_size
size_hint: None, None
Label:
text: "World"
size: self.texture_size
size_hint: None, None
"""
class MyApp(App):
def build(self):
return Builder.load_string( KV )
MyApp().run()
I'm trying to learn how to use multiple kv files in one project. But I ran into this issue:
Here's the screeenshot of my issue.
.py
from kivy.lang.builder import Builder
from kivymd.app import MDApp
Builder.load_file("cm_dd_btns.kv")
kv = """
#:import hex kivy.utils.get_color_from_hex
MDScreen:
md_bg_color: hex("#07074D")
DD:
"""
class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)
MyApp().run()
.kv file
<DD#MDBoxLayout>
cols: 1
spacing: 1
orientation: "vertical"
Button:
text: "First btn"
Button:
text: "2nd btn"
I tried modify the size of the layout and widget in both the files. But it's not making both buttons visible.
Can someone explain how to fix this and why this is happening?
as stated in the title - I'm stuck. I've been playing with the code around and everything works as long as I keep ScreenManager and Popup separate. Once combined - they refuse to cooperate. Anyway, here is the simple app that shows the problem I'm having.
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import Screen, ScreenManager
class First(GridLayout,Screen):
def show_popup(self):
Popp().open()
pass
class Second(Screen):
pass
class Popp(Popup):
pass
class ScreenManagement(ScreenManager):
pass
app = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return app
if __name__ == "__main__":
MainApp().run()
And main.kv file
ScreenManagement:
First:
Second:
<First>:
name:"First"
rows: 2
Button:
text: "FirstButton"
on_release: app.root.current = "Second"
Button:
text: "Show popup"
on_release: root.show_popup()
<Second>:
name:"Second"
Button:
text: "BUTTON"
on_release: app.root.current = "First"
<Popp>:
title: "testing"
text: "Hello world"
size_hint: None,None
size: 400,400
auto_dismiss: False
Button:
text: "Okay"
on_press: root.dismiss()
App starts, first and second screen are working but when trying to get popup up I end up with:
kivy.uix.popup.PopupException: Popup can have only one widget as content
Somehow Screen is seen as a widget inside of Popp? Or am I terribly misinterpreting kivy docs?
It's a bug with loading kv file, it should throw an exception in this case.
What you are doing in the code is loading the kv file twice, what causes some weird behavior. Just delete the Builder.load_file(..) and it will work. The file is going to be loaded automatically.
Also, never do double subclassing of widgets like class First(GridLayout, Screen) as it might lead to some problems. Instead, create a grid layout inside the screen.
Put the elements in the Popup inside a layout, for example: Boxlayout.
Here's what I mean:
<Popp>:
title: "testing"
BoxLayout:
orientation: 'vertical'
size_hint: None,None
size: 400,400
Label:
text: "Hello world"
Button:
text: "Okay"
on_press: root.dismiss()
I have same problem with using kivy Builder.load_file and Popup, they dont work together.
the solution is simple, build popup in python code side. this is a loading popup example:
python:
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
import time, threading
buildKV = Builder.load_file("example.kv")
class ExampleApp(App):
def show_popup(self):
content = BoxLayout(orientation= "vertical")
image=Image(source= 'files/loading.gif', anim_delay= 0)
label=Label(text= 'Model is Running.\nBe Patient Please.')
content.add_widget(image)
content.add_widget(label)
self.popup = Popup(title='Model is Running.',
size_hint=(.250, .785),
content=content, auto_dismiss=False)
self.popup.open()
def process_button_click(self):
# Open the pop up
self.show_popup()
# Call some method that may take a while to run.
# I'm using a thread to simulate this
mythread = threading.Thread(target=self.something_that_takes_5_seconds_to_run)
mythread.start()
def something_that_takes_5_seconds_to_run(self):
thistime = time.time()
while thistime + 10 > time.time(): # 5 seconds
time.sleep(1)
# Once the long running task is done, close the pop up.
self.pop_up.dismiss()
if __name__ == "__main__":
ExampleApp().run()
kivy:
BoxLayout:
Button:
height: 40
width: 100
size_hint: (None, None)
text: 'Click Me'
on_press: app.process_button_click()
I created a class for a Popup and set the title property in the kv file.
When the popup shows, it does not have the title as in the kv file, but instead shows No Title as if it was never set.
It is exactly the same problem as here, but I do not understand from this link what the problem is or how to make it work:
https://github.com/kivy/kivy/issues/751
I understand how to do this using IDs in kv lang, but that only works if the Popup is put as a child widget of the root widget (ex. MainUI). Then I can link an instance of a python class to a widget in the kv file.
But then the popup displays as part of the root widget.
What I want to do, is instantiate a new instance of the popNewDB class when the New button is clicked and have this instance use the values such as "title" in the KV file.
Can you please explain how to do this?
Here is my code:
py file:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
class popNewDB(Popup):
pass
class MainUI(Widget):
pop = ObjectProperty(popNewDB())
def showpopup(self):
self.pop.open()
class VerseReminder(App):
def build(self):
return MainUI()
if __name__ == '__main__':
VerseReminder().run()
kv file:
#:kivy 1.9.1
<popNewDB>
title: 'Hallo'
<MainUI>
Label:
pos: root.center_x - self.width/2,root.center_y + 200
text: "Quote Reminder"
BoxLayout:
size_hint: None,None
width: 400
height: 200
pos: root.center_x-200,root.center_y-50
orientation: 'vertical'
spacing: 20
Button:
size_hint: 1,1
text: "New..."
on_press: root.showpopup()
Button:
size_hint: 1,1
text: "Open..."
Button:
size_hint: 1,1
text: "Quit"
At the time pop = ObjectProperty(popNewDB()) is evaluated, the rules haven't been loaded, so only a barebones Popup will be created. Instead, you could do this:
class MainUI(Widget):
pop = ObjectProperty()
def showpopup(self):
if self.pop is None:
self.pop = PopNewDB()
self.pop.open()
Here, the first time the button is pressed, a new instance of PopNewDB will be created and stored in self.pop.
(NB: I renamed the Popup subclass to start with a Capital Letter, to be consistent with language standards and kivy expectations)