Simple, versatile and re-usable entry dialog (sometimes referred to as input dialog) in PyGTK

若如初见. 提交于 2019-11-28 13:48:35

Based on an example I found (thanks Ardoris!), I came up with a dialog subclass... hope it helps someone out there!

#!/usr/bin/env python
import gtk
class EntryDialog(gtk.MessageDialog):
    def __init__(self, *args, **kwargs):
        '''
        Creates a new EntryDialog. Takes all the arguments of the usual
        MessageDialog constructor plus one optional named argument 
        "default_value" to specify the initial contents of the entry.
        '''
        if 'default_value' in kwargs:
            default_value = kwargs['default_value']
            del kwargs['default_value']
        else:
            default_value = ''
        super(EntryDialog, self).__init__(*args, **kwargs)
        entry = gtk.Entry()        
        entry.set_text(str(default_value))
        entry.connect("activate", 
                      lambda ent, dlg, resp: dlg.response(resp), 
                      self, gtk.RESPONSE_OK)
        self.vbox.pack_end(entry, True, True, 0)
        self.vbox.show_all()
        self.entry = entry
    def set_value(self, text):
        self.entry.set_text(text)
    def run(self):
        result = super(EntryDialog, self).run()
        if result == gtk.RESPONSE_OK:
            text = self.entry.get_text()
        else:
            text = None
        return text

The run() method returns either the text entered in the entry box if the user presses <Enter> or clicks Ok. If Cancel is clicked or <Esc> pressed, the run() method returns None.

Except for that, the dialog should behave as any other gtk.MessageDialog instance.

Maybe that is not very general as it assumes you will always have Ok as an option, but that is what I need in 99% of my use cases anyway.

There isn't one available in GTK+. You've got two options:

  • Create a dialog, pack the Entry and any other content you need (probably the best way in my opinion)
  • Retrieve the content_area of the MessageDialog and append an Entry to it.

Something along the lines of:

#!/usr/bin/env python

import gtk

messagedialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK, message_format="Hello")

action_area = messagedialog.get_content_area()

entry = gtk.Entry()
action_area.pack_start(entry)

messagedialog.show_all()
messagedialog.run()
messagedialog.destroy()

Though it does probably need more refinement to get the Entry to display nicely.

Here's the function I wrote, based on the previous answers here. It's a function instead of a class, which means you can use it in one line.

def get_text(parent, message, default=''):
    """
    Display a dialog with a text entry.
    Returns the text, or None if canceled.
    """
    d = gtk.MessageDialog(parent,
                          gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                          gtk.MESSAGE_QUESTION,
                          gtk.BUTTONS_OK_CANCEL,
                          message)
    entry = gtk.Entry()
    entry.set_text(default)
    entry.show()
    d.vbox.pack_end(entry)
    entry.connect('activate', lambda _: d.response(gtk.RESPONSE_OK))
    d.set_default_response(gtk.RESPONSE_OK)

    r = d.run()
    text = entry.get_text().decode('utf8')
    d.destroy()
    if r == gtk.RESPONSE_OK:
        return text
    else:
        return None
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!