I'm trying to build this application which contains multiple buttons. I can bind each button event to a callback but I am not able to change the state (namely the label) of any other button except for the one that fired the event. Does anyone know how to do this?
All you need is a reference to the other button, then you can do other_button.text = 'whatever'.
The way to do this depends on how you've constructed the program. For instance, if you constructed in the program in kv language, you can give your buttons ids with id: some_id and refer to them in the callback with stuff like on_press: some_id.do_something().
In pure python, you could keep references to the button in the parent class when you create them (e.g. self.button = Button()) so that the callback can reference self.button to change it. Obviously that's a trivial example, but the general idea lets you accomplish anything you want.
Probably not the official way, but try out the following code. It will change the text property of the buttons...
Ezs.kv file:
#:kivy 1.8.0
<Ezs>:
BoxLayout:
orientation: 'vertical'
padding: 0
spacing: 6
#choose
Button:
id: btn_1
text: 'text before'
on_press: btn_2.text = 'Whatever'
on_release: self.text = 'Who-Hoo'
#choose
Button:
id: btn_2
text: 'Press this'
on_release: self.text = 'HEEYY'
on_press: btn_1.text = 'text after'
.py file:
class Ezs(BoxLayout):
class EzsApp(App):
def build(self):
return Ezs
if __name__ == '__main__':
EzsApp().run()
Related
Trying to learn Kivy.
I am using the kivy_garden.contextmenu which I open when I right click on a widget.
This works.
But when clicking un element in the context menu, I am receiving the on_touch_xxx events on the underneath widget anyway (here it is myWidget) .
My first thought was I could use flags to avoid this behaviour, e.g. setting a value menu_is_showing to True when I show the menu, and ignoring the underneath's widget's on_touch_up if the menu is showing. I did it and it was almost working (a was never notified the menu had been closed by click outside of it so the flag system would break in that case)...
Then I realised (while writing here) I could create a property for the context menu "visible", which made it all work as I expect a context menu would.
And here is the working code (which you are welcome to comment/correct):
from kivy.lang import Builder
from kivy.config import Config
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
import kivy_garden.contextmenu
from kivy.properties import ObjectProperty
kv = '''
<myWidget>:
on_touch_up: root._on_touch_up(*args[1:])
menu_visible: context_menu.visible
BoxLayout:
id: boxlayout1
pos_hint : {'x':0, 'y':0}
size_hint: 1,1
canvas.before:
Color:
rgba: (0, 0, 1, 1)
Rectangle:
#texture: self.texture
size: self.width-10, self.height-10
pos: self.x+5, self.y+5
ContextMenu:
id: context_menu
visible: False
cancel_handler_widget: root
ContextMenuTextItem:
text: "action 1"
on_release: root._action1(); root._hide_menu()
ContextMenuTextItem:
text: "action 2"
on_release: root._action2(); root._hide_menu()
<myLayout>:
BoxLayout:
Button:
text: "Dummy"
myWidget:
id: floatlayout1
'''
Builder.load_string(kv)
class myWidget(FloatLayout):
menu_visible = ObjectProperty()
def __init__(self, **kwargs):
super(myWidget, self).__init__(**kwargs)
def _action1(self):
print("Do Action 1")
def _action2(self):
print("Do Action 2")
def _on_touch_up(self, touch):
if self.menu_visible:
return
if self.collide_point(*touch.pos) and touch.button == 'left':
print("Left Click reached the blue area")
elif self.collide_point(*touch.pos) and touch.button == 'right':
print("Right Click reached the blue area")
self.ids.context_menu.show(*touch.pos)
def _hide_menu(self):
self.ids.context_menu.hide()
class myLayout(FloatLayout):
pass
class testApp(App):
def build_config(self, config):
Config.set('kivy', 'exit_on_escape', '0')
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
self.title = 'Testing Context Menu and Layouts'
def build(self):
return myLayout()
if __name__ == '__main__':
testApp().run()
Try clicking left and right in the blue area and check the console output. (the left button in the layout is only there to add an offset and make sure things I do in the blue area do not align by chance just because it would be in (0,0))
And that's fine, but I would have thought a context menu would already do that, and by default would not propagate the touch events to other widgets. Is there a way to do that?
If so, could you please be so kind to tell me how you'd do that?
Thanks for your time.
C
I'm creating a tool bar in PyQt. How it looks now is:
(HomeButton).............................................(ExitButton)..|
I want to use the space in the middle to put in an image/logo -- with no function so it looks like:
(homebutton)......[IMAGE/LOGO_HERE]......(exitbutton)..|
I've tried to do this by adding a widget with an image but it's not showing up. My code is:
logo = QWidget()
logolabel = QLabel(p3logo)
logopixmap = QPixmap(self.LOGO)
logolabel.setPixmap(QPixmap(self.LOGO))
logolabel.setPixmap(logopixmap)
logo.resize(logopixmap.width(),logopixmap.height())
###logoAction = QAction(QIcon('logo.png'), 'Logo', self)
spacer = QWidget()
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
exitAction = QAction(QIcon('exit.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+X')
exitAction.triggered.connect(self.exitClicked)
homeAction = QAction(QIcon('home.png'), 'Home', self)
homeAction.setShortcut('Ctrl+H')
homeAction.triggered.connect(self.homeClicked)
self.toolbar = self.addToolBar('Toolbar')
self.toolbar.addAction(homeAction)
self.toolbar.addWidget(logo)
###self.toolbar.addAction(logoAction)
self.toolbar.addWidget(spacer)
self.toolbar.addAction(exitAction)
self.toolbar.addSeparator()
I also tried to add it in as an 'icon' but it was resized to the same size as the home/exit buttons making it hardly visible.
Your code example is effectively just adding an empty widget to the toolbar, because the label has not been put inside a layout. It looks like it can be fixed by getting rid of the container widget and simply adding the label directly:
self.toolbar.addWidget(logolabel)
I'm sorry if this is so simple, but I'm trying to bind an event to a checkbox in a menubar with wxPython. For some reason, it won't work! I've tried a variety of different ways to get it to print a statement, but nothing happens when I check the box. Is it not binding correctly? This is just a simple app I wrote to demonstrate the problem...
import wx
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title)
panel = wx.Panel(self)
menuBar = wx.MenuBar()
menu = wx.Menu()
self.checkbox = menu.AppendCheckItem(-1, "Check me")
menuBar.Append(menu,'&check box')
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_CHECKBOX, self.onCheck, self.checkbox)
def onCheck(self, e):
print self.checkbox.IsChecked()
app = wx.App()
test = Frame(None, -1, "Test")
test.Show()
app.MainLoop()
I've figured it out. I needed to change the Bind event from wx.EVT_CHECKBOX to wx.EVT_MENU.
What is missing in this code to running carousel??
I´m trying to conect the carousel in a button. When I run, it´s show a button, but the on_press nothing happens.
What is missing in this code to running carousel??
Builder.load_string('''
<tela>:
Button:
text: 'ir'
font_size: 32
size_hint: None, None
pos_hint: {'right': 1}
size: 150, 50
on_press: root.ida()
''')
class acesso(BoxLayout):
def ida(self):
self.clear_widgets()
self.add_widget(tela1())
class tela(BoxLayout):
def ida(self):
self.parent.ida()
class tela1(App,Widget):
def livro(self):
carousel = Carousel(direction='right',loop='true')
for i in range(1,5):
src = "images/%d.png" % i
image = Image(source=src,pos=(1,10), size=(1250, 635))
carousel.add_widget(image)
return carousel
class CarroselApp(App):
def build(self):
self.acesso = acesso()
self.acesso.add_widget(tela())
return self.acesso
if __name__ == "__main__":
CarroselApp().run()
There is multiples issue with your code:
You inherith from App and Widget for tela1. I don't know the effect of that, but this would be wrong somehow. Thoses are not meant to be combined. Your CarroselApp is already here.
Your tela1 widget have a livro() method, but is never called. Plus, you create a widget Carousel without really adding it to the tela1.
tela inherith from a Widget, so it wont layout the children. I'm 200% this would not give what you wished in the first place.
I guess if you replace tela1 with this code, it might works:
class tela1(FloatLayout):
def __init__(self, **kwargs):
super(tela1, self).__init__(**kwargs)
self.add_widget(self.livro())
def livro(self):
carousel = Carousel(direction='right',loop='true')
for i in range(1,5):
src = "images/%d.png" % i
image = Image(source=src,pos=(1,10), size=(1250, 635))
carousel.add_widget(image)
return carousel
Note: please consider pep8 for your code. Using lowercase for class name is not usual and confusing.
So, I have a wxPython ListCtrl which contains rows of data. How can I make an event that calls a function, with the row contents, when one of the rows if clicked on?
You can use the Bind function to bind a method to an event. For example,
import wx
class MainWidget(wx.Frame):
def __init__(self, parent, title):
super(MainWidget, self).__init__(parent, title=title)
self.list = wx.ListCtrl(parent=self)
for i,j in enumerate('abcdef'):
self.list.InsertStringItem(i,j)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnClick, self.list)
self.Layout()
def OnClick(self, event):
print event.GetText()
if __name__ == '__main__':
app = wx.App(redirect=False)
frame = MainWidget(None, "ListCtrl Test")
frame.Show(True)
app.MainLoop()
This app will print the item in the ListCtrl that is activated (by pressing enter or double-clicking). If you just want to catch a single click event, you could use wx.EVT_LIST_ITEM_SELECTED.
The important point is that the Bind function specifies the method to be called when a particular event happens. See the section in the wxPython Getting Started guide on event handling. Also see the docs on ListCtrl for the events that widget uses.