IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GTK+ avec C & C++ Discussion :

Gtkspinbutton ou un spin bouton discret


Sujet :

GTK+ avec C & C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Par défaut Gtkspinbutton ou un spin bouton discret
    Hello la team Gtk,

    habituellement je viens sur ce forum pour poser une question suite à un problème.

    Cette fois c’est pour faire un petit cadeau.

    Le code est livré plus loin.

    Dans le programme gtk3-demo il y a certaine petite merveille il faut le dire.

    Notamment la démo du spinbutton m’a particulièrement attiré pour la possibilité offerte de gérer un spinbutton avec des valeurs discrètes (celle d’un tableau ou d’une liste).

    J’ai reconstitué du code «*pur*» Gtk sans passer par du xml et Glade. Les neurones ont un peu chauffé pour mettre les mains dans le cambouis*!!!!!!!.

    Résultat:
    un callback standardisé spin_button_input. Un tel callback permet par exemple d'actualiser la valeur numérique interne du SpinButton à partir de l'entry interne du spinbutton

    * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
    * la sortie est new_val

    Pour l’appeler on capture le signal input
    Au passage en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR. Mais je n’en ai pas besoin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    static gint spin_button_input (GtkSpinButton *spinbutton, gdouble * new_val, gpointer data)
    {
    	/** peu documenté un tel callback permet par exemple d'actualiser 
             * la valeur numérique interne du SpinButton (pointé avec new_val) à partir de l'entry interne du spinbutton
             * 
             * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
             * la sortie est new_val
             * 
             * en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR 
             **/
    	gint index;
    	gchar *candidate_char, *wanted_char;
    	gboolean found = FALSE;
     
    	tab_t * array = (tab_t *) data;
     
    	for (index = 1; index <= array->len; index++)  
        {
    		candidate_char = g_ascii_strup (array->value_tab[index - 1], -1);
    		/** comme le spinbutton a un gtk_entry qui a été chargé avec une valeur de texte
                    * on peut le comparer a une valeur dans un tableau. A partir du rang trouvé **/
    		wanted_char = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (spinbutton)), -1);
    		if (strstr (candidate_char, wanted_char) == candidate_char)
    		{
    			g_print(" on cherchait %s et on l'a trouvé\n",wanted_char);
    			found = TRUE;
    		}
    		g_free (wanted_char);
    		g_free (candidate_char);
    		if (found)
    			break;
        }
    	if (!found)
        {
    		*new_val = 0.0;
    		return GTK_INPUT_ERROR;
        }
        // actualisation ici
    	*new_val = (gdouble) index;
    	g_print( " la valeur de new_val est %d\n",index);
    	return TRUE;
    }
    le callback suivant est le contraire du précédent spin_button_output

    ce callback actualise une valeur de texte du gtkentry d'un spinbutton

    * la donnée d'entrée numérique est celle de l' adjustement du spinbutton
    * la sortie est l'actualisation du Gtkentry avec une valeur du tableau

    Pour l’appeler on capture le signal output

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    static gint spin_button_output (GtkSpinButton *spin_button, gpointer * data)
    {
    	/** ce callback actualise une valeur de texte du gtkentry
             * d'un spinbutton 
             * 
             * la donnée d'entrée numérique est celle de l' adjustement du spinbutton 
             * la sortie est l'actualisation du Gtkentry avec une valeur du tableau
             * **/
    	GtkAdjustment *adjustment;
    	gdouble value;
    	gint i;
     
    	tab_t * array = (tab_t *) data;
     
    	adjustment = gtk_spin_button_get_adjustment (spin_button);
    	value = gtk_adjustment_get_value (adjustment);
    	g_print( " la valeur de value du spinbutton  est %d\n", (gint) value);	
     
    	for (i = 1; i <= array->len; i++)
        if (fabs (value - (double)i) < 1e-5)
    	{
    		if (strcmp (array->value_tab[i-1], gtk_entry_get_text (GTK_ENTRY (spin_button))))
    			gtk_entry_set_text (GTK_ENTRY (spin_button), array->value_tab[i-1]);
    	}
    	return TRUE;
    }
    la cerise sur le gateau de la démo des développeurs est de fournir une commande Gobject pour synchroniser un widget avec la valeur d’un autre en 2 coups de cuillère à pot.

    Voici un code complet en tout modestie. D’ailleurs je critique déjà le code qui utilise un tableau dont la taille doit être limitée. Une première amélioration pour un code plus robuste et propre serait d’utiliser une GList au lieu d’un tableau.

    Le code en totalité avec la commande pour le compiler pour ceux qui découvrent Gtk en version 3.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    #include <gtk/gtk.h>
    #include <glib/gi18n.h>
    #include <math.h>
    #include <stdlib.h>
     
    //test_spine_discret_test.c
    /*  Compile with:
     * 
     *  gcc -std=c11 -Wall -fmax-errors=10 -Wextra test_spine_discret_test.c -o test_spine_discret_test `pkg-config --cflags --libs gtk+-3.0`
     */
     
    typedef struct
    	{
    	/* ----- longueur du tableau  ---------- */
    	gint len;
    	/* ----- widget value --------- */
    	gchar *value_tab[50]; // obligé de mettre une limite ?
    	} tab_t;
     
    void cb_quit (GtkWidget *widget, gpointer user_data)
    {
    	gtk_main_quit();
    	/* parametres inutilises */
    	(void)widget;
    	(void)user_data;
    }
     
    static gint spin_button_input (GtkSpinButton *spinbutton, gdouble * new_val, gpointer data)
    {
    	/** peu documenté un tel callback permet par exemple d'actualiser 
             * la valeur numérique interne du SpinButton (pointé avec new_val) à partir de l'entry interne du spinbutton
             * 
             * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
             * la sortie est new_val
             * 
             * en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR 
             **/
    	gint index;
    	gchar *candidate_char, *wanted_char;
    	gboolean found = FALSE;
     
    	tab_t * array = (tab_t *) data;
     
    	for (index = 1; index <= array->len; index++)  
        {
    		candidate_char = g_ascii_strup (array->value_tab[index - 1], -1);
    		/** comme le spinbutton a un gtk_entry qui a été chargé avec une valeur de texte
                    * on peut le comparer a une valeur dans un tableau. A partir du rang trouvé **/
    		wanted_char = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (spinbutton)), -1);
    		if (strstr (candidate_char, wanted_char) == candidate_char)
    		{
    			g_print(" on cherchait %s et on l'a trouvé\n",wanted_char);
    			found = TRUE;
    		}
    		g_free (wanted_char);
    		g_free (candidate_char);
    		if (found)
    			break;
        }
    	if (!found)
        {
    		*new_val = 0.0;
    		return GTK_INPUT_ERROR;
        }
        // actualisation ici
    	*new_val = (gdouble) index;
    	g_print( " la valeur de new_val est %d\n",index);
    	return TRUE;
    }
     
    static gint spin_button_output (GtkSpinButton *spin_button, gpointer * data)
    {
    	/** ce callback actualise une valeur de texte du gtkentry
             * d'un spinbutton 
             * 
             * la donnée d'entrée numérique est celle de l' adjustement du spinbutton 
             * la sortie est l'actualisation du Gtkentry avec une valeur du tableau
             * **/
    	GtkAdjustment *adjustment;
    	gdouble value;
    	gint i;
     
    	tab_t * array = (tab_t *) data;
     
    	adjustment = gtk_spin_button_get_adjustment (spin_button);
    	value = gtk_adjustment_get_value (adjustment);
    	g_print( " la valeur de value du spinbutton  est %d\n", (gint) value);	
     
    	for (i = 1; i <= array->len; i++)
        if (fabs (value - (double)i) < 1e-5)
    	{
    		if (strcmp (array->value_tab[i-1], gtk_entry_get_text (GTK_ENTRY (spin_button))))
    			gtk_entry_set_text (GTK_ENTRY (spin_button), array->value_tab[i-1]);
    	}
    	return TRUE;
    }
     
    static gboolean value_to_label (GBinding     *binding,
                    const GValue *from,
                    GValue       *to,
                    gpointer      user_data)
    {
    	/** synchronise le label à partir de l'adjustement **/
    	g_value_take_string (to, g_strdup_printf ("%g", g_value_get_double (from)));
    	return TRUE;
    	/* Parametre inutilise */
    	(void)binding;	
    	(void)user_data;	
    }
     
    static void do_spinbutton (GtkApplication *app)
    {
    	tab_t * month_array = g_slice_new (tab_t);
     
    	month_array->len =12;
    	month_array->value_tab[0] = "January";
    	month_array->value_tab[1] = "February";
    	month_array->value_tab[2] = "March";
    	month_array->value_tab[3] = "April";
    	month_array->value_tab[4] = "May";
    	month_array->value_tab[5] = "June";
    	month_array->value_tab[6] = "July";
    	month_array->value_tab[7] = "August";
    	month_array->value_tab[8] = "September";
    	month_array->value_tab[9] = "October";	
    	month_array->value_tab[10] = "November";
    	month_array->value_tab[11] = "December";
     
    	tab_t * day_array = g_slice_new (tab_t);
     
    	day_array->len =7;
    	day_array->value_tab[0] = "lundi";
    	day_array->value_tab[1] = "mardi";
    	day_array->value_tab[2] ="mercredi";
    	day_array->value_tab[3] ="jeudi";
    	day_array->value_tab[4] = "vendredi";
    	day_array->value_tab[5] ="samedi";
    	day_array->value_tab[6] ="dimanche";
     
      	/* Create a window with a title, and a default size */
    	GtkWidget *window = gtk_application_window_new (app);
     
    	/* Creation du conteneur principal */
    	GtkWidget *main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    	GtkWidget *vertical_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    	gtk_container_add (GTK_CONTAINER (window), vertical_box);
     
    	/* taille minimum */
    	gtk_window_set_default_size  (GTK_WINDOW (window), 500, -1);
     
    	/*création d'une bordure interne à la fenêtre window*/ 
    	gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    	gtk_window_set_title (GTK_WINDOW (window),"test de spin button discret avec adjustement ");
     
    	g_signal_connect (window, "delete_event",G_CALLBACK (cb_quit), NULL);
     
    	double value_month = 6;
    	GtkAdjustment * adjustement_button_month = gtk_adjustment_new (value_month,1, 13,1,1,1); 
    	double value_day = 2;
    	GtkAdjustment * adjustement_button_day = gtk_adjustment_new (value_day,1, 8,1,1,1); 
     
    	GtkWidget * spinbutton_month = gtk_spin_button_new(adjustement_button_month,1,1);
    	gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_month),20);
    	gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_month),"Utilisez le + ou le - pour faire défiler les mois ou les flèches clavier V /\\");
    	/** Définit l'indicateur qui détermine si la valeur d'un bouton de rotation revient 
             * à la limite opposée lorsque la limite supérieure ou inférieure de la plage est dépassée. **/
    	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_month), TRUE);
     
    	GtkWidget * spinbutton_day = gtk_spin_button_new(adjustement_button_day,1,1);
    	gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_day),20);
    	gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_day),"Utilisez le + ou le - pour faire défiler les jours ou les flèches clavier V /\\");
     
    	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_day), TRUE);
     
    	GtkWidget * month_label = gtk_label_new(NULL);
    	GtkWidget * legende_month_label = gtk_label_new("Numéro du mois");
    	GtkWidget * day_label = gtk_label_new(NULL);
    	GtkWidget * legende_day_label = gtk_label_new("Numéro du jour de la semaine");
     
    	int expand = TRUE ;
    	int fill = TRUE;
    	int padding =1;
     
    	// pour le premier spin month
    	gtk_box_pack_start (GTK_BOX (main_box), spinbutton_month, !expand, fill, padding);
    	GtkWidget * Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), legende_month_label, !expand, fill, padding);
    	gtk_box_pack_start (GTK_BOX (main_box), month_label, !expand, fill, padding);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
    	// pour le spin day
    	main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     
    	gtk_box_pack_start (GTK_BOX (main_box), spinbutton_day, !expand, fill, padding);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), legende_day_label, !expand, fill, padding);
    	gtk_box_pack_start (GTK_BOX (main_box), day_label, !expand, fill, padding);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
    	/** The output signal can be used to change to formatting of the value that 
             * is displayed in the spin buttons entry. **/
    	g_signal_connect (spinbutton_month, "output", G_CALLBACK (spin_button_output), month_array);
    	g_signal_connect (spinbutton_day, "output", G_CALLBACK (spin_button_output), day_array);
     
    	/** par rapport à la demo gtk3-demo module spinbutton j'ai rajouté un paramètre pour le callback
             * g_signal_connect (spinbutton, "input", G_CALLBACK (month_spin_input));
             **/
    	g_signal_connect (spinbutton_month, "input", G_CALLBACK (spin_button_input), month_array); 
    	g_signal_connect (spinbutton_day, "input", G_CALLBACK (spin_button_input), day_array); 
     
    	/**  la méthode suivante vue dans gtk3-demo module spinbutton 
             * la synchro est automatique du spinbutton vers le label et c'est 
             * la fonction value_to_label qui réalise l'action à faire 
             * Gobject va collecter la valeur du champ value du adjustement_button_month pour 
             * la ""coller"" dans le champ "label" celle du label month_label**/
    	g_object_bind_property_full (adjustement_button_month, "value",
                                     month_label, "label",
                                     G_BINDING_SYNC_CREATE,
                                     value_to_label,
                                     NULL,
                                     NULL, NULL);
    	g_object_bind_property_full (adjustement_button_day, "value",
                                     day_label, "label",
                                     G_BINDING_SYNC_CREATE,
                                     value_to_label,
                                     NULL,
                                     NULL, NULL);
    	/* Affichage de la fenetre principale */
    	gtk_widget_show_all (window);
    }
     
    int main (int argc, char **argv)
    {
        GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), NULL);
        int status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);
    	return status;
    }
    je suis preneur de vos remarques car il est certain perfectible

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Bonjour @turboiii.

    Oui c'est encore moi .

    Tout d'abord bravo pour ce code. Propre, sans aucun warning de compilation et intéressant quant à la technique utilisée.

    Tu penses bien que si je me permets de te répondre c'est pour apporter quelques précisions et aussi quelques modifications qui peuvent rendre le code plus robuste. Alors allons y gaiement .

    1 - Tout d'abord, il est important de respecter les prototypes des callbacks utilisés. Le signal "activate" d'un GApplication est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void
    user_function (GApplication *application,
                   gpointer      user_data)
    Il manque à ta fonction le dernier paramètre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static void do_spinbutton (GtkApplication *app, gpointer data)
    Tu me diras qu'ici ce n'est pas bien grave, hormis le côté rigoriste, puisque tu ne l'utilises pas. Oui mais moi je vais te montrer une technique qui l'utilise .

    2 - Pour fermer une application on n'utilise pas le signal "delete-event" mias le signal "destroy".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_signal_connect (window, "destroy",G_CALLBACK (cb_quit), NULL);
    Si tu ne fais rien de spécial dans cb_quit (); tu peux directement appeler gtk_main_quit (); :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_signal_connect (window, "destroy",G_CALLBACK (gtk_main_quit), NULL);
    3 - Parlons maintenant du gros du sujet . Les allocations dynamiques.
    Tu alloues dans do_spinbutton (); deux tableaux pour les jours et les mois. Je peux comprendre l'idée et c'est tout à fait fonctionnel. Mais je ne vois nulle part dans ton code la libération de tout ce petit monde lorsque l'application s'arrête ! A ajouter donc. Pour ma part j'essaye dans la mesure du possible d'éviter les allocations dans le tas. Moins on en fait, moins il y a risque de fuite.

    En partant de ce principe j'ai tenté de modifier ton code. Tout d'abord, il faut être sûr que les tableaux vont exister tout le temps de vie de l'application. Donc ils doivent être déclarer dans le main ();. Ces tableaux doivent être propagés à tous les callbacks qui en ont besoin. Malheureusement nous n'avons qu'un pointeur pour faire ca. Donc, on utilisera une structure, comme tu l'as fait avec tab_t. Ceci donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct
    {
      gchar *month[13];
      gchar *day [8];
    } daymonth_t;
    Ces deux tableaux disposent chacun d'un élément de trop. Puisqu'ils sont définis et immuables, il suffit d'ajouter un élément à NULL pour pouvoir le parcourir. Ainsi je supprime ta variable len de l'équation.

    L'initialisation dans le main (); donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
      daymonth_t tab;
     
      tab.month[0] = "January";
      tab.month[1] = "February";
      tab.month[2] = "March";
      tab.month[3] = "April";
      tab.month[4] = "May";
      tab.month[5] = "June";
      tab.month[6] = "July";
      tab.month[7] = "August";
      tab.month[8] = "September";
      tab.month[9] = "October";
      tab.month[10] = "November";
      tab.month[11] = "December";
      tab.month[12] = NULL;
     
      tab.day[0] = "lundi";
      tab.day[1] = "mardi";
      tab.day[2] = "mercredi";
      tab.day[3] = "jeudi";
      tab.day[4] = "vendredi";
      tab.day[5] = "samedi";
      tab.day[6] = "dimanche";
      tab.day[7] = NULL;
    Maintenant tab est alloué dans la pile. A la fin de l'application, la mémoire allouée sera naturellement libérée en sortant de la fonction. Il me suffit maintenant de transmettre cette variable à la fonction do_spinbutton (); :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), &tab);
    A présent tu comprends ma remarque sur le prototype du callback .

    4 - Gestion du tableau tab dans les différents callbacks.
    C'est ici que ca se corse. Dans do_spinbutton (); il faut supprimer les anciennes allocations et récupérer le pointeur de tab :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    static void do_spinbutton (GtkApplication *app, gpointer data)
    {
      daymonth_t *tab = (daymonth_t*)data;
    Et on transmet les tableaux correspondants aux callbacks des GtkSpinButton :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      /** The output signal can be used to change to formatting of the value that 
       * is displayed in the spin buttons entry. **/
      g_signal_connect (spinbutton_month, "output", G_CALLBACK (spin_button_output), tab->month);
      g_signal_connect (spinbutton_day, "output", G_CALLBACK (spin_button_output), tab->day);
     
      /** par rapport à la demo gtk3-demo module spinbutton j'ai rajouté un paramètre pour le callback
       * g_signal_connect (spinbutton, "input", G_CALLBACK (month_spin_input));
       **/
      g_signal_connect (spinbutton_month, "input", G_CALLBACK (spin_button_input), tab->month);
      g_signal_connect (spinbutton_day, "input", G_CALLBACK (spin_button_input), tab->day);
    5 - Les callbacks des GtkSpinButton :
    Pour parcourir les tableaux il suffit de vérifier que l'élément pointé n'est pas égale à NULL.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (i=0; array[i]; i++)
    Ici tant que array[i]!=NULL la boucle continue. Plus besoin de connaître sa taille .

    La technique de lecture étant expliquée passons à la modification du callback attaché au signal "output". Maintenant que je dispose d'un tableau dont le premier élément pointe sur la case [0], il est très simple d'afficher le bon mois. Plus besoin de conditions (dont je n'ai pas bien compris le principe if (fabs (value - (double)i) < 1e-5) ). value correspond à l'indice du tableau à afficher.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    static gint spin_button_output (GtkSpinButton *spin_button, gpointer * data)
    {
      /** ce callback actualise une valeur de texte du gtkentry
       * d'un spinbutton 
       * 
       * la donnée d'entrée numérique est celle de l' adjustement du spinbutton 
       * la sortie est l'actualisation du Gtkentry avec une valeur du tableau
       * **/
      GtkAdjustment *adjustment;
      gdouble value;
      gchar **array = (gchar**)data;
     
      adjustment = gtk_spin_button_get_adjustment (spin_button);
      value = gtk_adjustment_get_value (adjustment);
      gtk_entry_set_text (GTK_ENTRY (spin_button), array[(gint)value]);
     
      return TRUE;
    }
    Pour arriver à ce résultat, il faut bien entendu modifier aussi le callback attaché au signal "input". Ici, j'ai simplement modifié le code pour tenir compte que le tableau transmis commence en 0.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    static gint spin_button_input (GtkSpinButton *spinbutton, gdouble *new_val, gpointer data)
    {
      /** peu documenté un tel callback permet par exemple d'actualiser 
       * la valeur numérique interne du SpinButton (pointé avec new_val) à partir de l'entry interne du spinbutton
       * 
       * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
       * la sortie est new_val
       * 
       * en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR 
       **/
      gint index;
      gchar *candidate_char, *wanted_char;
      gboolean found = FALSE;
     
      /* tab_t * array = (tab_t *) data; */
      gchar **array = (gchar**)data;
     
      for (index=0; array[index]; index++) {
        candidate_char = g_ascii_strup (array[index], -1);
     
        /** comme le spinbutton a un gtk_entry qui a été chargé avec une valeur de texte
         * on peut le comparer a une valeur dans un tableau. A partir du rang trouvé **/
        wanted_char = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (spinbutton)), -1);
     
        if (strstr (candidate_char, wanted_char) == candidate_char)
    	found = TRUE;
         g_free (wanted_char);
        g_free (candidate_char);
        if (found)
          break;
      }
     
      if (!found)
        {
          *new_val = 0.0;
          return GTK_INPUT_ERROR;
        }
      // actualisation ici
      *new_val = (gdouble) index;
     
      return TRUE;
    }
    En l'état le code est fonctionnel. Cependant un artefact apparaît à l'affichage. Puisque l'indice des tableaux commence en 0 le chiffre en regard des mois et des jours est décalé de -1. Il suffit pour corriger le tir de modifier le callback value_to_label (); en ajoutant +1 à value.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static gboolean value_to_label (GBinding     *binding,
    				const GValue *from,
    				GValue       *to,
    				gpointer      user_data)
    {
      /** synchronise le label à partir de l'adjustement **/
      g_value_take_string (to, g_strdup_printf ("%g", g_value_get_double (from)+1.));
      return TRUE;
      /* Parametre inutilise */
      (void)binding;	
      (void)user_data;	
    }
    6 - Histoire d'éclaircir tout ce bricolage, voila ton code complet avec toutes les modifications.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    #include <gtk/gtk.h>
    #include <glib/gi18n.h>
    #include <math.h>
    #include <stdlib.h>
     
    //test_spine_discret_test.c
    /*  Compile with:
     * 
     *  gcc -std=c11 -Wall -fmax-errors=10 -Wextra test_spine_discret_test.c -o test_spine_discret_test `pkg-config --cflags --libs gtk+-3.0`
     */
     
    typedef struct
    {
      gchar *month[13];
      gchar *day [8];
    } daymonth_t;
     
    void cb_quit (GtkWidget *widget, gpointer user_data)
    {
      gtk_main_quit();
      /* parametres inutilises */
      (void)widget;
      (void)user_data;
    }
     
    static gint spin_button_input (GtkSpinButton *spinbutton, gdouble *new_val, gpointer data)
    {
      /** peu documenté un tel callback permet par exemple d'actualiser 
       * la valeur numérique interne du SpinButton (pointé avec new_val) à partir de l'entry interne du spinbutton
       * 
       * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
       * la sortie est new_val
       * 
       * en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR 
       **/
      gint index;
      gchar *candidate_char, *wanted_char;
      gboolean found = FALSE;
     
      /* tab_t * array = (tab_t *) data; */
      gchar **array = (gchar**)data;
     
      for (index=0; array[index]; index++) {
        candidate_char = g_ascii_strup (array[index], -1);
     
        /** comme le spinbutton a un gtk_entry qui a été chargé avec une valeur de texte
         * on peut le comparer a une valeur dans un tableau. A partir du rang trouvé **/
        wanted_char = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (spinbutton)), -1);
     
        if (strstr (candidate_char, wanted_char) == candidate_char)
    	found = TRUE;
         g_free (wanted_char);
        g_free (candidate_char);
        if (found)
          break;
      }
     
      if (!found)
        {
          *new_val = 0.0;
          return GTK_INPUT_ERROR;
        }
      // actualisation ici
      *new_val = (gdouble) index;
     
      return TRUE;
    }
     
    static gint spin_button_output (GtkSpinButton *spin_button, gpointer * data)
    {
      /** ce callback actualise une valeur de texte du gtkentry
       * d'un spinbutton 
       * 
       * la donnée d'entrée numérique est celle de l' adjustement du spinbutton 
       * la sortie est l'actualisation du Gtkentry avec une valeur du tableau
       * **/
      GtkAdjustment *adjustment;
      gdouble value;
      gchar **array = (gchar**)data;
     
      adjustment = gtk_spin_button_get_adjustment (spin_button);
      value = gtk_adjustment_get_value (adjustment);
      gtk_entry_set_text (GTK_ENTRY (spin_button), array[(gint)value]);
     
      return TRUE;
    }
     
    static gboolean value_to_label (GBinding     *binding,
    				const GValue *from,
    				GValue       *to,
    				gpointer      user_data)
    {
      /** synchronise le label à partir de l'adjustement **/
      g_value_take_string (to, g_strdup_printf ("%g", g_value_get_double (from)+1.));
      return TRUE;
      /* Parametre inutilise */
      (void)binding;	
      (void)user_data;	
    }
     
    static void do_spinbutton (GtkApplication *app, gpointer data)
    {
      daymonth_t *tab = (daymonth_t*)data;
     
      /* Create a window with a title, and a default size */
      GtkWidget *window = gtk_application_window_new (app);
     
      /* Creation du conteneur principal */
      GtkWidget *main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
      GtkWidget *vertical_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
      gtk_container_add (GTK_CONTAINER (window), vertical_box);
     
      /* taille minimum */
      gtk_window_set_default_size  (GTK_WINDOW (window), 500, -1);
     
      /*création d'une bordure interne à la fenêtre window*/ 
      gtk_container_set_border_width (GTK_CONTAINER (window), 10);
      gtk_window_set_title (GTK_WINDOW (window),"test de spin button discret avec adjustement ");
     
      g_signal_connect (window, "destroy",G_CALLBACK (gtk_main_quit), NULL);
     
      double value_month = 6;
      GtkAdjustment * adjustement_button_month = gtk_adjustment_new (value_month, 0, 12, 1, 1, 1);
      double value_day = 2;
      GtkAdjustment * adjustement_button_day = gtk_adjustment_new (value_day, 0, 7, 1, 1, 1);
     
      GtkWidget * spinbutton_month = gtk_spin_button_new(adjustement_button_month, 1, 1);
      gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_month), 20);
      gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_month),"Utilisez le + ou le - pour faire défiler les mois ou les flèches clavier V /\\");
      /** Définit l'indicateur qui détermine si la valeur d'un bouton de rotation revient
       * à la limite opposée lorsque la limite supérieure ou inférieure de la plage est dépassée. **/
      gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_month), TRUE);
     
      GtkWidget * spinbutton_day = gtk_spin_button_new(adjustement_button_day, 1, 1);
      gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_day), 20);
      gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_day),"Utilisez le + ou le - pour faire défiler les jours ou les flèches clavier V /\\");
     
      gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_day), TRUE);
     
      GtkWidget * month_label = gtk_label_new(NULL);
      GtkWidget * legende_month_label = gtk_label_new("Numéro du mois ");
      GtkWidget * day_label = gtk_label_new(NULL);
      GtkWidget * legende_day_label = gtk_label_new("Numéro du jour de la semaine ");
     
      int expand = TRUE ;
      int fill = TRUE;
      int padding =1;
     
      // pour le premier spin month
      gtk_box_pack_start (GTK_BOX (main_box), spinbutton_month, !expand, fill, padding);
      GtkWidget * Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
      gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
      Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
      gtk_box_pack_start (GTK_BOX (main_box), legende_month_label, !expand, fill, padding);
      gtk_box_pack_start (GTK_BOX (main_box), month_label, !expand, fill, padding);
     
      gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
      /* // pour le spin day */
      main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     
      gtk_box_pack_start (GTK_BOX (main_box), spinbutton_day, !expand, fill, padding);
      Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
      gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
      Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
      gtk_box_pack_start (GTK_BOX (main_box), legende_day_label, !expand, fill, padding);
      gtk_box_pack_start (GTK_BOX (main_box), day_label, !expand, fill, padding);
     
      gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
      /** The output signal can be used to change to formatting of the value that 
       * is displayed in the spin buttons entry. **/
      g_signal_connect (spinbutton_month, "output", G_CALLBACK (spin_button_output), tab->month);
      g_signal_connect (spinbutton_day, "output", G_CALLBACK (spin_button_output), tab->day);
     
      /* The input signal can be used to influence the conversion of the users input into a double value. */
      g_signal_connect (spinbutton_month, "input", G_CALLBACK (spin_button_input), tab->month);
      g_signal_connect (spinbutton_day, "input", G_CALLBACK (spin_button_input), tab->day);
     
      /**  la méthode suivante vue dans gtk3-demo module spinbutton 
       * la synchro est automatique du spinbutton vers le label et c'est 
       * la fonction value_to_label qui réalise l'action à faire 
       * Gobject va collecter la valeur du champ value du adjustement_button_month pour 
       * la ""coller"" dans le champ "label" celle du label month_label**/
      g_object_bind_property_full (adjustement_button_month, "value",
                               month_label, "label",
                               G_BINDING_SYNC_CREATE,
                               value_to_label,
                               NULL,
                               NULL, NULL);
      g_object_bind_property_full (adjustement_button_day, "value",
                               day_label, "label",
                               G_BINDING_SYNC_CREATE,
                               value_to_label,
                               NULL,
                               NULL, NULL);
      /* Affichage de la fenetre principale */
      gtk_widget_show_all (window);
    }
     
    int main (int argc, char **argv)
    {
      daymonth_t tab;
     
      tab.month[0] = "January";
      tab.month[1] = "February";
      tab.month[2] = "March";
      tab.month[3] = "April";
      tab.month[4] = "May";
      tab.month[5] = "June";
      tab.month[6] = "July";
      tab.month[7] = "August";
      tab.month[8] = "September";
      tab.month[9] = "October";
      tab.month[10] = "November";
      tab.month[11] = "December";
      tab.month[12] = NULL;
     
      tab.day[0] = "lundi";
      tab.day[1] = "mardi";
      tab.day[2] = "mercredi";
      tab.day[3] = "jeudi";
      tab.day[4] = "vendredi";
      tab.day[5] = "samedi";
      tab.day[6] = "dimanche";
      tab.day[7] = NULL;
     
      GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
      g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), &tab);
      int status = g_application_run (G_APPLICATION (app), argc, argv);
      g_object_unref (app);
      return status;
    }
    En espérant apporter une pierre à l'édifice...

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Par défaut
    Hello gerald3d

    D’abord merci d’avoir regardé mon code et pris la peine de me faire une réponse très détaillée.

    Je suis globalement d’accord sur toute tes remarques. Mais mon code était quelque peu incomplet.

    Néanmoins à l’occasion de cet exercice j’ai appris quelques éléments intéressants.

    -1 on est pas obligé de fournir un callback complet par exemple si on ne se sert pas de tout

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void
    user_function (GApplication *application,
                   gpointer      user_data)
    si user_data n’est pas utilisé l’entête du callback fonctionne sans c’est donc très souple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void
    user_function (GApplication *application)
    avec toujours un appel du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), NULL);
    néanmoins on utilise en général pas mal ce paramètre user_data je suis d’accord.

    -2 je connais bien l’astuce de passer un pointeur d’une variable structure pour transmettre plus d’un paramètre dans un callback de Gtk. C’est plus une pratique du langage C que purement Gtk.
    La première fois que j’ai rencontré ce besoin j’ai un peu galéré…...

    3- Pour fermer une application on n'utilise pas le signal "delete-event" mais le signal "destroy".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_signal_connect (window, "destroy",G_CALLBACK (cb_quit), NULL);
    avec cb_quit un callback qui fait des actions pour fermer des fichiers nettoie et range avant de fermer la porte

    ou directement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_signal_connect (window, "destroy",G_CALLBACK (gtk_main_quit), NULL);
    Mais que fait la police je traîne cette mauvaise pratique un peu partout. Merci de ce rappel je vais me corriger.

    4- il faut libérer le tas et l’autre partie de la mémoire
    pour le tas c’est à coup de g_slice_free si on a fait la resa mémoire avec g_slice_new. Ces fonctions de la Glib seraient plus robustes et portables sur tous les OS que les fonctions C pures.
    Pour la mémoire classique on libère à coup de g_free(pointeur);
    Entièrement raison.

    Je suis en train de travailler à faire la même fonction mais avec des Glist, c’est encore plus souple et plus standard que travailler avec des tableaux dont on est obligé de déclarer une taille fixe. Dès que j’ai finis je posterai mon code.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Par défaut avec une fonction list
    hello la team GTK,

    je vous avais promis une version de spinbutton à valeur discrète dont les éléments sont gérés par une GList la voici . Si cela peut aider.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    #include <gtk/gtk.h>
    #include <glib/gi18n.h>
    #include <stdlib.h>
     
    //test_spine_discret_list.c
    /*  Compile with:
     * 
     *  gcc -std=c11 -Wall -fmax-errors=10 -Wextra test_spine_discret_list.c -o test_spine_discret_list `pkg-config --cflags --libs gtk+-3.0`
     */
     
    typedef struct
    {
      GList * list_day;
      GList * list_month;
    } listdaymonth_t;
     
    void cb_quit (GtkWidget *widget, gpointer user_data)
    {
    	gtk_main_quit();
    	/* parametres inutilises */
    	(void)widget;
    	(void)user_data;
    }
     
    static gint spin_button_input (GtkSpinButton *spinbutton, gdouble * new_val, gpointer data)
    {
    	/** peu documenté un tel callback permet par exemple d'actualiser 
             * la valeur numérique interne du SpinButton (pointé avec new_val) à partir de l'entry interne du spinbutton
             * 
             * l'entrée est gtk_entry_get_text (GTK_ENTRY (spinbutton)
             * la sortie est new_val
             * 
             * en l'état je ne sais pas traiter l'erreur en return GTK_INPUT_ERROR 
             **/
    	gint index = 0;
    	gchar *candidate_char, *wanted_char;
    	gboolean found = FALSE;
     
        GList * list = (GList*) data;
        index = g_list_length(list);
     
        while (list)
        {
    		candidate_char = g_ascii_strup (list->data,-1);
    		/** comme le spinbutton a un gtk_entry qui a été chargé avec une valeur de texte
                    * on peut le comparer a une valeur dans un tableau. A partir du rang trouvé **/
    		wanted_char = g_ascii_strup (gtk_entry_get_text (GTK_ENTRY (spinbutton)), -1);
    		if (strstr (candidate_char, wanted_char) == candidate_char)
    		{
    			g_print(" on cherchait %s et on l'a trouvé au rang %d\n",wanted_char,index);
    			found = TRUE;
    		}
    		g_free (wanted_char);
    		g_free (candidate_char);
    		if (found)
    			break;
    		index--;
    		list=g_list_next(list);
    	}
    	if (!found)
        {
    		*new_val = 0.0;
    		return GTK_INPUT_ERROR;
        }
        // actualisation ici
    	*new_val = (gdouble) index;
    	g_print( " la valeur de new_val est %d\n",index);
    	return TRUE;
    }
     
    static gint spin_button_output (GtkSpinButton *spin_button, gpointer * data)
    {
    	/** ce callback actualise une valeur de texte du gtkentry
             * d'un spinbutton 
             * 
             * la donnée d'entrée numérique est celle de l' adjustement du spinbutton 
             * la sortie est l'actualisation du Gtkentry avec une valeur du tableau
             * **/
    	GtkAdjustment *adjustment;
    	gdouble value;
    	GList * list = (GList*) data;
    	gint index = g_list_length(list);
     
    	adjustment = gtk_spin_button_get_adjustment (spin_button);
    	value = gtk_adjustment_get_value (adjustment);
    	g_print( " la valeur de value du spinbutton  est %d\n", (gint) value);	
        while (list)
        {
    		if (index == (gint )value)
    			if (strcmp (list->data, gtk_entry_get_text (GTK_ENTRY (spin_button))))
    				gtk_entry_set_text (GTK_ENTRY (spin_button), list->data);
    		list=g_list_next(list);
    		index--;
    	}
    	return TRUE;
    }
     
    static gboolean value_to_label (GBinding     *binding,
                    const GValue *from,
                    GValue       *to,
                    gpointer      user_data)
    {
    	/** synchronise le label à partir de l'adjustement **/
    	g_value_take_string (to, g_strdup_printf ("%g", g_value_get_double (from)));
    	return TRUE;
    	/* Parametre inutilise */
    	(void)binding;	
    	(void)user_data;	
    }
     
    static void do_spinbutton (GtkApplication *app, gpointer data)
    {
    	listdaymonth_t *list = (listdaymonth_t*)data;
     
      	/* Create a window with a title, and a default size */
    	GtkWidget *window = gtk_application_window_new (app);
     
    	/* Creation du conteneur principal */
    	GtkWidget *main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    	GtkWidget *vertical_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    	gtk_container_add (GTK_CONTAINER (window), vertical_box);
     
    	/* taille minimum */
    	gtk_window_set_default_size  (GTK_WINDOW (window), 500, -1);
     
    	/*création d'une bordure interne à la fenêtre window*/ 
    	gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    	gtk_window_set_title (GTK_WINDOW (window),"test de spin button discret avec adjustement ");
     
    	g_signal_connect (window, "delete_event",G_CALLBACK (cb_quit), NULL);
     
    	double value_month = 6;
    	GtkAdjustment * adjustement_button_month = gtk_adjustment_new (value_month,1, 13,1,1,1); 
    	double value_day = 2;
    	GtkAdjustment * adjustement_button_day = gtk_adjustment_new (value_day,1, 8,1,1,1); 
     
    	GtkWidget * spinbutton_month = gtk_spin_button_new(adjustement_button_month,1,1);
    	gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_month),20);
    	gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_month),"Utilisez le + ou le - pour faire défiler les mois ou les flèches clavier V /\\");
    	/** Définit l'indicateur qui détermine si la valeur d'un bouton de spin revient 
             * à la limite opposée lorsque la limite supérieure ou inférieure de la plage est dépassée. **/
    	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_month), TRUE);
     
    	GtkWidget * spinbutton_day = gtk_spin_button_new(adjustement_button_day,1,1);
    	gtk_entry_set_width_chars(GTK_ENTRY(spinbutton_day),20);
    	gtk_widget_set_tooltip_markup(GTK_WIDGET(spinbutton_day),"Utilisez le + ou le - pour faire défiler les jours ou les flèches clavier V /\\");
     
    	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_day), TRUE);
     
    	GtkWidget * month_label = gtk_label_new(NULL);
    	GtkWidget * legende_month_label = gtk_label_new("Numéro du mois");
    	GtkWidget * day_label = gtk_label_new(NULL);
    	GtkWidget * legende_day_label = gtk_label_new("Numéro du jour de la semaine");
     
    	int expand = TRUE ;
    	int fill = TRUE;
    	int padding =1;
     
    	// pour le premier spin month
    	gtk_box_pack_start (GTK_BOX (main_box), spinbutton_month, !expand, fill, padding);
    	GtkWidget * Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), legende_month_label, !expand, fill, padding);
    	gtk_box_pack_start (GTK_BOX (main_box), month_label, !expand, fill, padding);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
    	// pour le spin day
    	main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     
    	gtk_box_pack_start (GTK_BOX (main_box), spinbutton_day, !expand, fill, padding);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), Separator, FALSE, FALSE, 0);
    	Separator = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
    	gtk_box_pack_start (GTK_BOX (main_box), legende_day_label, !expand, fill, padding);
    	gtk_box_pack_start (GTK_BOX (main_box), day_label, !expand, fill, padding);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), main_box, !expand, fill, padding);
     
    	/** The output signal can be used to change to formatting of the value that 
             * is displayed in the spin buttons entry. **/
    	g_signal_connect (spinbutton_month, "output", G_CALLBACK (spin_button_output), list->list_month);
    	g_signal_connect (spinbutton_day, "output", G_CALLBACK (spin_button_output), list->list_day);
     
    	/** par rapport à la demo gtk3-demo module spinbutton j'ai rajouté un paramètre pour le callback
             * g_signal_connect (spinbutton, "input", G_CALLBACK (month_spin_input));
             **/
    	g_signal_connect (spinbutton_month, "input", G_CALLBACK (spin_button_input), list->list_month); 
    	g_signal_connect (spinbutton_day, "input", G_CALLBACK (spin_button_input), list->list_day); 
     
    	/**  la méthode suivante vue dans gtk3-demo module spinbutton 
             * la synchro est automatique du spinbutton vers le label et c'est 
             * la fonction value_to_label qui réalise l'action à faire 
             * Gobject va collecter la valeur du champ value du adjustement_button_month pour 
             * la ""coller"" dans le champ "label" celle du label month_label**/
    	g_object_bind_property_full (adjustement_button_month, "value",
                                     month_label, "label",
                                     G_BINDING_SYNC_CREATE,
                                     value_to_label,
                                     NULL,
                                     NULL, NULL);
    	g_object_bind_property_full (adjustement_button_day, "value",
                                     day_label, "label",
                                     G_BINDING_SYNC_CREATE,
                                     value_to_label,
                                     NULL,
                                     NULL, NULL);
    	/* Affichage de la fenetre principale */
    	gtk_widget_show_all (window);
    	//non utilisé
    	(void)data;
    }
     
    int main (int argc, char **argv)
    {
    	listdaymonth_t * list = g_slice_new (listdaymonth_t);
    	GList * value_list_day = NULL;
    	GList * value_list_month = NULL;
     
    	value_list_day = g_list_append(value_list_day,"lundi");
    	value_list_day = g_list_append(value_list_day,"mardi");
    	value_list_day = g_list_append(value_list_day,"mercredi");
    	value_list_day = g_list_append(value_list_day,"jeudi");
    	value_list_day = g_list_append(value_list_day,"vendredi");
    	value_list_day = g_list_append(value_list_day,"samedi");
    	value_list_day = g_list_append(value_list_day,"dimanche");
     
    	value_list_day = g_list_reverse(value_list_day);
     
    	list->list_day =value_list_day;
     
    	value_list_month = g_list_append(value_list_month,"January");
    	value_list_month = g_list_append(value_list_month,"February");
    	value_list_month = g_list_append(value_list_month,"March");
    	value_list_month = g_list_append(value_list_month,"April");
    	value_list_month = g_list_append(value_list_month,"May");
    	value_list_month = g_list_append(value_list_month,"June");
    	value_list_month = g_list_append(value_list_month,"July");
    	value_list_month = g_list_append(value_list_month,"August");
    	value_list_month = g_list_append(value_list_month,"September");
    	value_list_month = g_list_append(value_list_month,"October");
    	value_list_month = g_list_append(value_list_month,"November");
    	value_list_month = g_list_append(value_list_month,"December");
     
    	value_list_month = g_list_reverse(value_list_month);
    	list->list_month =value_list_month;
     
        GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), list);
        int status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);
        // libération du tas
        g_slice_free(listdaymonth_t, list);
        g_free(value_list_day);
        // libération mémoire
        g_free(value_list_month);
    	return status;
    }
    je tiens quand même à souligner qu'il reste un détail à régler. La fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void
    gtk_spin_button_set_wrap (GtkSpinButton *spin_button,
                              gboolean wrap);
    permet normalement, si le drapeau wrap est TRUE de faire défiler les valeurs en boucle. Si on arrive à une limite on recommence à l'autre bout. Eh bien mon code ne le fait pas à l'extrémité supérieure

  5. #5
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Hormis quelques warnings en console que tu pourras régler sans problème, très belle réalisation.

    Il ne te reste plus qu'à transformer tout ce petit monde en GtkWiget.

    Sortie console :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Gtk-CRITICAL **: 14:56:04.042: gtk_main_quit: assertion 'main_loops != NULL' failed
    free(): invalid pointer

  6. #6
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    Bonjour,

    j'ai lu ça en diagonale, mais rapidement j'ai vu:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	value_list_month = g_list_append(value_list_month,"January");
            ...
    	value_list_month = g_list_append(value_list_month,"December");
     
    	value_list_month = g_list_reverse(value_list_month);
    En général on utilise g_list_reverse, mais quand on a ajouté les éléments avec g_list_prepend et non g_list_append. L'explication est simple: la complexité algorithmique. Si tu ajoutes un élément à la find de la liste avec append, tu dois parcourir toute la liste, ce qui prend du temps inutilement. Sur une liste de 12 éléments ça va, mais sur un million... Pour ajouter le millionnième élément tu auras parcouru 999 999 éléments inutilement. Pour éviter cela, on ajoute en début de liste les éléments, ce qui permet de n'avoir qu'un seul élement à mettre jour, même quand on ajoute le milliionnième. Mais dans ce cas la liste finale est à l'envers: Décembre, novembre, etc. Donc on la retourne avec le reverse pour remettre les éléments dans le bon ordre.

    Ensuite, plutôt que d'ajouter 12 lignes pour ajouter chaque mois dans ta liste, fais une boucle:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	const char * months[] = {"January", "February", "March", ..., "December"};
    	for (int i=0; i < G_N_ELEMENTS(months); i++)
    		value_list_month = g_list_prepend(value_list_month, months[i]);
    C'est important de séparer sa logique de ses données. En effet, il est en général plus facile d'ajouter ou supprimer des données que de modifier du code.

    Une autre chose que j'ai vue:
    J'imagine que c'est parce que le compilateur râle car un argument de la fonction n'es pas utilisé. Dans ce cas il suffit d'ajouter G_GNUC_UNUSED devant la définition de variable.

Discussions similaires

  1. spin bouton et macro import
    Par cbredeche dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 21/11/2016, 14h28
  2. [GTK3][C] Dimensions des boutons dans le GtkSpinButton
    Par blumax dans le forum GTK+ avec C & C++
    Réponses: 2
    Dernier message: 01/11/2016, 20h30
  3. [vba-excell] Compteur Spin-bouton
    Par CIBOOX dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 08/02/2007, 14h20
  4. Pop-up d'une dialog box a partir d'un bouton
    Par bobbyjack dans le forum MFC
    Réponses: 21
    Dernier message: 13/09/2005, 15h32
  5. Afficher/Masquer un bouton comme IE 6
    Par benj63 dans le forum C++Builder
    Réponses: 3
    Dernier message: 29/07/2002, 13h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo