Kivy - Add others MDFloatingActionButton after touch - python

I'm trying to add the MDFloatingActionButton widget after clicking on button but I'm not getting it.
Someone could help me to solve this problem.
The goal is to create a list of buttons after clicking the FAB with the icon plus.
I tried adding code to add_widget() in a number of ways but none worked.
fab.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty
from kivymd.theming import ThemeManager
from kivymd.time_picker import MDTimePicker
from kivymd.button import MDFloatingActionButton
from kivy.animation import Animation
from kivy.core.window import Window
Window.clearcolor = (1, 1, 1, 1)
class MDFloatingActionButtonList(MDFloatingActionButton):
angle = NumericProperty(0)
def on_touch_up(self, touch):
if self.collide_point(*touch.pos):
if self.angle == 0:
self.angle += 45
#MDFloatingActionButton.add_widget()
else:
self.angle -= 45
class Fab(App):
theme_cls = ThemeManager()
def build(self):
return MDFloatingActionButtonList()
Fab().run()
fab.kv
<MDFloatingActionButtonList>:
canvas.before:
PushMatrix
Rotate:
angle: self.angle
axis: (0, 0, 1)
origin: self.center
canvas.after:
PopMatrix
MDFloatingActionButton:
id: float_act_btn
icon: 'plus'
opposite_colors: True
elevation_normal: 8
pos_hint: {'center_x': 0.5, 'center_y': 0.2}
Result:
Goal for example:

Oh boy, this is a tough one. The KivyMD project is poorly documented, even though the design is so pretty.
Ok, here is one example of how it might look:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivymd.button import MDFloatingActionButton
from kivymd.menu import MDDropdownMenu
from kivymd.theming import ThemeManager
Window.clearcolor = (1, 1, 1, 1)
menu_items = [
{'viewclass': 'MDFloatingActionButton',
'text': 'Example',
'on_press': lambda: print("Hello")},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example'},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example'},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example item'},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example'},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example'},
{'viewclass': 'MDFloatingActionButton',
'text': 'Example'},
]
class Fab(App):
theme_cls = ThemeManager()
layout = BoxLayout()
md = MDDropdownMenu(items=menu_items)
def build(self):
button = MDFloatingActionButton()
self.layout.add_widget(button)
button.bind(on_press=lambda x: self.md.open(button))
return self.layout
Fab().run()
Another way is to manually add the buttons to the window. But then you will have to handle the dissmiss (I did not implement it):
from kivy.app import App
from kivy.core.window import Window
from kivymd.button import MDFloatingActionButton
from kivymd.theming import ThemeManager
Window.clearcolor = (1, 1, 1, 1)
class Fab(App):
theme_cls = ThemeManager()
button = None
def build(self):
self.button = MDFloatingActionButton()
self.button.bind(on_press=lambda x: self.open_menu(self.button))
return self.button
def open_menu(self, instance):
x, y = instance.to_window(instance.x, instance.center_y)
for i in range(1, 5):
Window.add_widget(MDFloatingActionButton(center_y=y+100*i, x=x))
Fab().run()

Why don't you try this?
MDFloatingActionButtonSpeedDial
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
Screen:
MDFloatingActionButtonSpeedDial:
data: app.data
root_button_anim: True
'''
class Example(MDApp):
data = {
'language-python': 'Python',
'language-php': 'PHP',
'language-cpp': 'C++',
}
def build(self):
return Builder.load_string(KV)
Example().run()
Here is the output:

Related

kivy transition between screens

i made a gui with python kivy with a starting screen that has a button in it which generates new screens when pressed, and it also generates new buttons so its easier to pick the screen i need to get in focus but i can't get it working properly cause i can't generate buttons on the newly made screens
when they aren't in focus, the script only generates buttons for the screen in focus it seems
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
sm = ScreenManagement(transition=FadeTransition())
class newtab(Screen):
def __init__(self, **kwargs):
super(newtab, self).__init__(**kwargs)
self.bt1=(Button(text="New tab", size_hint =(.1, .1) ,pos_hint ={'center_x':.1, 'center_y':.94}))
self.add_widget(self.bt1)
self.bt1.bind(on_release=self.new_tab)
self.txt1 = TextInput(text='',size_hint =(.1, .1), pos_hint ={'center_x':.2, 'center_y':.75}, multiline=True)
self.add_widget(self.txt1)
def transition(self, instance):
self.manager.current = (instance.text)
for item in sm.screen_names:
self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
def new_tab(self, *args):
n = len(self.manager.screen_names) ##number of screens+1
screen = newtab(name="screen {}".format(n)) #make new screen and give it number
self.manager.add_widget(screen)
self.manager.current = "screen 0"
for item in sm.screen_names:
self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
sm.add_widget(newtab(name='screen 0'))
class Application(App):
def build(self):
return sm
if __name__ == "__main__":
Application().run()
I suppose that below is what you expected to get. But I agree with #ApuCoder that you may look for TabbedPanel functionality.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
sm = ScreenManagement(transition=FadeTransition())
class newtab(Screen):
def __init__(self, **kwargs):
super(newtab, self).__init__(**kwargs)
self.bt1 = (Button(text="New tab", size_hint=(.1, .1), pos_hint={'center_x': .1, 'center_y': .94}))
self.add_widget(self.bt1)
self.bt1.bind(on_release=self.new_tab)
self.txt1 = TextInput(text='', size_hint=(.1, .1), pos_hint={'center_x': .2, 'center_y': .75}, multiline=True)
self.add_widget(self.txt1)
# add all present screen buttons to newly created screen
for i, screen in enumerate(sm.screens):
self.bt2 = (Button(text=screen.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * i + .1), 'center_y': .84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
# add this newly created screen button to all screens
for screen in sm.screens + [self]:
screen.bt2 = (Button(text=self.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * len(sm.screens) + .1), 'center_y': .84}))
screen.add_widget(screen.bt2)
screen.bt2.bind(on_release=screen.transition)
def transition(self, instance):
self.manager.current = instance.text
def new_tab(self, *args):
n = len(self.manager.screen_names) ##number of screens+1
screen = newtab(name="screen {}".format(n)) # make new screen and give it number
self.manager.add_widget(screen)
self.manager.current = "screen 0"
sm.add_widget(newtab(name='screen 0'))
class Application(App):
def build(self):
return sm
if __name__ == "__main__":
Application().run()

Kivy: Create a list of coloured labels using build() method

I want to create a list of coloured labels. The thing is that I could do it with the kv file, but I need to do it through the build() method. So I tried replicate what I have done, but it does not work. And I can't understand why.
This is what I've coded
from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
class RL(RelativeLayout): # Creates the background colour for each label
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(.7, 0, .5, 1)
Rectangle(size_hint=self.size)
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
RL_list = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding= 10, spacing = 15)
for i in range(0, self.N_LBLS):
self.RL_list.append(RL())
self.labels_text.append(Label(text=f'{i}º label', size_hint=self.size))
self.RL_list[i].add_widget(self.labels_text[i])
box.add_widget(self.RL_list[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()
It's supposed to make a button to the left, and a list of 8 coloured labels to the right.
The problem is that you are setting size_hint=self.size in each Label. The self.size is the size of the MainMenu, which is [100,100] when that code is executed. Note that size_hint is a multiplier that is applied to the parents size to calculate the widgets size. So a size_hint of [100,100] makes each Label 100 times bigger than the MainMenu. So your code is working, but the Labels are so large that the text is off the screen. Start by just removing size_hint=self.size.
And, to set a background color on a Label, you can just use the canvas of that Label, rather than some container. Here is a version of your code that does that:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class ColorLabel(Label):
pass
Builder.load_string('''
<ColorLabel>:
bg_color: [.7, 0, .5, 1]
canvas.before:
Color:
rgba: self.bg_color
Rectangle:
pos: self.pos
size: self.size
''')
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding=10, spacing=15)
for i in range(0, self.N_LBLS):
self.labels_text.append(ColorLabel(text=f'{i}º label'))
box.add_widget(self.labels_text[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
lbl.bg_color = [0, 1, 0, 1]
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()

Kivy: change z-index of canvas rectangles

I am very new to kivy, and have been trying to figure out how to order rectangles created with the canvas class in the z dimension. Using the .kv language I created a root widget that creates a grid of rectangles. That part worked out fine, then I created a child widget consisting of 1 blue rectangle that I was able to move around with the kivy clock. The problem is that I want to display the blue rectangle on top of everything else.
This is my python code (full of unnecessary imports):
import kivy
from kivy.config import Config
Config.set('graphics', 'resizable', False)
Config.set('graphics', 'width', '1000')
Config.set('graphics', 'height', '700')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.core.window import Window
from kivy.properties import (ObjectProperty, ReferenceListProperty, ListProperty)
import random
from kivy.clock import Clock
from kivy.vector import Vector
class board(FloatLayout):
car = ObjectProperty(None)
def __init__(self, **k):
super(board, self).__init__(**k)
with self.canvas:
l = 2
w = 4
for b in range(1, l+1):
for a in range(1,w+1):
for i in range(3):
for x in range(2):
numb = random.randint(1, 2)
if numb == 1:
Color(1, 0, 0, 1)
Rectangle(pos=(a*70+20*(x)-50, b*80+20*(i)-20), size=(10, 10))
Color(0,1,0,1)
print(a)
print(b)
Rectangle(pos=(a*70-10, 20), size=(20, l*80+35))
Rectangle(pos=(0, 20), size=(20, l*80+35))
Rectangle(pos=(20, 20), size=(w*70-30, 20))
Rectangle(pos=(20, b*80 + 35), size=(w*70-30, 20))
class Car(Widget):
velocity = ListProperty([1, 1])
def __init__(self, **k):
super(Car, self).__init__(**k)
self.canvas.add(Color(1,0,0,1))
self.canvas.add(Rectangle(size=(50,50)))
Clock.schedule_interval(self.update, 1.0/60.0)
def update(self, *args):
self.x += self.velocity[0]
self.y += self.velocity[1]
print('hello')
class RobotApp(App):
def build(self):
ba= Car()
return board()
if __name__ == '__main__':
RobotApp().run()
This is my kivy code:
#:kivy 1.11.1
<Car>:
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos:self.pos
size: 10, 10
<board>:
car: Cars
canvas:
Rectangle:
pos: 0, 0
size: 500, 700
Car:
id: Cars
pos: self.parent.pos
Thanks to Inclement, I was able to figure out the problem. I had to change three lines:
One in the python file.
with self.canvas:
to
with self.canvas.before:
Two in the kivy file.
<Car>:
canvas:
to
<Car>:
canvas.after:
then
<board>:
canvas:
to
<board>:
canvas.before:
my blue square now displays on top, thanks!

Kivy graph doesn't appear in widget

I'm trying to find a solution to embed a graph within a kivy widget. There seems to be only one example of using kivy garden graph (sin wave) and I'm having difficulty implementing this within my app.
Here is the code that I'm working with
#!/usr/bin/kivy
import kivy
from random import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.switch import Switch
from kivy.uix.label import Label
from kivy.garden.graph import Graph, MeshLinePlot
from math import sin
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from kivy.graphics import *
from kivy.config import Config
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '480')
Builder.load_string("""
<Menuscreen>:
#Handling the gesture event.
ScreenManager:
id: manager
Screen:
id: main_screen
name:'main_screen'
FloatLayout:
MyGraph:
size_hint: None, None
size: 800,600
pos: 25,25
""")
class MyGraph(Graph):
def __init__(self, **kwargs):
super(MyGraph, self).__init__(**kwargs)
self.xlabel = 'This is the X axis'
self.ylabel = 'This is the Y axis'
self.x_ticks_minor = 5
self.x_ticks_major = 25
self.y_ticks_major = 1
self.y_grid_label = True
self.x_grid_label = True
self.x_grid = True
self.y_grid = True
self.xmax = 100
self.xmin = -0
self.ymin = -1
self.ymax = 1
self.plot = MeshLinePlot(color=[1, 0, 0, 1])
self.plot.points = [(x, sin(x / 10.)) for x in range(0, 100)]
self.add_plot(self.plot)
class MenuScreen(Screen):
pass
sm = ScreenManager()
menu_screen = MenuScreen(name='menu')
sm.add_widget(menu_screen)
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
All of the axis labels seem to appear but the points on the graph do not appear. Is there something that I am missing to get this to appear? Thanks in advance for your advice.
Mostafar at Github asked this same question, and thanks to #Tshirtman, the following answer was provided:
mostafar commented on Apr 27, 2014 After a chat with #tshirtman, He found out the problem is with stencilbuffer and by changing line 139 of init.py of graph module to:
self._fbo = Fbo(size=self.size, with_stencilbuffer=False)
It will be visible in my example, but then there will be many problems with new features of graph (SmoothLinePlot).
Link: https://github.com/kivy-garden/garden.graph/issues/7

Binding on_press with events in Kivy

I'm having a hard time with Kivy's sytem of half pure-python and half kv language setup. All I'm trying to do is for now is a 'hello world' type on_press event, and I can't get it to work.
from kivy.uix.modalview import ModalView
from kivy.uix.listview import ListView
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.app import App
import citylists
import cat_dict
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.storage.jsonstore import JsonStore
store = JsonStore('data.json')
Builder.load_string("""
#:import ListItemButton kivy.uix.listview
#:import sla kivy.adapters.listadapter
<ListViewModal>:
ListView:
size_hint: .8, .8
adapter:
sla.ListAdapter(
data=["{0}".format(i) for i in root.categories],
on_press=root.callback(self),
cls=ListItemButton.ListItemButton)
""")
class ListViewModal(ModalView):
categories = sorted(cat_dict.SECTION_DICT)
def __init__(self, **kwargs):
super(ListViewModal, self).__init__(**kwargs)
def callback(self, instance):
print "HI" + str(instance)
class MainView(GridLayout):
def __init__(self, **kwargs):
kwargs['cols'] = 1
super(MainView, self).__init__(**kwargs)
listview_modal = ListViewModal()
self.add_widget(listview_modal)
class MainScreen(Screen):
pass
mainscreen=MainScreen()
mainlayout = MainView()
mainscreen.add_widget(mainlayout)
sm = ScreenManager()
sm.add_widget(mainscreen)
class CARApp(App):
def build(self):
return sm
if __name__ == '__main__':
CARApp().run()
cat_dict.py
SECTION_DICT = {
"accounting+finance": "acc",
"admin / office": "ofc",
"arch / engineering": "egr",
'art / media / design': 'med',
'biotech / science': 'sci',
'business / mgmt': 'bus',
'customer management': 'csr',
'education': 'edu',....
Ultimately, I want to bind the on_press event for each of the dynamically created buttons titled with each key in SECTION_DICT, then save the value in JsonStore.
In simple terms all I need to happen is for a user to press a button to choose a craigslist category, which will return the 3 letter abbreviation to be used later in the program.
A ListAdapter does not have an on_press event. You need to bind to the on_press event of each button, which can be done using an args converter:
#:import ListItemButton kivy.uix.listview.ListItemButton
#:import ListAdapter kivy.adapters.listadapter.ListAdapter
<ListViewModal>:
ListView:
size_hint: .8, .8
adapter:
ListAdapter(
data=["{0}".format(i) for i in root.categories],
args_converter=lambda row_index, rec: \
{'text': rec, 'on_press': root.callback, 'size_hint_y': None, 'height': 25},
cls=ListItemButton)
Also, take care to pass functions themselves as callbacks rather than the return value of functions. In other words, use root.callback instead of root.callback(self).

Categories