I have created a custom Button class in Kivy with some callback methods, when I right click on the button I want to be able to choose from a couple of different actions:
from kivy.config import Congfig
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
from kivy.app import App
from kivy.uix import Button
class CustomButton(Button):
"""This is just for demonstration"""
def __init__(self, name='', **kwargs):
super(Service, self).__init__(**kwargs)
self.name = name
self.on_touch_down = self.mouse_click
def mouse_click(self, touch):
if self.collide_point(touch.x, touch.y):
if touch.button == 'right':
# Open context menu
pass
def callback_1(self):
# This will be called from one of the context options
pass
def callback_2(self):
# Or this will be called from a different option
pass
The code is just for demonstration purposes to express what I'm trying to achieve. Is this possible?
Thanks in advance.
In your mouse_click() method (where you have # Open context menu) you can call a custom popup menu like:
self.popup = PopMenu(touch)
self.popup.open()
With a PopMenu class that creates a ModalView, something like:
class PopMenu(object):
def __init__(self, touch):
myContent = BoxLayout(orientation='vertical')
button = Button(text='button1')
myContent.add_widget(button)
button = Button(text='button2')
myContent.add_widget(button)
button = Button(text='button3')
myContent.add_widget(button)
self.popup = ModalView(size_hint=(None, None), height=myContent.height, pos_hint={'x' : touch.spos[0], 'top' : touch.spos[1]})
self.popup.add_widget(myContent)
def open(self, *args):
self.popup.open()
And you can add your callbacks to the buttons in the PopMenu.
Related
I'm learning to program with Python and Kivy.
I'm trying to change the text of a Label inserted in one class, by pressing the button which is in another
class. Without using Kv language
I tried them all, the text does not change. Help me!!!!
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
class Gestione(BoxLayout):
def __init__(self, **kwargs):
super(Gestione, self).__init__(**kwargs)
self.w1 = Windows()
self.w2 = Windows2()
self.add_widget(self.w1)
self.add_widget(self.w2)
class Windows(BoxLayout):
def __init__(self, **kwargs):
super(Windows,self).__init__(**kwargs)
self.label = Label()
self.label.text = "Label to change in Window1"
self.add_widget(self.label)
class Windows2(BoxLayout):
def __init__(self, **kwargs):
super(Windows2, self).__init__(**kwargs)
self.link = Windows()
bottone = Button(text="button Class2", on_press=self.changetext)
self.add_widget(bottone)
def changetext(self, *args, **kwargs):
self.link.label.text = "Text changed"
class Gestioneapp(App):
def build(self):
return Gestione()
Gestioneapp().run()
Please help, I'm trying to make an application for a child to learn the alphabet, I'm just learning programming and working with classes.
I need to pass to the SecondScreen class the text that the button_press function returns from the ScreenMain class.
`
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from itertools import chain
from kivy.uix.screenmanager import ScreenManager, Screen
class ScreenMain(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.alphabet = [chr(i) for i in chain(range(1040, 1046), range(1025, 1026), range(1046, 1069), range(32, 33),
range(1069, 1072))]
gr = GridLayout(cols=5, padding=[35], spacing=3)
for i in self.alphabet:
gr.add_widget(Button(text=i, on_press=self.button_press))
self.add_widget(gr)
def button_press(self, instance):
self.manager.transition.direction = 'left'
self.manager.current = 'second_screen'
print(instance.text) # I output to the console, everything is ok
return instance.text
class SecondScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
get = ScreenMain.button_press # I'm trying to pass a letter from a function to a class button_press
layout = GridLayout(cols=5, rows=5, padding=[35], spacing=10)
layout.add_widget(Button(
text=str(get))) # Trying to create a button on the second page with the text of the letter pressed on the first screen
self.add_widget(layout)
def _on_press_button_new_layout(self, *args):
self.manager.transition.direction = 'right'
self.manager.current = 'main_screen'
class MyApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(ScreenMain(name='main_screen'))
sm.add_widget(SecondScreen(name='second_screen'))
return sm
if __name__ == '__main__':
MyApp().run()
`
I'm trying to build this simple GUI for a "voting app" where, by clicking the button with the candidate's ID, +1 will be added in the value of the ID key inside a dictionary. (counting votes on click basically)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
CANDIDATES = {"T1031" : 0,"T2112" : 0, "T4561" : 0}
class MyLayout(BoxLayout):
orientation = "Vertical"
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
for i in CANDIDATES:
canditate = Button(text=i, on_press=self.button_clicked)
self.add_widget(canditate)
def button_clicked(self, obj):
print("button pressed", obj)
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyApp().run()
So how can I grab the text displayed on the button ?
(Also, if any of you guys know...how do I put an ID on the buttons? I tried with writing "id = i" but the GUI doesn't even start when I do that)
Many thanks in advance!
You can access the text value from a button using the Button.text property:
def button_clicked(self, obj):
# Note that obj here is a button object
# You can access it's text value, for example, using obj.text
CANDIDATES[obj.text] += 1
print(f"{obj.text}'s current vote count is now {CANDIDATES[obj.text]}")
I'm not really sure as to why the canvas isn't clearing.
The first build(self) implementation that has the parent variable is the one that works. The only thing I see different is that the second implementation is adding the Button widget to the MyPaintWidget instead of both of those widgets getting added to a default Widget class.
Very new to kivy i'm semi-familiar with python. I'd love an explanation.
from random import random
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Color, Ellipse, Line
'''
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols=2
self.add_widget(Label(text='User Name'))
self.username=TextInput(multiline=False)a
self.add_widget(self.username)
self.add_widget(Label(text='password'))
self.password=TextInput(password=True, multiline=False)
self.add_widget(self.password)
class MainApp(App):
def build(self):
return LoginScreen()
'''
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
color = (random(), 1, 1)
with self.canvas:
Color(*color)
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y))
print(touch)
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
#WHY ARE THESE TWO IMPLEMENTATIONS OF BUILD SO DIFFERENT?????
'''
def build(self):
parent = Widget()
self.painter = MyPaintWidget()
clearbtn = Button(text='Clear')
clearbtn.bind(on_release=self.clear_canvas)
parent.add_widget(self.painter)
parent.add_widget(clearbtn)
return parent
'''
def build(self):
self.painter = MyPaintWidget()
clearbtn = Button(text='Clear')
clearbtn.bind(on_release=self.clear_canvas)
self.painter.add_widget(clearbtn)
return self.painter
def clear_canvas(self, obj):
self.painter.canvas.clear()
if __name__ == '__main__':
MyPaintApp().run()
Touches are dispatched down the widget tree, they enter at the root widget which must pass the touch down to its children (or fail to do so, if it wants).
Your MyPaintWidget class overrides on_touch_down but fails to pass the touch to its children, so the Button never receives the touch and never gets a chance to become pressed.
Add return super(MyPaintWidget, self).on_touch_down(touch) to the MyPaintWidget.on_touch_down to call the parent class method that automatically handles this for you.
I want to change a text of a label but I can't do it, I can see it changing on the shell but not on the UI. I even directly change the text of the label by referencing its id but still its not updating. Anyone knows how to do this?
class MainApp(Screen, EventDispatcher):
title = "Top 10 Plays of 2015"
def __init__(self,*args,**kwargs):
super(MainApp, self).__init__(*args, **kwargs)
def change_curr_title(self, title, *args):
self.title = title
self.ids.lblTitle.text = self.title
print(self.ids.lblTitle.text)
pass
class OtherVideos(BoxLayout, EventDispatcher):
def __init__(self, *args, **kwargs):
super(OtherVideos,self).__init__(*args, **kwargs)
self.loadVideos()
def loadVideos(self):
self.clear_widgets()
con = MongoClient()
db = con.nba
vids = db.videos.find()
vidnum = 1
for filename in vids:
myid = "vid" + str(vidnum)
getfilename = filename['filename']
button = Button(id=myid,
text=getfilename,
color=[0,0.7,1,1],
bold=1)
button.bind(on_release=partial(self.change_Title, getfilename))
self.add_widget(button)
vidnum += 1
def change_Title(self, title, *args):
main = MainApp()
main.change_curr_title(title)
This is the construction of my kivy:
<MainApp>:
....
BoxLayout:
....
BoxLayout:
....some widgets
BoxLayout:
OtherVideos:
...this is where the buttons are generated...
BoxLayout:
Label:
id: lblTitle
text: root.title
Is there anyway to upload my whole code on this? like the file itself, so you guys can look at it.
EDIT: I can easily update the label when I'm making a new method like this without a parameter and binding it to a button through kivy
def update_label(self):
self.ids.lblTitle.text = "New Title"
I don't know why buttons with events created dynamically doesn't work.
Here:
def change_Title(self, title, *args):
main = MainApp() # !
main.change_curr_title(title)
you are creating a new object of screen (MainApp), which isn't connected to anything. To make it work, main should link to the existing instance of MainApp screen.
The OtherVideos box layout needs to have a reference to it, preferably in kv file.
Edit
In order to create a link from MainApp to OtherVideos, create an ObjectProperty:
class OtherVideos(BoxLayout):
main = ObjectProperty()
def __init__(self, *args, **kwargs):
super(OtherVideos,self).__init__(*args, **kwargs)
self.loadVideos()
...
which will be populated in kv file:
OtherVideos:
main: root
...this is where the buttons are generated...
Then, in the change_Title function, use this reference:
def change_Title(self, title, *args):
self.main.change_curr_title(title)