PyGTK: access buttons in gtk.MessageDialog? - python

I have a function that creates prompts using gtk.MessageDialog in PyGTK. How could I access the predefined buttons? Or would I need to manually construct a gtk.Dialog? I'd rather not, seeing as MessageDialog is a convenience function.
The function:
def gtkPrompt(self, name):
# Create new GTK dialog with all the fixings
prompt = gtk.MessageDialog(None, 0, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, name)
# Set title of dialog
prompt.set_title("Prompt")
# Create and add entry box to dialog
entry = gtk.Entry()
prompt.vbox.add(entry)
# Show all widgets in prompt
prompt.show_all()
# Run dialog until user clicks OK or Cancel
if prompt.run() == gtk.RESPONSE_CANCEL:
# User cancelled dialog
rval = False
else:
# User clicked OK, grab text from entry box
rval = entry.get_text()
# Destory prompt
prompt.destroy()
# Give the good (or bad) news
return rval

You can use get_children() to get to the "OK" button:
def yesNoDialog(window, message, default=False):
dialog=gtk.MessageDialog(window, gtk.DIALOG_MODAL |
gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION,
gtk.BUTTONS_YES_NO, message)
if default:
h_button_box=dialog.vbox.get_children()[1]
yes_button=h_button_box.get_children()[0]
yes_button.grab_default()
response=dialog.run()
dialog.destroy()
if response==gtk.RESPONSE_YES:
return True
else:
return False

Since 2.22 you can use get_widget_for_response() method. For example:
cancelButton = dialog.get_widget_for_response(response_id=gtk.RESPONSE_CANCEL)

gtk.MessageDialog is a subclass of gtk.Dialog. gtk.Dialog objects store their buttons in a gtk.HBox under the action_area attribute.
In code:
> prompt.action_area.get_children()
[<gtk.Button object at 0x18c0aa0 (GtkButton at 0x130e990)>, <gtk.Button object at 0x18c0af0 (GtkButton at 0x130e8d0)>]

Related

How to Enable Button if there is Item in ComboBox in pyqt5?

Hi, in this image i want to enable start button when USB name appear in combo-Box and if the name does not appear the button should disabled automatically, Here is My Code.
def x(self):
if (self.comboBox_3.currentIndex() == -1):
self.pushButton_5.setEnabled(False)
else:
self.pushButton_5.setEnabled(True)
You must use the currentIndexChanged signal to evaluate that logic:
# __init__ method
# ...
self.comboBox_3.currentIndexChanged[int].connect(self.on_currentIndexChanged)
def on_currentIndexChanged(self, index):
self.pushButton_5.setEnabled(index != -1)

Urwid: make cursor invisible

I'm using urwid, which is a Python "framework" for designing terminal user interfaces in ncurses. There's one thing though that I'm not able to do in urwid that was easy in curses - make the cursor invisible. As it is now, the cursor is visible when selecting buttons, and it just looks plain ugly. Is there a way to disable it?
I agree that the flashing cursor on an urwid.Button looks a bit lame, so I've come up with a solution to hide it. In urwid, the Button class is just a subclass of WidgetWrap containing a SelectableIcon and two Text widgets (the enclosing "<" and ">"). It's the SelectableIcon class that sets the cursor position to the first character of the label, by default. By subclassing SelectableIcon, modifying the cursor position and then wrapping it into an urwid.WidgetWrap subclass you can create your own custom button that can do all the tricks a built-in Button, or even more.
Here' what it looks like in my project.
import urwid
class ButtonLabel(urwid.SelectableIcon):
def __init__(self, text):
"""
Here's the trick:
we move the cursor out to the right of the label/text, so it doesn't show
"""
curs_pos = len(text) + 1
urwid.SelectableIcon.__init__(self, text, cursor_position=curs_pos)
Next, you can wrap a ButtonLabel object along with any other objects into a WidgetWrap subclass that will be your custom button class.
class FixedButton(urwid.WidgetWrap):
_selectable = True
signals = ["click"]
def __init__(self, label):
self.label = ButtonLabel(label)
# you could combine the ButtonLabel object with other widgets here
display_widget = self.label
urwid.WidgetWrap.__init__(self, urwid.AttrMap(display_widget, None, focus_map="button_reversed"))
def keypress(self, size, key):
"""
catch all the keys you want to handle here
and emit the click signal along with any data
"""
pass
def set_label(self, new_label):
# we can set the label at run time, if necessary
self.label.set_text(str(new_label))
def mouse_event(self, size, event, button, col, row, focus):
"""
handle any mouse events here
and emit the click signal along with any data
"""
pass
In this code, there is actually not much combination of widgets in the FixedButton WidgetWrap subclass, but you could add a "[" and "]" to the edges of the button, wrap it into a LineBox, etc. If all this is superfluous, you can just move the event handling functions into the ButtonLabel class, and make it emit a signal when it gets clicked.
To make the button reversed when the user moves on it, wrap it into AttrMap and set the focus_map to some palette entry ("button_reversed", in my case).
Building upon Drunken Master's answer, I've cleaned up the solution as much as possible.
The urwid.SelectableIcon is basically an urwid.Text field with this ugly blinking cursor.
So instead of overriding the urwid.SelectableIcon and packing it into an urwid.WidgetWrap, let's take an urwid.Text directly and make it selectable and react to button/mouse activation (inspired from urwid's simple menu tutorial):
import urwid
choices = u'Chapman Cleese Gilliam Idle Jones Palin'.split()
class ListEntry(urwid.Text):
_selectable = True
signals = ["click"]
def keypress(self, size, key):
"""
Send 'click' signal on 'activate' command.
"""
if self._command_map[key] != urwid.ACTIVATE:
return key
self._emit('click')
def mouse_event(self, size, event, button, x, y, focus):
"""
Send 'click' signal on button 1 press.
"""
if button != 1 or not urwid.util.is_mouse_press(event):
return False
self._emit('click')
return True
def menu(title, choices):
body = [urwid.Text(title), urwid.Divider()]
for c in choices:
button = ListEntry(c)
urwid.connect_signal(button, 'click', item_chosen, c)
body.append(urwid.AttrMap(button, None, focus_map='reversed'))
return urwid.ListBox(urwid.SimpleFocusListWalker(body))
def item_chosen(button, choice):
response = urwid.Text([u'You chose ', choice, u'\n'])
done = ListEntry(u'Ok')
urwid.connect_signal(done, 'click', exit_program)
main.original_widget = urwid.Filler(urwid.Pile([response,
urwid.AttrMap(done, None, focus_map='reversed')]))
def exit_program(button):
raise urwid.ExitMainLoop()
main = urwid.Padding(menu(u'Pythons', choices), left=2, right=2)
top = urwid.Overlay(main, urwid.SolidFill(u'\N{MEDIUM SHADE}'),
align='center', width=('relative', 60),
valign='middle', height=('relative', 60),
min_width=20, min_height=9)
urwid.MainLoop(top, palette=[('reversed', 'standout', '')]).run()
Works like a charm:
urwid uses the curs_set function, but does not expose it as a class method anywhere. Someone could modify urwid to allow using this method; otherwise there's no reliable method of doing this.
You might report it as an issue.
Along the lines of Drunken Master's answer, but with "minimally invasive surgery":
class ButtonLabel(urwid.SelectableIcon):
'''
use Drunken Master's trick to move the cursor out of view
'''
def set_text(self, label):
'''
set_text is invoked by Button.set_label
'''
self.__super.set_text(label)
self._cursor_position = len(label) + 1
class MyButton(urwid.Button):
'''
- override __init__ to use our ButtonLabel instead of urwid.SelectableIcon
- make button_left and button_right plain strings and variable width -
any string, including an empty string, can be set and displayed
- otherwise, we leave Button behaviour unchanged
'''
button_left = "["
button_right = "]"
def __init__(self, label, on_press=None, user_data=None):
self._label = ButtonLabel("")
cols = urwid.Columns([
('fixed', len(self.button_left), urwid.Text(self.button_left)),
self._label,
('fixed', len(self.button_right), urwid.Text(self.button_right))],
dividechars=1)
super(urwid.Button, self).__init__(cols)
if on_press:
urwid.connect_signal(self, 'click', on_press, user_data)
self.set_label(label)
Here, we only modify the button's appearance but otherwise leave its behaviour unchanged.

wxPython - Prevent the same warning dialog from appearing twice

I have a textctrl accepting user input. I want to check the text after the user enters it to see if it is also in a predefined list of words. I can do this check when the textctrl loses focus. I can also set it to check when the enter key is pressed. However, if I do both, the input is checked twice (not a huge deal, but not necessary). If the input is incorrect (the word is not in the list) then 2 error dialogs pop up. This is not ideal. What is the best way around this?
Edit: In case I wasn't clear, 2 warnings popup if the input is incorrect and Enter is hit. This causes one dialog to appear, which steals focus, causing the second to appear.
This demo code meets your criteria.
You should be able to test run it in its entirety in a separate file.
import sys; print sys.version
import wx; print wx.version()
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "hello frame")
self.inspected = True
self.txt = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
self.txt.SetLabel("this box must contain the word 'hello' ")
self.txt.Bind(wx.EVT_TEXT_ENTER, self.onEnter)
self.txt.Bind(wx.EVT_KILL_FOCUS, self.onLostFocus)
self.txt.Bind(wx.EVT_TEXT, self.onText)
def onEnter(self, e):
self.inspectText()
def onLostFocus(self, e):
self.inspectText()
def onText(self, e):
self.inspected = False
def inspectText(self):
if not self.inspected:
self.inspected = not self.inspected
if 'hello' not in self.txt.GetValue():
self.failedInspection()
else:
print "no need to inspect or warn user again"
def failedInspection(self):
dlg = wx.MessageDialog(self,
"The word hello is required before hitting enter or changing focus",
"Where's the hello?!",
wx.OK | wx.CANCEL)
result = dlg.ShowModal()
dlg.Destroy()
if result == wx.ID_OK:
pass
if result == wx.ID_CANCEL:
self.txt.SetLabel("don't forget the 'hello' !")
mySandbox = wx.App()
myFrame = TestFrame()
myFrame.Show()
mySandbox.MainLoop()
exit()
The strategy used was to add a flag to the instance to indicate if it has already been inspected and to overwrite the flag if the text changes.

Get input from custom dialog with entry, ok, and cancel button and return - Python/GTK3

In Python with gobject, I am having immense issues getting input from the user.
Here is my code:
def get_network_pw(self, e):
def okClicked(self):
print(pwd.get_text())
return pwd.get_text()
pwDialog.destroy()
def cancelClicked(self):
print("nope!")
pwDialog.hide()
return None
#Getting the about dialog from UI.glade
pwDialog = self.builder.get_object("passwordDialog")
okBtn = self.builder.get_object("pwdOkBtn")
cancelBtn = self.builder.get_object("pwdCancelBtn")
pwd = self.builder.get_object("userEntry")
# Opening the about dialog.
#okBtn.connect("clicked", okClicked)
#cancelBtn.connect("clicked", cancelClicked)
pwDialog.run()
I am not sure where I am going wrong? It refuses to return the userEntry text. I also tried the code from Python/Gtk3 : How to add a Gtk.Entry to a Gtk.MessageDialog? and Simple, versatile and re-usable entry dialog (sometimes referred to as input dialog) in PyGTK to no avail.
EDIT
I have a dialog I made in glade. It contains a GtkTextBox (userEntry), an Ok button (pwdOkBtn) and a cancel button (pwdCancelBtn). When the user clicks OK, it theoretically should return what they entered in the text box (say, 1234). When they click cancel, it should return None. However, when they click Ok, it returns "", and when they click cancel, it returns "". I'm not sure where I am going wrong here.
Extra code tries:
I tried the following code as well:
def get_network_pw(self, e):
d = GetInputDialog(None, "Enter Password")
dialog = d.run()
if dialog is 1:
print("OK")
else:
print("Nope!")
d.hide()
GetInputDialog:
class GetInputDialog(Gtk.Dialog):
def __init__(self, parent, title):
Gtk.Dialog._init(self, title, parent)
self.response = "Cancel"
self.setupHeader()
self.setupUI()
def setupUI(self):
wdg = self.get_content_area() #explained bellow
self.txtSource = Gtk.Entry() #create a text entry
wdg.add(self.txtSource)
self.show_all() #show the dialog and all children
def setupHeader(self, title="Get User Input"):
hb = Gtk.HeaderBar()
hb.props.show_close_button = True
hb.props.title = title
self.set_titlebar(hb)
btnOk = Gtk.Button("OK")
btnOk.connect("clicked", self.btnOkClicked)
hb.pack_start(btnOk)
btnCancel = Gtk.Button("Cancel")
btnCancel.connect("clicked", self.btnCancelClicked)
hb.pack_start(btnCancel)
def btnOkClicked(self, e):
self.response = "Ok" #set the response var
dst = self.txtSource #get the entry with the url
txt = dst.get_text()
return 1
def btnCancelClicked(self, e):
self.response = "Cancel"
return -1
I think you're overcomplicating it. The run method returns the id of the button pressed in a dialog:
Don't use the .hide() and .destroy() methods in that way, those are for different situations. .destroy() destroys the widget, so you should not call it unless you know what you're doing.
Place the .hide() after the .run().
Capture the return value of the run(), and setup the buttons in the dialog to a different Response ID in Glade.
The relevant part of the code is:
def _btn_cb(self, widget, data=None):
"""
Button callback
"""
ret = self.dialog.run()
self.dialog.hide()
if ret == 0:
self.label.set_text(
self.entry.get_text()
)
The full code for this example is here:
https://gist.github.com/carlos-jenkins/c27bf6d5d76723a4b415
Extra: If you want to check a condition to accept the Ok button (don't know, for example that the entry is valid) execute the run() in a while loop, check if button is Cancel then break, else check the validity of the input, if valid do something and break, else continue:
def _btn_cb(self, widget, data=None):
"""
Button callback
"""
while True:
ret = self.dialog.run()
if ret == -1: # Cancel
break
try:
entry = int(self.entry.get_text())
self.label.set_text(str(entry))
break
except ValueError:
# Show in an error dialog or whatever
print('Input is not an integer!')
self.dialog.hide()

wx.Radiobox.SetBackgroundColour("pink") won't change the color of RadioButton until mouse pass by

I've built a wx.Dialog, with some wx.Radiobox need to validate. If user doesn't make a choice, the validator wouldn't return True and popup a wx.MessageBox tells user that you should choose something. Meanwhile, the background color should have changed to pink.
The problem here is when using RadioBox.SetBackgroundColour("pink"), the Background color of RadioBox's label text changed to pink, which is perfectly normal, but the background color for RadioButton's label text won't change until mouse pass by.
I'm wondering why this and how to fix it. I've looked up in official docs and googled, but find nothing. Anyone have idea?
The platform is win8.1x64 and python 2.7.3 and wxpython 2.8.12.1. For using Psychopy standalone package, the version of both python and wxpython are quite old.
The Dialog as follow, a quite simple one :
class Dlg(wx.Dialog):
"""A simple dialogue box."""
def __init__(self):
global app
app = wx.PySimpleApp()
wx.Dialog.__init__(self, None,-1)
self.sizer = wx.FlexGridSizer(cols=1)
def show(self, cancelBTN=False):
"""Show a dialog with 2 RadioBox"""
# add two RadioBox
RadioBox1 = wx.RadioBox(self, -1, label="Wierd color", choices=["", "choice A", "choice B"], validator=RadioObjectValidator())
RadioBox2 = wx.RadioBox(self, -1, label="Wierd color", choices=["", "choice A", "choice B"], validator=RadioObjectValidator())
RadioBox1.ShowItem(0, show=False) # Hide the first choice
RadioBox2.ShowItem(0, show=False) # Hide the first choice
RadioBox1.GetValue = RadioBox1.GetStringSelection
RadioBox2.GetValue = RadioBox2.GetStringSelection
self.sizer.Add(RadioBox1, 1, wx.ALIGN_LEFT)
self.sizer.Add(RadioBox2, 1, wx.ALIGN_LEFT)
# add buttons for OK
self.sizer.Add(wx.Button(self, wx.ID_OK), 1, flag=wx.ALIGN_RIGHT)
self.SetSizerAndFit(self.sizer)
if self.ShowModal() == wx.ID_OK:
pass
# do something
self.Destroy()
And Validator as this:
class RadioObjectValidator(wx.PyValidator):
""" This validator is used to ensure that the user has entered something
into the text object editor dialog's text field.
"""
def __init__(self):
""" Standard constructor.
"""
wx.PyValidator.__init__(self)
def Clone(self):
""" Standard cloner.
Note that every validator must implement the Clone() method.
"""
return RadioObjectValidator()
def Validate(self, win):
""" Validate the contents of the given RadioBox control.
"""
RadioBox = self.GetWindow()
choice = RadioBox.GetValue()
if not choice:
wx.MessageBox(u'Choose something please', u'info', wx.OK | wx.ICON_EXCLAMATION)
RadioBox.SetBackgroundColour("pink")
RadioBox.SetFocus()
RadioBox.Refresh()
return False
else:
RadioBox.SetBackgroundColour(
wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
RadioBox.Refresh()
return True
def TransferToWindow(self):
""" Transfer data from validator to window.
The default implementation returns False, indicating that an error
occurred. We simply return True, as we don't do any data transfer.
"""
return True # Prevent wxDialog from complaining.
def TransferFromWindow(self):
""" Transfer data from window to validator.
The default implementation returns False, indicating that an error
occurred. We simply return True, as we don't do any data transfer.
"""
return True # Prevent wxDialog from complaining.
And simply run like this:
if __name__ == "__main__":
test = Dlg()
test.show()
Well, it's a bug in wxpython2.8.12.1, and has fixed in wxpython3.0.0.0, Thanks #GreenAsJade for reminding.

Categories

Resources