i have 10 button, which correspond to the same method. how am i going to check which button was clicked in the corresponding method? i tried to check for the button press of a particular button in the list by the following code, but i got segmentation fault error:
for i in range(0,10):
if button_list[i].clicked():
break
break
#operation with respect to the button clicked
Here's a sample code that illustrates knowing what button triggered the event by using the label of the button:
from gi.repository import Gtk
class ButtonWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Button Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
#Lets create 10 buttons for this demo
#You could create and set the label for
#each of the buttons one by one
#but in this case we just create 10
#and call them Button0 to Button9
for i in range(10):
name = "Button{}".format(i)
button = Gtk.Button(name)
button.connect("clicked", self.on_button_clicked)
hbox.pack_start(button, True, True, 0)
def on_button_clicked(self, button):
print button.get_label()
def on_close_clicked(self, button):
print "Closing application"
Gtk.main_quit()
win = ButtonWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
So you could just check what the label is and act accordingly.
Once you have connected all the buttons to the same callback, I assume the callback will have this signature: callback(button) where button is the button that emitted the clicked signal.
Inside that callback should be easy to check which button was clicked using something like:
button_list.index(button)
This will return the index of the button inside your list.
Related
Disabled button still catch clicks during the long task. During the long tasks the button is grayed out but if you click it during the long task, click event fires after the long task has finished. e.g.
def onClick(self, evt):
self.btn.Disable()
for i in range (1000):
print i
self.btn.Enable()
Button disables itself before executing the long for loop, but if we click the button during for loop, it starts the for loop again, because it calls the onClick function again, after the for loop finishes.
Any idea how to disable the click event as well ?
Although I have my doubts as to whether you should be coding your long running event this way, you can achieve what you want by using Unbind on the button click, perform the long running task, using Yield to use up any subsequent button clicks and then at the end of the task Bind to the button again.
i.e.
import wx
import time
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
self.btn = wx.Button(self, -1, "Click Me")
self.btn.Bind(wx.EVT_BUTTON, self.onClick)
self.Centre()
self.Show()
def onClick(self, event):
self.btn.Unbind(wx.EVT_BUTTON)
for i in range (10):
time.sleep(1)
print( i )
wx.GetApp().Yield() # Yielding allows button events to be used up
self.btn.Bind(wx.EVT_BUTTON, self.onClick)
print ("Accepting clicks again")
if __name__ == "__main__":
app = wx.App()
ButtonFrame()
app.MainLoop()
To be honest I didn't really get what you are asking.
Your code works as follows:
When you click on the button, the button (i.e. self.btn) is disabled
It will stayed disabled and execute the for loop
Once done executing the for loop, the button goes back to live
If you would like to disable the button, you should do it outside of the onclick event.
For example:
self.btn.Disable() # This will grey out the button, you can't click it, so the following onClick function wouldn't be triggered
def onClick(self, evt):
# do something
If you would like to use the button to trigger a task execution, and disable the button that triggers the task when the task is in the middle of execution, the best way is to use multi-thread. You can take a look at the following two links for more information:
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
https://wiki.wxpython.org/LongRunningTasks
In fact it's easier than my first answer suggested. There is no reason to UnBind, simply using Yield before re-enabling the button will suffice:
import wx
import time
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None,-1,"Disable Button Events")
panel = wx.Panel(self, -1)
self.btn = wx.Button(panel, -1, "Click Me", pos=(10,10), size=(80,30))
self.btn.Bind(wx.EVT_BUTTON, self.onClick)
self.Show()
def onClick(self, event):
self.btn.Disable()
for i in range (10):
time.sleep(1)
print("Long task running",i)
wx.GetApp().Yield() # Yielding allows button events to be used up
self.btn.Enable()
print("Accepting clicks again")
if __name__ == "__main__":
app = wx.App()
ButtonFrame()
app.MainLoop()
I have a main window with a Gtk Button named openDialog. If I click on this button another Window (addName) popups. I would like to write a method (or a function, don't know which is the right name in python) in my main window file, called printHi. I would like to run this printHi method (in my main window file), when addName window is destroyed.
I tried something like this:
def on_addName_destroy():
printHi()
But it doesn't work. Any suggestion?
You can make use of "delete-event" signal of gtk.Widget. It is also possible to make use of "destroy" signal of gtk.Object. Here is a sample which connects to both the signals although in your case connecting to any one of them should suffice.
#!/usr/bin/env python
import gtk
def on_addName_destroy(gtkobject, data=None):
print "This is called later after delete-event callback has been called"
print "Indication that the reference of this object should be destroyed"
print "============================================"
def on_addName_delete(widget, event, data=None):
print "This is called on delete request"
print "Propagation of this event further can be controlled by return value"
print "--------------------------------------------"
return False
def show_popup(widget, data=None):
dialog = gtk.Window(gtk.WINDOW_TOPLEVEL)
dialog.set_size_request(100, 100)
label = gtk.Label("Hello!")
dialog.add(label)
dialog.connect("delete-event", on_addName_delete)
dialog.connect("destroy", on_addName_destroy)
dialog.show_all()
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_size_request(100, 100)
button = gtk.Button("Popup")
button.connect("clicked", show_popup)
window.add(button)
window.connect("destroy", lambda x: gtk.main_quit())
window.show_all()
gtk.main()
Hope this helps!
I have a list of buttons and I have made a loop to find out what button is pressed, then disable that button on click.
Here is the snippet of code:
def change(self,event):
self.Disable()
for i in enumerate(file_pool):
self.button_pool.append(wx.Button(self.sizer, -1, i[1], pos=(20, i[0]*45),size=(200,40))) #this would create the list of buttons
for i in self.button_pool:
i.Bind(wx.EVT_BUTTON, self.change) #bind each button
However, this will Disable every widget, not just the pressed button. How can I only disable the clicked button?
Thanks
you can get your object from the event:
def change(self, event):
myobject = event.GetEventObject()
myobject.Disable()
I have very simple window where I have 2 buttons - one for cancel, one for apply. How to set the button for apply as default one? (When I press enter, "apply" button is pressed)
However, I want to set focus to the first input widget (I can't use grab_focus() on the button)
Any suggestions?
Edit:
After wuub's answer it works visually good. However, when I press the button in different widget, it doesn't run callback of the default button.
Example code:
import os, sys, pygtk, gtk
def run(button, window):
dialog = gtk.MessageDialog(window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, "OK")
dialog.run()
dialog.destroy()
window = gtk.Window()
window.connect("destroy", gtk.main_quit)
vbox = gtk.VBox(spacing = 10)
entry = gtk.Entry()
vbox.pack_start(entry)
button = gtk.Button(stock = gtk.STOCK_SAVE)
button.connect("clicked", run, window)
button.set_flags(gtk.CAN_DEFAULT)
window.set_default(button)
vbox.pack_start(button)
window.add(vbox)
window.show_all()
gtk.main()
EDIT2: Every input which can activate default widget must be ran
widget.set_activates_default(True)
http://www.pygtk.org/docs/pygtk/class-gtkdialog.html#method-gtkdialog--set-default-response
http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--set-default
Labels can have links by using Pango markup, but the "button-press-event" on a label is not emitted when the label is used in an Expander. I thought that if I created a subclass of Expander and emitted the "button-press-event" myself, the link would be clicked. A minimal example of "button-press-event" failing is given below:
import gtk
def on_activate(label, uri):
print(uri)
def on_click(widget, event):
label.emit('button-press-event', event)
window = gtk.Window()
expander = gtk.Expander()
window.add(expander)
label = gtk.Label('link')
label.set_use_markup(True)
label.connect("activate-link", on_activate)
expander.set_label_widget(label)
expander.connect("button-press-event", on_click)
window.connect("destroy", gtk.main_quit)
window.show_all()
gtk.mainloop()
If I add print calls, I can see that on_click() is being called, but on_activate() is not. The strange thing is, if I print the returns of label.emit(...), it prints False. What does that mean? How can I click the link?