Re: MVC and GTK



>Here's how to do it, cleanly, with existing GTK+:

  [ ... ]

Owen, having worked hard to find an example that would contradict
yours, plus having used the same basic method as you suggest quite a
lot, I broadly agree with you. But the toggle button case needs a
correction.

I still have a bad feeling about all this, but perhaps there really is
no cleaner way to do MVC. After all, the whole idea of a "silent"
change in the state of an object that others have a registered
interest in seems very dangerous.

Anyway, here's a revised walk through the toggle button example to
show how I handle this these days:

void
my_data_set_state (MyData *my_data, gboolean new_state)
{
     if (my_data->state == new_state)
         return;
 
     my_data->state = new_state;
     // generic C/C++ psuedocode
     signal_emit (SIGNAL_OBJECT(my_data),"state-changed"); 
}

void
state_change_handler (MyData *my_data)

{
   gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(button));
					    
   if (my_data->state != active) {
          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), 
                                        my_data->state);
   }
}

void
toggled_handler (GtkWidget *button, gpointer data)
{
  MyData *my_data = data;
  gboolean new_state = 
     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
 
  if (my_data->state != new_state)
      my_data_set_state (my_data, new_state);
}

So far, so good.

but now lets get a little more precise. the role of the toggle button
is to both *initiate* a change in the state and also to *display* the
current state. the initiation of the change doesn't guarantee that the
state will change or when it will change, and the button shouldn't
change its appearance until the state has really altered.

so using "toggled" doesn't really work at all, since by the time its
been emitted, the button has already (effectively) been modified. 

instead, we have to use button_press_event and stop propagation of the
event for the time being. so now we have:

gint
button_press_handler (GtkWidget *widget, GdkEventButton *ev, gpointer *data)

{
	MyData *my_data = (My_Data *) data;
	gboolean old_state = 
	   gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
						
        if (my_data->state == old_state) {

	      [ initiate change to !old_state, which may take a while
	        to be carried out and may happen in another thread ]
        }

        gtk_signal_emit_stop_by_name (GTK_OBJECT(button), 
				      "button_press_event");
}

then we have a handler for the state change as shown above. 

it works. so we have to avoid using "toggled" at all, since it comes
too late in the game. And thats the key for toggle buttons. Even so,
this is pretty "deep" GTK coding, in the sense that its totally
unintuitive for the newish GTK user.

--p




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