Search code examples
user-interfacewxpython

wxPython text field entry special effects including text entry event and clicking inside text field event


I am creating a wxPython based GUI (my first experience with creating GUIs). Several elements of the GUI are text entry fields, where the user is able to enter data into a text field (e.g. TextCtrl).

I'm trying to create a common effect in text entry fields where, before data is entered into the text field, there is a default indication of what should be placed in the text field (e.g. "Enter data here") which is grayed out until any text is entered. If the field is absent of user input, I would like for this default indication to show up again.

A great example of something of this sort is in the "Title" field of the stackoverflow question entry form, which says "What's your programming question? Be specific." Although, in this case there is yet another effect where, when I click inside the text field, the text turns lighter grey, and only disappears once I've entered something.

If TextCtrl is able to do this, how? I've tried to do this but I've been unsuccessful. Rather than demonstrate by example how I've been unsuccessful, I'd like to just ask how to do it.

Is there a class I should be using besides TextCtrl for these types of effects?

In the following code, I've tried to convey only the essential parts. I think the code would work though.

import wx

class FormTab(wx.Panel):

  def __init__(self, *args, **kwargs):
    super(FormTab, self).__init__(*args, **kwargs)
    self.createControls()
    self.bindEvents()
    self.doLayout()

  def createControls(self):
    self.exeTextCtrl = wx.TextCtrl(self, value="Executable")
    font=wx.Font(8,wx.DEFAULT,wx.ITALIC,wx.NORMAL)
    self.exeTextCtrl.SetFont(font)

  def bindEvents(self):
    for control, event, handler in \
      [(self.exeTextCtrl, wx.EVT_LEFT_DOWN, self.onExeReady),
       (self.exeTextCtrl, wx.EVT_TEXT, self.onExeEntered)]:
      control.Bind(event, handler)

  def onExeReady(self, event):
    self.exeTextCtrl.SetValue('')
    font=wx.Font(8,wx.DEFAULT,wx.NORMAL,wx.NORMAL)
    self.exeTextCtrl.SetFont(font)
    event.Skip()

  def onExeEntered(self, event):
    exclass.exe=event.GetString()

  def doLayout(self):
    raise NotImplementedError # done in parent class

class FormTabLayout(FormTab):
  def doLayout(self):
    boxSizer = wx.BoxSizer(orient=wx.HORIZONTAL)
    # A GridSizer will contain the other controls:
    gridSizer = wx.FlexGridSizer(rows=12, cols=1, vgap=10, hgap=10)
    expandOption = dict(flag=wx.EXPAND)
    for control, options in \
            [(self.exeTextCtrl, expandOption)]:
        gridSizer.Add(control, **options)

    for control, options in \
            [(gridSizer, dict(border=5, flag=wx.ALL))]:
        boxSizer.Add(control, **options)

    self.SetSizerAndFit(boxSizer)


class Exclas():
  def __init__(self):
    self.exe=""

class FrameWithForms(wx.Frame):
  def __init__(self, *args, **kwargs):
    super(FrameWithForms, self).__init__(*args, **kwargs)
    notebook = wx.Notebook(self)
    self.form1 = FormTabLayout(notebook)
    notebook.AddPage(self.form1, 'Options') # tab
    self.SetClientSize(notebook.GetBestSize())

if __name__=='__main__':
  exclass=Exclas()
  app = wx.App(redirect=True, filename='mylog.txt')
  frame = FrameWithForms(None, title='Example GUI')
  frame.Show()
  app.MainLoop()

Thank you.


Solution

  • You could use a wx.SearchCtrl with the SearchButton, CancelButton ect set to not be shown and use the method SetDescriptiveText for setting your default text.

    The search control is a wx.TextCtrl with added functionality.