Hexadecimal spin button

is it possible to have a hexadecimal spin button using GTK in C Language

Yes, see the gtk-demo example (the two functions are hooked up to the input and output signals in the .ui file).

You probably want the GTK3 version, given the API changes of GTK4.

Here is small code I have written. It is fine from 00 to 09. But at 0A it is reverting to 00.
Could you please help me identify the issue

#include <gtk/gtk.h>
#include <math.h>

gboolean callback( GtkSpinButton *spin, gpointer data )
{
	//printf( "begin\n" );
	int value = gtk_spin_button_get_value_as_int( spin );
	gchar *text = g_strdup_printf ("%02X", value);
	//printf( "%s\n", text );
	gtk_entry_set_text (GTK_ENTRY (spin), text);
	g_free (text);
	//printf( "end\n" );
	return TRUE;
}

int main()
{
	gtk_init( NULL, NULL );
	GtkWidget *const window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
	gtk_window_set_default_size( GTK_WINDOW(window), 100, 100 );
     g_signal_connect( window, "destroy", G_CALLBACK(gtk_main_quit), NULL );
	GtkWidget *box = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );

	gtk_container_add( (GtkContainer*)window, box );
	GtkWidget *spin = gtk_spin_button_new_with_range( 0, 255, 1 );
	gtk_box_pack_start( (GtkBox*)box, spin, FALSE, FALSE, 5 );
	g_signal_connect( spin, "output", G_CALLBACK(callback), NULL );
	gtk_widget_show_all( window );
	gtk_main();
	return 0;
}

You don’t handle the inputsignal which validates the input. By default, only numerical characters are accepted.

Dear Florian,

I am handling only output signal. Not input signal.
I am naive to this environment. Could you please suggest right fix.

Right, that’s why non-numeric characters like “A” or “C” aren’t accepted. See the linked demo for an appropriate input signal handler.

to certain extent, following is working. But plus and minus buttons not working now.

#include <gtk/gtk.h>
#include <math.h>

gboolean callback_input( GtkSpinButton *spin, gpointer data )
{
	char const *entry_text = gtk_entry_get_text( (GtkEntry*)spin );
	long int value = strtol( entry_text, NULL, 16 );
	if( value > 255 )
		value = 0;
	char text[3];
	sprintf( text, "%02lX", value );
	gtk_entry_set_text ( (GtkEntry*)spin, text );
	return TRUE;
}

gboolean callback_output( GtkSpinButton *spin, gpointer data )
{
	return TRUE;
}

int main()
{
	gtk_init( NULL, NULL );
	GtkWidget *const window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
	gtk_window_set_default_size( GTK_WINDOW(window), 100, 100 );
	g_signal_connect( window, "destroy", G_CALLBACK(gtk_main_quit), NULL );
	GtkWidget *box = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );

	gtk_container_add( (GtkContainer*)window, box );
	GtkWidget *spin = gtk_spin_button_new_with_range( 0, 255, 1 );
	gtk_box_pack_start( (GtkBox*)box, spin, FALSE, FALSE, 5 );
	gtk_spin_button_set_numeric( (GtkSpinButton*)spin, FALSE );
	g_signal_connect( spin, "input", G_CALLBACK(callback_input), NULL );
	g_signal_connect( spin, "output", G_CALLBACK(callback_output), NULL );
	gtk_widget_show_all( window );
	gtk_main();
	return 0;
}

Look, you were giving a link to example code that implements handlers for the two signals, hex_spin_input() and hex_spin_output(). All you have to do is to copy and paste those functions into your code.

Sure, tweak the output handler to not use the 0x prefix, but you cannot expect it to magically work for the input signal.

Dear Florian,

Thanks for your suggestion.
Copy pasted. It is working. One concern.
w.r.t. callback_input, I am passing NULL as parameter. What should be the right parameter ?
Because we are using new_val.

#include <gtk/gtk.h>
#include <math.h>

gint callback_input( GtkSpinButton *spin_button, gdouble *new_val )
{
	const gchar *buf;
	gchar *err;
	gdouble res;
	
	buf = gtk_entry_get_text (GTK_ENTRY (spin_button));
	res = strtol (buf, &err, 16);
	*new_val = res;
	if (*err)
		return GTK_INPUT_ERROR;
	else
		return TRUE;
}

gboolean callback_output( GtkSpinButton *spin_button, gpointer data )
{
	GtkAdjustment *adjustment;
	gchar *buf;
	gint val;
	
	adjustment = gtk_spin_button_get_adjustment (spin_button);
	val = (gint) gtk_adjustment_get_value (adjustment);
	if (fabs (val) < 1e-5)
		buf = g_strdup ("0x00");
	else
		buf = g_strdup_printf ("0x%.2X", val);
	if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button))))
		gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
	g_free (buf);
	
	return TRUE;
}

int main()
{
	gtk_init( NULL, NULL );
	GtkWidget *const window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
	gtk_window_set_default_size( GTK_WINDOW(window), 100, 100 );
	g_signal_connect( window, "destroy", G_CALLBACK(gtk_main_quit), NULL );
	GtkWidget *box = gtk_box_new( GTK_ORIENTATION_VERTICAL, 5 );

	gtk_container_add( (GtkContainer*)window, box );
	GtkWidget *spin = gtk_spin_button_new_with_range( 0, 255, 1 );
	gtk_box_pack_start( (GtkBox*)box, spin, FALSE, FALSE, 5 );
	gtk_spin_button_set_numeric( (GtkSpinButton*)spin, FALSE );
	g_signal_connect( spin, "input", G_CALLBACK(callback_input), NULL );
	g_signal_connect( spin, "output", G_CALLBACK(callback_output), NULL );
	gtk_widget_show_all( window );
	gtk_main();
	return 0;
}

NULL is fine. The signal handler actually has a third parameter, which the demo code omits. That parameter is the user_data argument that is common to all signals, and which is what you specify when connecting the handler.