So this is the .kv code:
Button:
id:last_message_2
text:''
font_size:18
background_normal:'textures/message.png'
size_hint_x:None
size: self.texture_size
pos_hint:{'right': 1}
padding:(9, 0)
opacity:0
on_release: root.onClick("send_rcnt2")
and what i want to do is make a custom button widget like this:
class MessageBubble(Button):
def __init__(self, **kwargs):
super(MessageBubble, self).__init__(**kwargs)
self.text = "Hello World"
self.font_size = 18
self.background_normal = "textures/message.png"
self.size_hint_x = None
self.size = self.texture_size
self.pos_hint = {'right': 1}
self.padding = (9, 0)
self.opacity = 0
and have only this left in the .kv file:
MessageBubble:
id:last_message_1
on_release: root.onClick("send_rcnt1")
but when i run the code i get a very small button with text out off bound
and when i debugged i got to know that texture_size was not updating dynamically
What can i do now?
You need to set the size in the kv rule for MessageBubble, because it needs to be updated later when self.texture_size changes. You can also do this manually by creating bindings in python.
Related
I'm still getting the hang of both kivy and python so bear with me. I have two layouts, my Graph layout is overriding the properties of my TopBar layout. Is there any way to fix this?
Here is my .kv file:
Root:
orientation: "vertical"
TopBar:
size_hint: 1,0.08
size_hint_max_y: 100
pos_hint: {"top":1}
TextInput:
text: "Search"
right: True
size_hint_max_x: 200
Button:
text: str(self.state)
Graph:
size_hint_max_y: 100
Button:
text: "test"
Here's the python file:
class Root(BoxLayout):
def __init__(self, **kwargs):
super(Root, self).__init__(**kwargs)
class TopBar(BoxLayout):
pass
class Graph(FloatLayout):
pass
class Gui(App):
def build(self):
return Root()
Gui().run()
Thanks!
kv file
Move size_hint_max_y: 100 from under Graph: to under Button:.
In the snippet, color was added to illustrates the Graph's canvas.
Snippet
Graph:
canvas.before:
Color:
rgba: 0, 0, 1, 0.5 # 50% blue
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_max_y: 100
text: "test"
Output
I'm attempting to implement a recycle view widget in my kivy program. Its working fine, responding to the on press event etc but when it draws it adds an extra row that does not fit the formatting of the others. Here is the relevant part of my code, there is a lot so I only included this but I'll post more if needed. Any help is appreciated. I like kivy but this is def the strangest widget I have used in it.
Output
py file
class MessageBox(Popup):
def popup_dismiss(self):
self.dismiss()
class SelectableButton(RecycleDataViewBehavior, Button):
index = None
def refresh_view_attrs(self, rv, index, data):
""" Catch and handle the view changes """
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_press(self):
self.parent.selected_value = 'Selected: {}'.format(self.parent.btn_info[int(self.id)])
def on_release(self):
MessageBox().open()
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout):
selected_value = StringProperty('')
btn_info = ListProperty(["ButtonText" for x in range(0,2)])
class MainScreen(RecycleView):
rv_layout = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.data = [{'text': "Button" + str(x), 'id': str(x)} for x in range(0,2)]
kv file
<MessageBox>:
title: 'Popup Message Box'
size_hint: None, None
size: 400, 400
BoxLayout:
orientation: 'vertical'
#Label:
#text: app.root.rv_layout.selected_value
Button:
size_hint: 1, 0.2
text: 'OK'
on_press:
root.dismiss()
<SelectableButton>:
orientation: 'horizontal'
Button:
size_hint_x: .10
text: '+'
#font_size: 50
texture_size: self.width, self.height
size: self.texture_size
Button:
size_hint_x: .90
text: root.text
#font_size: 50
texture_size: self.width, self.height
size: self.texture_size
<MainScreen>:
pos_hint: {'x': 0, 'y': .11}
size_hint: 1, .70
viewclass: 'SelectableButton'
SelectableRecycleBoxLayout:
id: layout
default_size_hint: 1, 1
#size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Problem - Extra Buttons
In Python file, SelectableButton is a class of Button widget but in kv file, SelectableButton is a class of BoxLayout widget with two Buttons. Button widget does not has attribute, orientation but BoxLayout has this attribute. Due to the widget inheritance mismatch, Kivy used the definition from Python script.
As for visualization, I have added background color (red, and blue) to the two Buttons defined in the kv file. From the print screen below, the extra buttons are from the kv file.
py file
class SelectableButton(RecycleDataViewBehavior, Button):
kv file
<SelectableButton>:
orientation: 'horizontal'
Button:
...
Button:
...
Solution
Either change the Python file or kv file. In the example, the kv file is changed.
kv file
<SelectableButton>:
size_hint_x: .90
size: self.texture_size
Output - Visualization of original Kivy App
Output - Fixed Kivy App
This is a follow up to a previous question I've asked on how to change the properties of a kivy widget (update a kivy label text in another class). I've been trying to figure out why the temperature reading on the Menuscreen updates but within the Mashscreen, the text doesn't update. It looks like the values are being passed to eh temperature1def method but the screen widget doesn't update.
Also, is it better to send the value using
Mashscreen().temperature1def(self.test_temp)
or is it better practice to use
self.stuff_p.text = str(self.test_temp) + u'\u00B0F'
within the MenuScreen to update the label within the Mashscreen? Thanks in advance.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.properties import ObjectProperty
from kivy.clock import Clock
sm = """
ScreenManager:
#Handling the gesture event.
id:manager
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 0.5
Rectangle:
pos: 0,0
size: 800, 480
MenuScreen:
id:MenuScreen
name:'MenuScreen'
manager: manager
Mashscreen:
id:Mashscreen
name: 'Mashscreen'
manager: manager
<MenuScreen>:
stuff_r: mainel1temp
Button:
text: "Go to mashscreen"
on_release:
root.manager.current = "Mashscreen"
Label:
id: mainel1temp
text:'0'
size_hint: None, None
size: 75,50
pos: 295,308
font_size:'22sp'
text_size: self.size
halign: 'left'
valign: 'middle'
<Mashscreen>:
stuff_p: temperature1
FloatLayout:
Label:
id: temperature1
text:'100'
size_hint: None, None
size: 75,50
pos: 50,275
font_size:'22sp'
text_size: self.size
halign: 'left'
valign: 'middle'
"""
class MenuScreen(Screen):
test_temp = 99
stuff_r = ObjectProperty(None)
def __init__(self,**kwargs):
super(MenuScreen,self).__init__(**kwargs)
Clock.schedule_interval((self.read_temp), 1)
#self.read_temp(1)
def read_temp(self, dt):
self.test_temp += 1
self.stuff_r.text = str(self.test_temp) + u'\u00B0F'
Mashscreen().temperature1def(self.test_temp)
#self.parent.ids.Mashscreen.stuff_p.text = str(self.test_temp) + u'\u00B0F'
class Mashscreen(Screen):
stuff_p = ObjectProperty(None)
def __init__(self, **kwargs):
super(Mashscreen, self).__init__(**kwargs)
def temperature1def(self, temp1):
print(temp1)
self.stuff_p.text = str(temp1)
class TestApp(App):
def build(self):
return Builder.load_string(sm)
if __name__ == '__main__':
TestApp().run()
First…
Mashscreen().temperature1def(self.test_temp)
This doesn't call the temperature1def method on your Mashscreen instance in the UI, instead, it creates a new Mashscreen instance, calls the method on it, and then let this object be garbage collected by python. If you want to update your UI, you need to get a reference to the widget you want to update.
You define your Mashscreen in the root rule of your application, so you can get it by its id in this object.
App.get_running_app() will return a reference to your currently running app, which has a root attribute, which is your root widget, any widget at the root of a rule can use its ids attribute to get a reference to any id defined in its scope, so.
App.get_running_app().root.ids.Mashscreen.temperature1def(self.test_temp)
will certainly be more like what you actually want to do.
Now, regarding the question about how to do it best in python kivy, i find that it's cleaner to do something like.
App.get_running_app().root.ids.Mashscreen.temperature = self.test_temp
and then to change your Mashscreen class to have a temperature NumericProperty, and to change your kv rule to use this value in the Label.
<Mashscreen>:
stuff_p: temperature1
FloatLayout:
Label:
id: temperature1
text: '%s' % root.temperature
size_hint: None, None
size: 75,50
pos: 50,275
font_size:'22sp'
text_size: self.size
halign: 'left'
valign: 'middle'
im currently looking into kivy to start with crossplatform development. i have a bit of python experience (but basic) and now wanted to code a little game in kivy to get into. i probably wont finish this but i like learning stuff while doing it with something im intrested in.
Anyway my "App" is supposed to be seperated in two seperate "screens" the top one is only used for displaying stuff and the all interactive stuff is controlled from the bottom "screen".
Now i want to display some text in old school way by getting it written letter by letter to the screen.
This is working fine but for some reason the Label widget is only updated on screen if i call the "print_something" function from the top screen, if i call it from the bottom screen the function is indeed called but the Label widget wont change on screen.
Am i doing something wrong?
Here is a stripped version of the code:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.clock import Clock
Builder.load_string('''
<MainUI>:
orientation: 'vertical'
# both these variables can be the same name and this doesn't lead to
# an issue with uniqueness as the id is only accessible in kv.
<Screen1>:
print_txt: print_txt
layout: layout
RelativeLayout:
id: layout
pos: 0, 400
size: 480, 400
Button:
pos: 0, 200
size_hint: (1, 0.2)
text: "Test Print"
on_press: root.print_something('TEST PRINT FROM SCREEN1')
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
Label:
id: print_txt
padding_x: 10
markup: True
text_size: self.size
halign: 'left'
valign: 'top'
size_hint: (1, 0.2)
text: ""
<Screen2>:
btn1: btn1
RelativeLayout:
pos: 0, 0
size: 480, 400
Button:
id: btn1
pos_hint: {'x': .15, 'center_y': .5}
size_hint: (0.7, 0.5)
text: "Test Print"
on_press: root.print_text()
''')
class Screen1(Widget):
print_txt = ObjectProperty(None)
layout = ObjectProperty(None)
def print_something(self, string):
print 'Function called...'
self.print_txt.text = ''
counter = [0]
string_len = len(string)
def print_step(dt):
if counter[0] == string_len:
return False
else:
self.print_txt.text += string[counter[0]]
counter[0] = counter[0] + 1
Clock.schedule_interval(print_step, 2.0/60.0)
print 'Function End..'
class Screen2(Widget):
btn1 = ObjectProperty(None)
def __init__(self):
super(Screen2, self).__init__()
def print_text(self):
print 'Trying to print Text from Screen2 to Screen1'
target = Screen1()
target.print_something('TEST PRINT FROM SCREEN2')
class MainUI(Widget):
def __init__(self):
super(MainUI, self).__init__()
self.screen1 = Screen1()
self.add_widget(self.screen1)
self.add_widget(Screen2())
class MainApp(App):
def build(self):
Window.size = (480, 800)
return MainUI()
if __name__ == '__main__':
MainApp().run()
Your Screen2 print_text method creates a new Screen1 instance, which is modified but not displayed anywhere so you don't see anything change.
You could change the call to instead something like
on_press: root.parent.screen1.print_text()
...to access the print_text function of the Screen1 instance that you actually want to update.
I'm using Kivy, a Python Library, and i'm having trouble getting a scroll view to work, and organizing it into a .kv file.
I have a big system that's broken up into many .py and .kv files.
I am also using kivy's screen manager
ui_manager.py
#ui_manager.py
class UIManager():
_ScreenManager = None
def __init__(self, inScreenManager):
self.ScreenManager = inScreenManager # The main app constructs the manager, sends to me, then returns it as the root widget.
main.py
#main.py
class MyApp(App):
def build(self):
screenManager = ScreenManager()
uiManager = ui_manager.UIManager(screenManager)
return screenManager
Obviously I ommited a little code, but this is almost exactly what happens.
One of the screns needs to scroll. It will have a long graphic and many buttons.
The Kivy documentation, as usual, only tells me how to do it via code, NOT via the kivy language (.kv files)
http://kivy.org/docs/api-kivy.uix.scrollview.html
I want a class, OrangeWidget, to hold the scrolling widget, so I can play with its data later on.
Here is my best attempt at getting an organized scrollview working
orange_widget.py
#orange_widget.py
class OrangeWidget(Screen):
pass
class OrangeGraphic(Widget):
pass
Orange.kv
<OrangeLineWidget>
ScrollView:
size_hint: (None, None)
size: (400, 1200)
OrangeLineGraphic:
pos: root.pos
<OrangeGraphic>
canvas:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.center_x - 15, 0
size: 30, self.height * 2
Label:
text: "Hello"
I know it's a lot, and it's not looking well organized already, but i'm just trying to figure out how to get the dang thing working properly.
Here is the current result: It won't scroll, and for whatever reason it's been "boxed" to the right, instead of taking up the full screen
as answered on the ML, here you don't define the Label pos, your OrangeGraphic being a simple widget, not a layout, you need to do it:
<OrangeGraphic>
canvas:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.center_x - 15, 0
size: 30, self.height * 2
Label:
text: "Hello"
pos: root.pos
size: root.size
Looks like the trick, for this particular "sliding" screen, was to use a "Relative Layout"
https://groups.google.com/forum/#!topic/kivy-users/RwuI8QGm3fw
Here is the updated code:
orange_widget.py
class OrangeWidget(Screen):
def __init__(self, **kwargs):
super(OrangeWidget, self).__init__(**kwargs)
scrollView = ScrollView(size_hint=(1, 1))
# add custom widget into that layout
customWidget = OrangeGraphicWidget(height=1200, size_hint_y=None)
#layout.bind(minimum_height=layout.setter('height'))
scrollView.add_widget(customWidget)
self.add_widget(scrollView)
class OrangeGraphicWidget(RelativeLayout):
pass
OrangeWidget.kv
<OrangeWidget>
<OrangeGraphicWidget>
canvas:
Color:
rgba: 1, .5, 0, 1
Rectangle:
pos: self.center_x - 15, 20
size: 30, self.height - (self.height / 10)
Button:
text: "Button 1"
pos: root.pos
size_hint: (None, None)
Button:
text: "Button 2"
pos_hint: {'center_x': .5, 'center_y': .95}
size_hint: (None, None)