Kivy: button on_press switch to next tab using kivy builder - python-2.7

I'm new to python and kivy so please be gentle :)
I have 3 tabs and want the app to show the next tab when I press button1 and button2, and to shutdown itself when button3 is pressed. I would like to use kivy builder to do this, if possible.
Please help :/
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
class Root(TabbedPanel):
pass
Builder.load_string('''
<Root>
do_default_tab: False
size_hint: 1, 1
post_hint: {'center_x': .5, 'y': .5}
do_default_tab: False
TabbedPanelItem:
text: 'Step 1'
FloatLayout:
Button:
id: button1
size_hint: .10, .10
pos: 1350, 40
orientation: 'vertical'
text: 'Next!'
on_press: print("go to next step") #need help
TabbedPanelItem:
text: 'Step 2'
FloatLayout:
Button:
id: button2
size_hint: .10, .10
pos: 1350, 40
orientation: 'vertical'
text: 'Next!'
on_press: print("go to next step") #need help
TabbedPanelItem:
text: 'Step 3'
FloatLayout:
Button:
id: button3
size_hint: .10, .10
pos: 1350, 40
orientation: 'vertical'
text: 'The End.'
on_press: print("exiting") #need help
''')
class TabbedPanelApp(App):
def build(self):
return Root()
if __name__ == '__main__':
TabbedPanelApp().run()

TabbedPanel.switch_to seems pretty straightforward to me. Just use it like this in those three on_press:
root.switch_to(root.tab_list[1])
root.switch_to(root.tab_list[0])
root.switch_to(root.tab_list[2])
tab_list is in "reversed" order - the last added TabbedPanelItem is the first item in list.

Related

Bind kivy properties from one screen to another screen

newbie here trying to test my hand on something new.I'm trying to display slider value from one screen on another screen. The screen I want the value to be displayed in has multiple screens embedded in it. the first picture is the first screen.
home screen that contains multiple screens
below is the code for this screen:
<Thermostat>:
BoxLayout:
orientation: 'horizontal'
cols: 2
Label:
id: Thmo
font_size: "11sp"
text: "INSIDE: 50"
Label:
text: "More Info"
font_size: "11sp"
<Weather>:
BoxLayout:
orientation: 'horizontal'
cols: 2
Label:
id:Temp
text: "OUT TEMP: "+ root.checkWeather()
font_size: "11sp"
Label:
id: Locale
text: root.locale
font_size: "11sp"
The next screen which is the command screen is here below, i want the slider value from this screen to be updated in the home screen. I have tried using a global variable called TEMP but it did not work. any help would be appreciated.
command screen
below is the code for the command screen:
<Temperature>:
BoxLayout:
cols: 3
Label:
text: 'THERMOSTAT'
Slider:
id: temp_slider
min: 40
max: 100
value: 40
step: 1
on_value: app.TEMP = str(temp_slider.value)
Label:
id: value
text: str(temp_slider.value)
<Vent>:
BoxLayout:
size_hint_y: None
height: '48dp'
cols: 3
Label:
text: 'VENT'
Button:
id: state
text: 'Open'
on_press: root.Open(state)
Label:
id: cmdErr
from kivy.app import App
value = App.get_running_app().root.ids.SCREENCONTROLLER.get_screen('SCREENAMEHERE').ids.CHILDWIDGETID.
Basically, you do your usual id traveling but you start from the very top of the running app and work downwards.
'root' here is the widget that is returned in the Apps Build Method. You haven't provided that code, so I'm assuming you returned the Screen Controller.
Once you get to the screen controller, you can use its get_screen method by entering the string name you gave to the screen you want to go to, then from their you find it through ids as if you were on that screen.

Kivy Python 2.7 - Put a layout inside of another layout

I have been looking into this question for a while, and I cannot seem to find the solution anywhere. I want to put a table inside of this page I have in my app, the page is a FloatLayout and I was wondering if it was possible to put a table inside of the FloatLayout.
Yes, it is possible to put a table inside of the FloatLayout. In the following example, we have a GridLayout inside a FloatLayout. As for a table, you might want to use RecycleView.
Example
main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
class RootWidget(FloatLayout):
pass
class TestApp(App):
title = "GridLayout Inside FloatLayout Demo"
def build(self):
return RootWidget()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
<RootWidget>:
size: 300, 300
GridLayout:
cols: 3
row_force_default: True
row_default_height: 40
Button:
text: "Row 1 Col 1"
size_hint_x: None
width: 100
Label:
text: "Row 1 Col 2"
size_hint_x: None
width: 100
Button:
text: "Row 1 Col 3"
Button:
text: "Row 2 Col 1"
size_hint_x: None
width: 100
Label:
text: "Row 2 Col 2"
size_hint_x: None
width: 100
Button:
text: "Row 2 Col 3"
Output

Can't close ActionOverflow directly

I have 2 Screens in my app (ScreenManager). One of them has ActionBar with ActionOverflow. I have button that should change current Screen and close ActionOverflow, but the Screen changes and ActionOverflow remains open until
I tap the screen in another place.
Here some code:
# .kv
ScreenManager:
id: ScrMan
Screen:
name: 'scr1'
BoxLayout:
orientation: 'vertical'
ActionBar:
ActionView:
ActionOverflow:
id: ActOv
#some buttons
ActionButton:
text: 'some text'
on_press:
ActOv.is_open = False
#I also tried: is_open = False; self.parent.is_open = False; with the same result
ScrMan.current = 'scr2'
Screen:
name: 'scr2'
#some cool stuff here
How I can change the screen and close ActionOverflow list?
Edit: As you have version 1.9.1 (or older master branch, there was this fix missing. Changing actionbar.py in <python dir>/Lib/site-packages/kivy/uix/actionbar.py brings the default behavior to the old version.
The dropdown should close on its own by default. Maybe there's something wrong in your code e.g. placing ActionButton into ActionOverflow as a widget or maybe something else. Try this:
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
#:import Clock kivy.clock.Clock
#:import partial functools.partial
<Test>:
ScreenManager:
id: ScrMan
Screen:
name: 'scr1'
ActionBar:
pos_hint: {'top': 1}
ActionView:
ActionPrevious:
ActionOverflow:
ActionButton:
text: 'some very very long text'
ActionButton:
text: 'some very very long text'
ActionButton:
text: 'some very very long text'
ActionButton:
text: 'some very very long text'
ActionButton:
text: 'some very very long text'
ActionButton:
text: 'try this button!'
on_press:
ScrMan.current = 'scr2'
Clock.schedule_once(partial(root.change_scr, ScrMan), 1)
Screen:
name: 'scr2'
Label:
text: 'second'
''')
class Test(BoxLayout):
def change_scr(self, man, *dt):
man.current = man.previous()
runTouchApp(Test())

ScrollView and CustomButton

I woud like to create ScrollView with custom Buttons (Label + Image), but I've got problem with proper positioning Label and Image on Button object.
Code:
class TestScreen(Screen):
def change(self, btn, pos):
print pos
def populate(self):
scroll = self.ids.myscroll
grid = self.ids.scrollgrid
btn = Button(size_hint_y=None, width='29sp', text='')
box = BoxLayout(size=btn.size, pos=btn.pos,orientation='horizontal')
image = Image(source='image.png', size_hint_x=None, width=74)
label = Label(size_hint_x=None, width=100, text='test')
box.add_widget(image)
box.add_widget(label)
btn.add_widget(box)
grid.add_widget(btn)
btn.bind(pos=partial(self.change))
and .kv file:
<TestScreen>:
Button:
text: 'populate'
size_hint: None, None
size: 100,100
pos: 0,0
on_press: root.populate()
ScrollView:
id: myscroll
size_hint: None, None
size: 300, 500
pos: 100, 100
scroll_x: 0.5
GridLayout:
spacing: 20
padding: 20
id: scrollgrid
size_hint: None, None
cols: 1
size_hint_y: None
children
height: self.minimum_height
width: self.parent.width
The biggest problem is that during creating BoxLayout in populate(), btn.pos is [0,0] and after rendering btn.pos is changed to proper coordinates (I checked that using bind() for pos). How can I get correct cooridnates during creating mentioned BoxLayout?
If you add a widget to another widget, which isn't a layout, it will receive default pos (0,0) and size (100, 100). Use a grid layout to pack an image and a button together. Example:
main.py:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen
from kivy.properties import StringProperty, ObjectProperty
from random import choice
class ImageButton(GridLayout):
images = [
'http://kivy.org/logos/kivy-logo-black-256.png',
'http://img.interia.pl/rozrywka/nimg/2/7/roz4286600.jpg',
'http://www.i-programmer.info/images/stories/News/2014/Apr/A/kivycont2.jpg',
'http://static.giantbomb.com/uploads/scale_small/9/90155/2472244-abathur.png',
'https://www.gravatar.com/avatar/a07de5a89d18964a22775deae84d9ba6?s=328&d=identicon&r=PG',
'https://www.gravatar.com/avatar/578e323e1c4dda99b24bf047e0cb2e3e?s=328&d=identicon&r=PG&f=1'
]
source = StringProperty(images[0])
def change_image(self):
while True:
new_img = choice(self.images)
if new_img != self.source:
self.source = new_img
break
class MainScreen(Screen):
grid = ObjectProperty()
def populate(self):
for i in xrange(10):
self.grid.add_widget(ImageButton())
class Test(App):
def on_start(self):
self.root.populate()
Test().run()
test.kv:
MainScreen:
grid: grid
ScrollView:
GridLayout:
id: grid
cols: 1
spacing: '10dp'
padding: '10dp'
size_hint_y: None
height: self.minimum_height
<ImageButton>:
cols: 2
size_hint_y: None
height: '200dp'
AsyncImage:
source: root.source
size_hint_x: 0.3
Button:
text: 'click me'
on_press: root.change_image()
Adding widgets to a Button isn't a very nice solution. Button actually is a Label with a behavior set to it, therefore you only duplicate it without any good reason. How to make such a widget(a button with an image) is explained here, you'd need only to choose a position for Image and position whole widget for your needs. In the first example the App class also behaves as a BoxLayout, so imagine it as a layout only - a root widget. From there it'll be easy.
Also, when a widget is initialized, it comes with the default values of size and pos and other values specific for the widget itself, which are then changed. Basically, you created a widget with btn = Button(), but didn't set any pos or size, so when you access the position later within box, you only take the defaults and well... place them to size and pos of another widget - so you only replaced defaults with the same values. To get correct values you'll need to set them first inside the widget to your desired pos&size.

Placing an image in the middle of the label in Kivy

I have the following Kivy language file, which should mimic a dialer app. Also in the middle underneath the digits it should display an icon (red rectangle). However it seems that in my implementation the parent, self and root objects all have the same properties. What's wrong in my code? Is there a better way to do it?
# File name: dialer.kv
#:kivy 1.9.0
<Button>:
color: .8,.9,0,.65
font_size: 32
<MyGridLayout>:
rows: 3
spacing: 10
GridLayout:
rows: 1
size_hint_y: .40
Label:
text: '12345678901231234567890'
size: self.texture_size
text_size: root.width, None
font_size: 44
halign: 'center'
valign: 'middle'
canvas.before:
Rectangle:
pos: self.parent.center_x - self.width / 2, self.parent.center_y - self.height / 2
source: 'bg.png'
GridLayout:
cols: 3
rows: 4
size_hint_y: .50
spacing: 10
Button:
text: '1'
Button:
text: '2'
Button:
text: '3'
Button:
text: '4'
Button:
text: '5'
Button:
text: '6'
Button:
text: '7'
Button:
text: '8'
Button:
text: '9'
Button:
text: '*'
Button:
text: '0'
Button:
text: '#'
GridLayout:
cols: 2
size_hint_y: .10
spacing: 10
Button:
text: 'Clear'
Button:
text: 'Dial'
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# File name: main.py
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
class MyGridLayout(GridLayout):
pass
class DialerApp(App):
def build(self):
return MyGridLayout()
if __name__=="__main__":
DialerApp().run()
self variable you're using inside the canvas instructions is referencing to enclosing widget class (in this case it's a label), not a VertexInstruction like Rectangle. In your code self.parent.center_x is in fact the center of GridLayout and the self.width is the label width. To place your image in the middle of the label you can calculate the position manually:
<MyGridLayout>:
rows: 3
spacing: 10
GridLayout:
rows: 1
size_hint_y: .40
Label:
# ...
canvas.before:
Rectangle:
pos: self.center_x - 50, self.center_y - 50 # default size is 100x100
source: 'test.png'
# ...
You can also use Image widget as follows:
<MyGridLayout>:
rows: 3
spacing: 10
GridLayout:
rows: 1
size_hint_y: .40
Label:
# ...
Image:
center: self.parent.center
source: 'test.png'
# ...
Image is a Widget so now self refers to it and self.parent refers to the Label and we can use the center attribute to calculate the position automatically.