Re: GtkEntry input filters



"Carl B. Constantine" <duckwing duckwing ca> writes:

> I have a GtkEntry in my app where the only thing I want to be able to
> input is numbers. I don't want letters or characters like (, * &, -, ),
> and so forth.
>
> Anyone know how to write such an input filter?

Here's one I prepared earlier.  You can use it with Glade, too.  Use
like this:

NumericEntry<int> int_entry(20); // integer entry with value
NumericEntry<double> double_entry(0.0, -1.0, 1.0) // double with
                                                  // initial value
                                                  // and limits.

I hope this is useful.  I'd appreciate any "constructive criticism"
anyone has to offer!

HTH,
Roger


// numeric entry widget                                          -*- C++ -*-
// $Id: numericentry.h,v 1.2 2003/12/14 16:14:54 roger Exp $
//
// Copyright (C) 2003 Roger Leigh.
//
// Authors: Roger Leigh <rleigh debian org>
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
//
////////////////////////////////////////////////////////////////////////////

#ifndef GTKMM_RLEXTRA_NUMERICENTRY_H
#define GTKMM_RLEXTRA_NUMERICENTRY_H

#include <limits>
#include <sstream>

#include <gtkmm/entry.h>
#include <libglademm/xml.h>

namespace Gtkmm
{
  /**
   * Entry widget for numeric values.

   * This widget may be used for entering numeric values.  Unlike
   * Gtk::SpinButton, this widget does not have spinbuttons.  Being a
   * template class, it may be used to enter values for any numeric
   * data type, for example int, long, double or any numeric classes
   * that behave like numbers (they must be Assignable and
   * comparable).
   *
   * This widget requires that minumum and maximum limits are set, so
   * that values outside these bounds can not be entered.  If
   * unspecified, these values default to those obtainable through
   * std::numeric_limits<>.
   *
   * Future enhancements will include validation through regular
   * expressions, and specifying the range of precision allowed.
   */
  template<typename N>
  class NumericEntry : public Gtk::Entry
  {
  public:
    /**
     * The constructor.
     * @param value the initial value of the number displayed.
     * @param min the minimum value allowed.
     * @param max the maxumum value allowed.
     */
    NumericEntry(N value,
		 N min = std::numeric_limits<N>::min(),
		 N max = std::numeric_limits<N>::max()):
      m_error(false),
      m_min(min),
      m_max(max)
    {
      set_value(value);
    }

    /**
     * Constructor for initialisation from a Glade interface description.
     * @param cobject the GTK+ C object.
     * @param xml_interface the Glade XML interface.
     */
    explicit NumericEntry(BaseObjectType* cobject,
			  const Glib::RefPtr<Gnome::Glade::Xml>& xml_interface):
      Gtk::Entry(cobject),
      m_error(false),
      m_min(std::numeric_limits<N>::min()),
      m_max(std::numeric_limits<N>::max())
    {}

    /// The destructor.
    virtual ~NumericEntry()
    {}

    /**
     * Check if an error has occured.
     * An error occurs when an invalid number has been entered (for
     * example, out of bounds).  In this situation, get_value() may
     * not return an accurate or meaningful result.
     * @returns true if in an error state, or false if no error.
     */
    bool error() const
    {
      return m_error;
    }

    /**
     * Get the value of the number in the entry.
     * Make sure to check the error status with error() before calling
     * this method.
     * @returns the current value of the entry.
     */
    N get_value() const
    {
      std::istringstream input(get_text());
      N ret;
      input >> ret;
      return ret;
    }

  private:
    /**
     * Check if the number is within the specified bounds.  If outside
     * the bounds, clip to the appropriate limit.
     */
    void check_bounds(N& value)
    {
      if (value < m_min)
	value = m_min;
      if (value > m_max)
	value = m_max;
    }

  public:
    /**
     * Set the value of the number in the entry.
     * The value will be clipped to the specified bounds, if necessary.
     * @param value the value to set.
     */
    void set_value(N value)
    {
      check_bounds(value);

      std::ostringstream output;
      output << value;
      set_text(output.str());
    }

    /**
     * Get the maximum value allowed.
     * @returns the maximum value.
     */
    N get_max() const
    {
      return m_max;
    }

    /**
     * Set the maximum value allowed.
     * The minimum and current value will be clipped if necessary.
     * @param value the maximum value.
     */
    void set_max(N value)
    {
      if (value < m_min)
	m_min = value;
      m_max = value;

      N num = get_value();
      check_bounds(num);
      set_value(num);
    }

    /**
     * Get the minimum value allowed.
     * @returns the minimum value.
     */
    N get_min() const
    {
      return m_min;
    }

    /**
     * Set the minimum value allowed.
     * The maximum and current value will be clipped if necessary.
     * @param value the minimum value.
     */
    void set_min(N value)
    {
      if (value > m_max)
	m_max = value;
      m_min = value;

      N num = get_value();
      check_bounds(num);
      set_value(num);
    }

    /// Signal hander run when the entry has changed.
    virtual void on_changed()
    {
      m_error = false;

      // Filter out all characters except +-.,0123456789

      Glib::ustring orig = get_text();
      Glib::ustring stripped;

      Glib::ustring::iterator cur;
      for (cur = orig.begin();
	   cur != orig.end();
	   ++cur)
	{
	  if ((*cur >= '0' && *cur <= '9') ||
	      *cur == '+' || *cur == '-' ||
	      *cur == '.' || *cur == ',')
	    stripped += *cur;
	}

      if (orig.compare(stripped) != 0)
	set_text(stripped);

      std::istringstream input(get_text());
      N number;
      input >> number;
      if (input.fail())
	m_error = true;
      else
	if (number < m_min || number > m_max)
	  m_error = true;

      if (m_error == true)
	modify_base(Gtk::STATE_NORMAL, Gdk::Color("red"));
      else
	modify_base(Gtk::STATE_NORMAL, Gdk::Color(NULL));
    }

  protected:
    /// Error status.
    bool m_error;
    /// Minimum value.
    N m_min;
    /// Maximum value.
    N m_max;

  }; // class NumericEntry

}; // namespace Gtkmm


#endif // GTKMM_RLEXTRA_NUMERICENTRY_H



-- 
Roger Leigh

                Printing on GNU/Linux?  http://gimp-print.sourceforge.net/
                GPG Public Key: 0x25BFB848.  Please sign and encrypt your mail.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]