I am trying to use the popup widget in Kivy, but everytime I run the code, the popup just has 2 smaller versions of the widget on the main screen.
This is my Python code (the .py file):
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.widget import Widget
class Layout(Widget):
pass
class KivyTestApp(App):
def build(self):
return Layout()
app = KivyTestApp()
app.run()
and this is my Kivy code (the .kv file):
#: import Factory kivy.factory.Factory
<MyPopup#Popup>:
title: 'Test'
size_hint: None, None
size: 400, 400
<Layout>:
Button:
id: but
size: root.width, root.height
background_normal: ''
background_color: .5, .7, .9, 1
text: 'Press me to open the popup'
pos: 0, 0
on_press: Factory.MyPopup().open()
This creates a window that looks like this:
And the popup looks like this:
As you can see, I have added no content to the popup, yet Buttons still appear! If anyone could help me, that would be great, and thanks in advance!
Kivy already has an internal widget called Layout, which is subclassed all over the place. Try naming your own widget something else.
Related
I have an issue with an kv file and can't solve it. In the app, I use different screens and every screen should have the same menu bar. The app is provided for Android, but in the future I want to use it on Windows too. For Android, the menu bar should be at the bottom of the screen. For Windows, I want to place the menu bar at the top of the screens and there is my issue: the menu bar at the top doesn't work.
I've created a simple example code, to reproduce the issue.
Here is the a simple Python code. There is only one function to switch the screens:
import kivy
kivy.require('1.10.1')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuBar( Button ):
pass
class Screen1( Screen ):
pass
class Screen2( Screen ):
pass
class ScreenManager( ScreenManager ):
pass
class TestscreenApp( App ):
def switch_screen( self, screen ):
self.root.current = screen
if __name__ == '__main__':
TestscreenApp().run()
And here is the kv file. There are 2 screens and a menu bar. I want to reuse the menu bar on different screens.
As you can see, the menu bar on the first screen is on the bottom of the screen. On the second screen, I placed the menu bar at the top and nothing will be displayed :-(
If I place the menu bar on the second screen at the bottom, it works. If I place the menu bar on the first screen at the top, this also display me nothing.
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
ScreenManager:
id: screen_manager
Screen1:
name: "screen_1"
screen_manager: "screen_manager"
Screen2:
name: "screen_2"
screen_manager: "screen_manager"
<Screen1>:
name: "screen_1"
GridLayout:
rows: 2
GridLayout:
cols: 2
Button:
text: 'Test 1'
font_size: 50
Button:
text: 'Test 2'
font_size: 50
MenuBar:
<Screen2>:
name: "screen_2"
GridLayout:
rows: 2
MenuBar:
Button:
text: 'Test 3'
font_size: 50
on_release:
app.switch_screen( "screen_1" )
<MenuBar>:
name: "menu_bar_top"
GridLayout:
cols: 2
size: root.width, root.height
Button:
text: 'Menu 1'
font_size: 20
on_release:
app.switch_screen( "screen_1" )
Button:
text: 'Menu 2'
font_size: 20
on_release:
app.switch_screen( "screen_2" )
I tried many things and used the search, but I can't find anything similar. I also tried to use BoxLayout instead of GridLayout, but I can't find a solution.
What I am doing wrong? Can anyone explain me this strange behavior?
The problem is that you are defining the MenuBar as extending Button, then using it as a widget container. A Button is not intended to be used as a container. A better choice would be one of the Layout classes. Try changing:
class MenuBar( Button ):
pass
to:
class MenuBar( RelativeLayout ):
pass
You made my day! That is a solution for my problem.
I did not think to change my Python code. All the time I've changed my kv file to fix the issue.
Thanks
I'am new in Kivy and have follow problem (Environment is Python 3.7 with Kivy-1.11.1.):
I need a navigation area and a view area (=ViewScreen). With the navigation area i change the view area (change of kv-files - look later at 'def next_screen'). My problem is, that i can't interact with widgets (e.g. 'lblTest') in the view area.
I use follow files:
testGUI.py (= GUI Application)
testGUIRoot.kv (= RootWidget as kv-file)
testGUIBtn1.kv (= view area 1 as kv-file)
testGUIBtn2.kv (= view area 2 as kv-file)
The GUI Application is simple and starts the GUI and change the view area.
testGUI.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
class RootWidget(BoxLayout):
# runs select application
def startApplication (self, instance):
print(self.lblTest)
class mainGUI(App):
def build(self):
# loading the content of root.kv
self.root = Builder.load_file('testGUIRoot.kv')
def next_screen(self, screen):
#Clear container and load the given screen object from file in kv folder.
filename = screen + '.kv'
# unload the content of the .kv file
# reason: it could have data from previous calls
Builder.unload_file(filename)
# clear the container
self.root.container.clear_widgets()
# load the content of the .kv file
screen = Builder.load_file(filename)
# add the content of the .kv file to the container
self.root.container.add_widget(screen)
if __name__ == '__main__':
'''Start the application'''
mainGUI().run()
I use follow kv-files:
testGUIRoot.kv:
#:kivy 1.11.1
RootWidget:
container: container
orientation: 'horizontal'
# Navigation
BoxLayout:
orientation: 'vertical'
size_hint: (0.35, 1)
Button:
text: 'testButton1'
on_release: root.startApplication(self,)
on_press: app.next_screen('testGUIBtn1')
Button:
text: 'testButton2'
on_release: root.startApplication(self,)
on_press: app.next_screen('testGUIBtn2')
# ViewScreen
BoxLayout:
size_hint: (0.65, 1)
id: container
orientation: 'vertical'
padding: 0
spacing: 3
Label:
text: 'no data'
color: (0.667,0.667,0.667,1)
font_size: 14
bold: True
testGUIBtn1.kv:
#:kivy 1.11.1
Label:
id: lblTest
text: 'Button 1'
color: (0.667,0.667,0.667,1)
font_size: 14
bold: True
testGUIBtn2.kv:
#:kivy 1.11.1
Label:
id: lblTest
text: 'Button 2'
color: (0.667,0.667,0.667,1)
font_size: 14
bold: True
Follow error appears:
AttributeError: 'RootWidget' object has no attribute 'lblTest'
Have you a solution to interact with the Object 'lblTest'? For example like self.lblTest.text = 'Test-Text'.
Thank you in advance
I have been working with Kivy just this week, also as a new user.
The thing I have learned is to define properties on your RootWidget, just as the labels you already defined in the .kv files. This 'links' the layout and the Python code to eachother.
First of all you need to import the Kivy ObjectProperty by adding:
from kivy.properties import ObjectProperty
Next up is to declare the property on your RootWidget class.
You can add lblTest = ObjectProperty(None) right after the class-declaration.
The top of your file testGUI.py should look like this then:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
class RootWidget(BoxLayout):
# Link the layout objects
lblTest = ObjectProperty(None)
# runs select application
def startApplication (self, instance):
print(self.lblTest)
The page that really helped me with this is https://techwithtim.net/tutorials/kivy-tutorial/object-properties/
A little sidenote is it would be best to keep your id attributes fully unique.
I found the solution
Content of 'def next_screen' of mainGUI(App) to 'def startApplication'. Now i can change widgets in object oScreen or using the object in other python libs.
def startApplication (self, instance, sScreen):
filename = sScreen + '.kv'
# unload the content of the .kv file
# reason: it could have data from previous calls
Builder.unload_file(filename)
# clear the container
self.container.clear_widgets()
# load the content of the .kv file
oScreen = Builder.load_file(filename)
# add the content of the .kv file to the container
self.container.add_widget(oScreen)
print(oScreen.ids.lblTest.text)
The follow should be added in kv-files testGUIBtn1.kv, testGUIBtn2.kv:
RootWidget:
In kv-file testGUIRoot.kv you have change on_release to
on_release: root.startApplication(self,'testGUIBtn1')
I'm developing a python app using Kivy.
Sometimes when I'm launching other python scripts without kivy imports a blank Kivy window opens randomly without any reason.
Is this a bug? Or am I missing something on the app closing?
I've seen this strange behaviour only under Windows (8), Python 2.7.
The window is completely white and seems not responding (I know it's a Kivy window from the little icon on the top-left corner), few seconds later the system says python.exe has stopped working.
This is not a bug. You have to add child widgets e.g. button, label, textinput, etc. into your root widget. Please refer to example below for details.
Example
main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
class MyRootWidget(FloatLayout):
pass
class TestApp(App):
title = "Kivy Demo"
def build(self):
return MyRootWidget()
if __name__ == '__main__':
TestApp().run()
test.kv
#:kivy 1.10.0
<MyRootWidget>:
canvas:
Color:
rgba: [1, 1, 1, 1] # White color
Rectangle:
size: self.width, self.height
BoxLayout:
orientation: "vertical"
Label:
font_size: 50
text: "[color=ff3333][b]Hello[/b][/color]"
markup: True
Label:
font_size: 20
text: "[color=3333ff]World[/color]"
markup: True
Output
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)
I'm trying to code a custom popup in kivy for picking a color from the ColorPicker widget. Right now i'm trying to hook up an 'OK' button to dismiss the popup, but it's not working. The popup up displays correctly, but when i click OK, nothing happens. The popup continues on screen.
Here's my python code.
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.colorpicker import ColorPicker
class PaintWindow(BoxLayout):
pass
class CPopup(Popup):
def on_press_dismiss(self, *args):
self.dismiss()
return False
class PixPaint(App):
def build(self):
pw = PaintWindow()
return pw
if __name__ == '__main__':
PixPaint().run()
Here's the KV code.
<PaintWindow>:
orientation: 'vertical'
CPopup:
<CPopup>:
title: 'Pick a Color'
size_hint: 1.0, 0.6
id: cpopup
BoxLayout:
orientation: 'vertical'
ColorPicker:
size_hint: 1.0, 1.0
Button:
text: 'OK'
size_hint: 1.0, 0.2
on_press: cpopup.on_press_dismiss()
Any help is much appreciated. Sorry for all the code! :)
The reason the popup is not closing is because you are adding it directly to your PaintWindow here:
<PaintWindow>:
orientation: 'vertical'
CPopup:
Instead of actually calling the method open() of Popup. So,
1 - Remove the CPopup: from the kv file
<PaintWindow>:
orientation: 'vertical'
#CPopup:
...
2 - Call the open() method somewhere else. As a good example in the build(self) of PixPaint
class PixPaint(App):
def build(self):
pw = PaintWindow()
popup = CPopup();
popup.open()
return pw
Just in case, a few extras:
You can also get rid off the id: cpopup on the the definition of <CPopup>: and use root instead (on_press: root.on_press_dismiss()).
Moreover, you can get rid off the on_press_dismiss() and do on_press: root.dismiss() instead.