Re: [gtkmm] filter or validate



Eduardo Andrés Mizerit <eamlinux yahoo com ar> writes:

> I would setup a Gtk::Entry widget such that it only accepts numerical
> characters and drops any other characters.
> I need an example about it.

Easy ;-)

Here's one I prepared earlier.  I'm sure you could adapt it to your
needs.

Validation is immediate, but if you use on_activated() and
on_focus_out_event() rather than on_changed() this could be deferred.

It's a template, so can be used with any numeric type.  For example:

// integer entry for numbers between 0 and 10, defaulting to 1
NumericEntry<int> int_entry(1,0,10);
// double precision floating point entry, with the whole range of
// double
NumericEntry<double> double_entry(0.0);

It can also be used with Glade/libglade and get_widget_derived():

  Glib::RefPtr<Gnome::Glade::Xml> xml = ...
  NumericEntry<long> *entry;
  xml->get_widget_derived("entry_name", *entry);


// 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 numberic 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 _Number>
  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(_Number value,
		 _Number min = std::numeric_limits<_Number>::min(),
		 _Number max = std::numeric_limits<_Number>::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<_Number>::min()),
      m_max(std::numeric_limits<_Number>::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.
     */
    _Number get_value() const
    {
      std::istringstream input(get_text());
      _Number 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(_Number& 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(_Number value)
    {
      check_bounds(value);

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

    /**
     * Get the maximum value allowed.
     * @returns the maximum value.
     */
    _Number 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(_Number value)
    {
      if (value < m_min)
	m_min = value;
      m_max = value;

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

    /**
     * Get the minimum value allowed.
     * @returns the minimum value.
     */
    _Number 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(_Number value)
    {
      if (value > m_max)
	m_max = value;
      m_min = value;

      _Number 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());
      _Number 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.
    _Number m_min;
    /// Maximum value.
    _Number 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]