Re: synchronize widgets without redundant signals



Thanks for the help. I am aware of the Gtk::Adjustment, though I have
never used it specifically outside of widgets that it is designed for. I
still see a problem here, and have created a short program to illustrate
one example.

This program has a scroll bar and an entry widget. As you slowly slide
the scroll bar towards the left, observe that the handle jumps at each
transition to the next lower integer. What is happening is that the
scroll bar is updating the adjustment, this signals the entry's
adjust_changed() member function. If the value of the adjustment changes
the entry, it updates with set_text(), which then calls the entry's
on_my_changed() function, which then sets the adjustment (again).

Since the entry is much less precise than the adjustment, the adjustment
is then changed (if it was at 6.9, say, then it would change to 6.0).

Clearly this is a partially contrived example, showing the problem a bit
exaggerated. However the problem does exist, and unless I am missing
something, I see no way around it. There are times when you want to
display a value in different formats, which may have limited precision
from the underlying "model".

If the program could know that the entry was updated by the set_text()
function instead of by the user's interaction, it would not have a need
to reset the adjustment, and the problem wouldn't exist.

What am I missing here?

Thanks.

Paul Davis wrote:
> On Sun, 2008-03-09 at 19:48 -0400, JLM wrote:
>> I am working on an application that will have multiple widgets that
>> display the same value in different ways. For example I could have a
>> scroll bar that represents a numeric value, and an entry that also
>> represents the same value. That way the user can either slide the scroll
>> bar or enter a value into the entry.
>>
>> What I am trying to avoid is having one value update cause multiple
>> signals to be emitted. The concern is that this could lead to an
>> infinite loop, particularly if the datatypes aren't exact with each
>> other, and one widget update rounds one way and another rounds another
>> for example.
>>
>> I'm looking for a way to call a widget's set_value() without having the
>> on_value_changed() called, or the signal_value_changed() emitted.
> 
> That's what you *think* you're looking for.
> 
> But what you're actually looking for is Gtk::Adjustment. In fact,
> precisely *one* Gtk::Adjustment that will be used by your scroll bar,
> spin buttons, and what ever else. Each "Control" widget will update the
> "Model" (Adjustment). The "Model" will emit "value_changed()" precisely
> once, and they will all update. Each one will check to see if the
> current value differs from the value they are showing in the "View". If
> it is they will change that to match the new value. Of course, spin
> buttons, scrollbars etc. do this automatically.
> 
> Before you start, google "model view controller programming".
> 
> --p
> 
> 
> 
//g++ -Wall -W -Wundef -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline -Werror -D__STDC_LIMIT_MACROS -Isrc/ `pkg-config --cflags --libs gtkmm-2.4 gtkglextmm-1.2` widget_test.cpp
#include <iostream>
#include <sstream>
#include <gtkmm.h>

class adjustment : public Gtk::Adjustment
{
  void on_value_changed() { Gtk::Adjustment::on_value_changed(); std::cout << "Value changed\n"; }
  void set_value(double x) { Gtk::Adjustment::set_value(x); std::cout << "Set value\n"; }
  void sig_val_changed() { std::cout << "Signal emitted\n"; }
  public:
    adjustment(double value, double lower, double upper, double step_increment=1, double page_increment=10,
               double page_size=0) : Gtk::Adjustment(value, lower, upper, step_increment, page_increment, page_size) {
      signal_value_changed().connect(sigc::mem_fun(*this, &adjustment::sig_val_changed)); }
};

class entry : public Gtk::Entry
{
  Gtk::Adjustment* adjust;
  void on_my_changed();
  void adjust_changed();
  public:
    entry(Gtk::Adjustment* b) : Gtk::Entry(), adjust(b) { signal_changed().connect(sigc::mem_fun(*this, &entry::on_my_changed)); adjust->signal_value_changed().connect(sigc::mem_fun(*this, &entry::adjust_changed)); }
};

void entry::on_my_changed()
{
  std::cout << "on_my_changed\n";
  std::stringstream tmp_str(get_text());
  gdouble val;
  tmp_str >> val;
  adjust->set_value(val);
}

void entry::adjust_changed()
{
  int val=int(adjust->get_value());
  std::stringstream temp_str;
  temp_str << val;
  set_text(temp_str.str());
}

int main(int argc, char* argv[])
{
  Gtk::Main kit(argc, argv);
  Gtk::Window window;
  adjustment adjust(10.0, 0.0, 10.0);
  Gtk::HScrollbar hscroll(adjust);
  hscroll.set_size_request(300,0);
  entry ent(&adjust);
  Gtk::HBox hbox(false, 2);
  hbox.pack_start(hscroll, true, true, 2);
  hbox.pack_start(ent, true, true, 2);
  window.add(hbox);
  window.show_all();
  Gtk::Main::run(window);
  return(0);
}


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