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++

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

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    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 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    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 régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    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 régulier
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    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 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    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
    Points : 2 002
    Points
    2 002
    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.
    Documentation officielle GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels GTK+ 3:
    GTK en C, GTK en Python

    Tutoriels par l'exemple (platform-demos):
    GTK (tous langages)

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

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    Par défaut
    Hello la Team Gtk,

    Un ENORME Merci pour vos commentaires précieux. Comme c'est un code que j'ai fait pour le forum pour isoler la problématique fatalement j'ai laissé quelques erreurs, les voici corrigées. J'ai appliqué religieusement les recommandations. Mais mon compilateur n'a pas aimé les huitres de noel, il était de mauvaise humeur aujourd'hui

    du coup
    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]);
    a été remplacé par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char * months[] = {"January", "February", "March", "April","May","June",
    							"July","August","September","October","November", "December"};
    	for (guint i=0; i < G_N_ELEMENTS(months); i++)
    		value_list_month = g_list_prepend(value_list_month, months[i]);
    J'ai utilisé un entier non signé guint et supprimé le const pour calmer monsieur gcc

    et puis pour résoudre la libération du tas j'ai utilisé le signal shutdown pour l'action à réaliser en fin de programme

    voici le nouveau code

    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
    #include <gtk/gtk.h>
    #include <glib/gi18n.h>
    #include <stdlib.h>
     
    //test_spine_discret_list_02.c
    /*  Compile with:
     * 
     *  gcc -std=c11 -Wall -fmax-errors=10 -Wextra test_spine_discret_list_02.c -o test_spine_discret_list_02 `pkg-config --cflags --libs gtk+-3.0`
     */
     
    typedef struct
    {
      GList * list_day;
      GList * list_month;
    } listdaymonth_t;
     
    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 (G_GNUC_UNUSED GBinding     *binding,
                    const GValue *from,
                    GValue       *to,
                    G_GNUC_UNUSED 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;
    }
     
    static void do_spinbutton (GtkApplication *app, G_GNUC_UNUSED 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 ");
     
    	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);
    }
     
    static void do_shutdown (G_GNUC_UNUSED GtkApplication *app, gpointer list)
    {
    	// libération du tas
        g_slice_free(listdaymonth_t, list);
    }
     
    int main (int argc, char **argv)
    {
    	listdaymonth_t * list = g_slice_new (listdaymonth_t);
    	GList * value_list_day = NULL;
    	GList * value_list_month = NULL;
     
    	char * days[] = {"lundi", "mardi", "mercredi", "jeudi","vendredi","samedi",
    							"dimanche"};
    	for (guint i=0; i < G_N_ELEMENTS(days); i++)
    		value_list_day = g_list_prepend(value_list_day, days[i]);
     
    	char * months[] = {"January", "February", "March", "April","May","June",
    							"July","August","September","October","November", "December"};
    	for (guint i=0; i < G_N_ELEMENTS(months); i++)
    		value_list_month = g_list_prepend(value_list_month, months[i]);
     
    	list->list_month =value_list_month;
    	list->list_day =value_list_day;
     
        GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), list);
        g_signal_connect (app, "shutdown", G_CALLBACK (do_shutdown), list);
        int status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);
    	return status;
    }
    nota il reste encore 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 toujours pas à l'extrémité supérieure

    sin quelqu'un avait une idée. La je sèche vraiment

    Ultime et dernier point : Il ne me reste plus qu'à transformer tout ce petit monde en GtkWidget. Certe pourquoi pas pour la beauté du geste. J'ai déjà regardé ce type d'opération en gtk2... Cela reste encore pour moi un peu indigeste. Un lien vers une réalisation récente pourrait m'intéresser pour étudier cette affaire.... peut être enfin l'occasion en Gtk3 de comprendre et d'aller jusqu'au bout je suis prêt à relever le défi

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

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    Par défaut
    Hello la team Gtk+3

    je reprends un dossier en suspens depuis un bout de temps

    j'en étais à la phase de customisation et je bute sur une question comment on dessine plusieurs widgets cette question me taraude depuis un certain temps mais je ne fais pas que cela pdt le confinement


    voici mon header

    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
    #ifndef __SPINBUTTON_DISCRET_H__
    #define __SPINBUTTON_DISCRET_H__
     
    #include <gtk/gtk.h>
    #include <cairo.h>
    //spinbuttondiscret.h
    G_BEGIN_DECLS
     
    #define CB_TEST
     
    /* define la variable SPINBUTTON_TYPE_DISCRET  contient la fonction  de type Gtype de la class */
    #define SPINBUTTON_TYPE_DISCRET gtk_spinbutton_discret_get_type()
     
    G_DECLARE_FINAL_TYPE(GtkSpinButtonDiscret, gtk_spinbutton_discret,GTK , SPINBUTTONDISCRET , GtkSpinButton)
    /** signification des paramètres
     * le préfixe GtkSpinButtonDiscret pour la classe GtkSpinButtonDiscretClass
     * gtk_spinbutton_discret pour définir le type gtk_spinbutton_discret_get_type()
     * le transtypage GTK_SPINBUTTONDISCRET
     * l'ancêtre GtkSpinButton
     **/
    /* Type definition */
    typedef struct _GtkSpinButtonDiscretPrivate GtkSpinButtonDiscretPrivate;
     
    struct _GtkSpinButtonDiscret 
    {
       GtkSpinButton parent;
     
       /*< Private >*/
       GtkSpinButtonDiscretPrivate *priv;
    };
     
    /* Private data structure */
    struct _GtkSpinButtonDiscretPrivate
    {    
       GList * 			discret_list; // la liste des élément discrets
       gboolean 		show_label;	//drapeau pour afficher ou pas le chiffre correspondant au rang affiché dans la liste
       GtkWidget * 		widget_label;  // le label qui affiche ce chiffre
       GdkWindow *		window;
       GtkAdjustment * 	adjustement;
       GtkWidget * 		box; //la boite qui contient tout
    };
    struct _GtkSpinButtonDiscretClass 
    {
       GtkSpinButtonClass parent_class;
    };
     
    /* Public API */
    GtkWidget *gtk_spinbutton_discret_new(GtkAdjustment *adjustment,
                         gdouble        climb_rate,
                         guint          digits,
                         GList * discret_list);
     
    void gtk_spinbutton_discret_show_label(GtkSpinButtonDiscret *spin, gboolean label_flag);
    gboolean gtk_spinbutton_discret_get_label(GtkSpinButtonDiscret *spin);
     
     
    G_END_DECLS
     
    #endif /*__SPINBUTTON_DISCRET_H__ */
    le code source en chantier évidemment

    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
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    #include "spinbuttondiscret.h"
    /* spinbuttondiscret.c */
     
    /* Properties enum */
    enum 
    {
       P_0, /* Padding */
       P_SHOW_LABEL,  //propriété pour afficher un label à côté du spin button
    };
     
    /* Internal API */
    void gtk_spinbutton_discret_load_discret_list (GtkSpinButtonDiscret *spin,GList *discret_list);
    void gtk_spinbutton_discret_show_label(GtkSpinButtonDiscret *spin, gboolean show_label);
    static void gtk_spinbutton_discret_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
    static void gtk_spinbutton_discret_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
    static void gtk_spinbutton_discret_size_request(GtkWidget *widget, GtkRequisition *requisition);
    static void gtk_spinbutton_discret_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height);
    static void gtk_spinbutton_discret_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width);
    static void gtk_spinbutton_discret_size_allocate(GtkWidget *widget,  GtkAllocation *allocation);
    static gboolean gtk_spinbutton_discret_draw (GtkWidget * widget, cairo_t *cr);
    static void gtk_spinbutton_discret_realize(GtkWidget *widget);
     
    /* Define type */
    G_DEFINE_TYPE_WITH_PRIVATE(GtkSpinButtonDiscret, gtk_spinbutton_discret, GTK_TYPE_SPIN_BUTTON)
    /** signification des paramètres pour G_DEFINE_TYPE(GtkSpinButtonDiscret, gtk_spinbutton_discret, GTK_TYPE_SPIN_BUTTON)
     * le même préfixe GtkSpinButtonDiscret que pour la classe GtkSpinButtonDiscretClass
     * implementation de la fonction (gtk_spinbutton_discret)_get_type avec un  protocole standard
     * define a parent class pointer accessible from the whole .c file
     * a noter que GTK_TYPE_SPIN_BUTTON a été trouvé dans le code source gtkspinbutton.c qui est consultable
     **/
     
     /* Public API */
    /**
     * gtk_spin_button_new:
     * @adjustment: (allow-none): the #GtkAdjustment object that this spin
     *     button should use, or %NULL
     * @climb_rate: specifies how much the spin button changes when an arrow
     *     is clicked on
     * @digits: the number of decimal places to display
     *
     * Creates a new #GtkSpinButton.
     *
     * Returns: The new spin button as a #GtkWidget
     * classic engine
    GtkWidget * gtk_spin_button_new (GtkAdjustment *adjustment,
                         gdouble        climb_rate,
                         guint          digits)
    {
      GtkSpinButton *spin;
      if (adjustment)
        g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
      spin = g_object_new (GTK_TYPE_SPIN_BUTTON, NULL);
      gtk_spin_button_configure (spin, adjustment, climb_rate, digits);
      return GTK_WIDGET (spin);
    } 
     
       * GtkSpinButton::input:
       * @spin_button: the object on which the signal was emitted
       * @new_value: (out) (type double): return location for the new value
       *
       * The ::input signal can be used to influence the conversion of
       * the users input into a double value. The signal handler is
       * expected to use gtk_entry_get_text() to retrieve the text of
       * the entry and set @new_value to the new value.
       *
       * The default conversion uses g_strtod().
       *
       * Returns: %TRUE for a successful conversion, %FALSE if the input
       *     was not handled, and %GTK_INPUT_ERROR if the conversion failed.
       * 
       *  spinbutton_signals[INPUT] =
        g_signal_new (I_("input"),
                      G_TYPE_FROM_CLASS (gobject_class),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (GtkSpinButtonClass, input),
                      NULL, NULL,
                      _gtk_marshal_INT__POINTER,
                      G_TYPE_INT, 1,
                      G_TYPE_POINTER);
                      * 
       * GtkSpinButton::output:
       * @spin_button: the object on which the signal was emitted
       *
       * The ::output signal can be used to change to formatting
       * of the value that is displayed in the spin buttons entry.
       * |[<!-- language="C" -->
       * // show leading zeros
       * static gboolean
       * on_output (GtkSpinButton *spin,
       *            gpointer       data)
       * {
       *    GtkAdjustment *adjustment;
       *    gchar *text;
       *    int value;
       *
       *    adjustment = gtk_spin_button_get_adjustment (spin);
       *    value = (int)gtk_adjustment_get_value (adjustment);
       *    text = g_strdup_printf ("%02d", value);
       *    gtk_entry_set_text (GTK_ENTRY (spin), text);
       *    g_free (text);
       *
       *    return TRUE;
       * }
       * ]|
       *
       * Returns: %TRUE if the value has been displayed
       */
    GtkWidget *gtk_spinbutton_discret_new(GtkAdjustment *adjustment,
                         gdouble        climb_rate,
                         guint          digits,
                         GList * discret_list) 
    {
    	/** retourne une instance Gobject de type gtk_spinbutton_discret_get_type() **/
        #ifdef CB_TEST
    		g_print ("création de gtk_spinbutton_discret_new\n");
    	#endif
    	GtkSpinButton *spin;
    	if (adjustment)
    		g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
     
    	spin = g_object_new (SPINBUTTON_TYPE_DISCRET, NULL);
    	//affectation de de la liste	
    	gtk_spinbutton_discret_load_discret_list (GTK_SPINBUTTONDISCRET(spin), discret_list);
    	gtk_spin_button_configure (spin, adjustment, climb_rate, digits);
    	GtkSpinButtonDiscretPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(spin, SPINBUTTON_TYPE_DISCRET, GtkSpinButtonDiscretPrivate);
     
    	g_print ("\n gtk_spinbutton_discret_new  SUCCESS ligne= %d\n", __LINE__);
    	gboolean test = TRUE;
    	if (test)
    		return GTK_WIDGET (spin);
    	else
    		return GTK_WIDGET (priv->box);
    } 
     
    /* Initialization */
    static void gtk_spinbutton_discret_class_init(GtkSpinButtonDiscretClass *klass) 
    {
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_class_init\n");
    	#endif
    	GObjectClass *g_class;
    	GtkWidgetClass *widget_class;
    	GParamSpec *pspec;
     
    	g_class = G_OBJECT_CLASS(klass);
    	widget_class = GTK_WIDGET_CLASS(klass);
     
    	/* Override widget class methods */
    	g_class->set_property = gtk_spinbutton_discret_set_property;
    	g_class->get_property = gtk_spinbutton_discret_get_property;
     
    	widget_class->realize = gtk_spinbutton_discret_realize;
    	widget_class->get_preferred_width = gtk_spinbutton_discret_get_preferred_width;
    	widget_class->get_preferred_height = gtk_spinbutton_discret_get_preferred_height;
    	widget_class->size_allocate = gtk_spinbutton_discret_size_allocate;
     
    	widget_class->draw = gtk_spinbutton_discret_draw;
     
    	/* Install property */
    	pspec = g_param_spec_boolean("label", "Label", 
    	   "display label at right spin", FALSE, 
    	   G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     
    	g_object_class_install_property(g_class, P_SHOW_LABEL, pspec);
    	g_print ("\n gtk_spinbutton_discret_class_init ligne SUCCESS %d\n", __LINE__);
    	/* Add private data */
    	g_type_class_add_private(g_class, sizeof(GtkSpinButtonDiscretPrivate));
    }
     
    static void gtk_spinbutton_discret_init(GtkSpinButtonDiscret *spin) 
    {
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_init\n");
    	#endif
    	GtkSpinButtonDiscretPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE(spin, SPINBUTTON_TYPE_DISCRET, GtkSpinButtonDiscretPrivate);
    	//GtkSpinButtonDiscretPrivate *priv = gtk_form_get_instance_private (spin);
     
    	gtk_widget_set_has_window(GTK_WIDGET(spin), TRUE);
     
    	/* Set default values */
    	priv->discret_list = NULL; // la liste des élément discrets
    	priv->show_label = TRUE;//drapeau pour afficher ou pas le chiffre correspondant au rang affiché dans la liste
    	priv->widget_label =  NULL;  // le label qui affiche ce chiffre
    	priv->window = NULL;
    	priv->adjustement =NULL;
     
    	/* Create cache for faster access */
    	spin->priv = priv;
    }
     
    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; // si je remplace gpointer data par ???? je simplifie le code
        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 (G_GNUC_UNUSED GBinding     *binding,
                    const GValue *from,
                    GValue       *to,
                    G_GNUC_UNUSED 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;
    }
     
    /* Overriden virtual methods */
    static void gtk_spinbutton_discret_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 
    {   
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_set_property\n");
    	#endif
    	GtkSpinButtonDiscret *spin = GTK_SPINBUTTONDISCRET(object);
    	switch(prop_id) 
    	{
    		case P_SHOW_LABEL:
    			gtk_spinbutton_discret_show_label(spin, g_value_get_boolean(value));
    			break;
    		default:
    			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    			break;
       }
    }
     
    static void gtk_spinbutton_discret_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 
    {
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_get_property\n");
    	#endif
    	GtkSpinButtonDiscret *spin = GTK_SPINBUTTONDISCRET(object);
    	switch(prop_id) 
    	{
    		case P_SHOW_LABEL:
    			g_value_set_boolean(value, spin->priv->show_label);
    			break;
    		default:
    			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
    			break;
    	}
    }
     
    static void gtk_spinbutton_discret_size_request(GtkWidget *widget, GtkRequisition *requisition) 
    {
    	/** nous stockons la taille préférée de notre widget, cette fonction ne sert qu'a cela
             * mais requisition sera par la suite consulté **/
    	g_return_if_fail (GTK_SPINBUTTONDISCRET (widget));
    	g_return_if_fail (requisition != NULL);
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_size_request\n");
    	#endif	
    	requisition->width  = 100; // provisoire WIDTH, );
    	requisition->height = 100; // provisoire , HEIGHT);
    }
     
    static void gtk_spinbutton_discret_size_allocate(GtkWidget *widget, GtkAllocation *allocation) 
    {
    	/** Cette fonction sera appelée par le conteneur dans lequel se trouvera notre widget+ le label,
             * une fois que les contraintes qui sont imposées au conteneur sont fixées, 
             * ça permet au conteneur de redimensionner au mieux notre widget GtkSpinButtonDiscret,
             * d'après le résultat obtenu dans le second argument de la fonction avec
             * gtk_widget_set_allocation(widget, allocation);
             * puis nous lançons la demande de déplacement, et re-dimensionnement, 
             * avec l'appel à gdk_window_move_resize.
             * C'est un protocole qu'on retrouve dans les divers exemples  **/ 
    	g_return_if_fail (GTK_SPINBUTTONDISCRET (widget));
    	g_return_if_fail (allocation != NULL);
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_size_allocate\n");
    	#endif
    	GtkSpinButtonDiscretPrivate *priv = GTK_SPINBUTTONDISCRET(widget)->priv;
     
    	gtk_widget_set_allocation(widget, allocation);
     
    	if (gtk_widget_get_realized(widget)) 
    	{   
    		//g_print ("dans gtk_spinbutton_discret_size_allocate les tailles private sont %d et %d \n",WIDTH,HEIGHT);
    		g_print ("dans gtk_spinbutton_discret_size_allocate les tailles allocation sont %d et %d \n",allocation->width,allocation->height);
    		gdk_window_move_resize(	priv->window, 
    								allocation->x, 
    								allocation->y,
    								100,100); // provisoire WIDTH, HEIGHT);
    	}
    }
     
    static void gtk_spinbutton_discret_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
    {
    	/** la fonction établit une largeur   compatible avec le spinbuuton plus le label image   **/
    	g_return_if_fail (GTK_SPINBUTTONDISCRET (widget));
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_get_preferred_width\n");
    	#endif
    	GtkRequisition requisition;
     
    	gtk_spinbutton_discret_size_request (widget, &requisition);
    	*minimal_width = *natural_width = requisition.width;
    }
     
    static void gtk_spinbutton_discret_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height)
    {
    	/** la fonction établit une hauteur   compatible avec le spinbuuton plus le label image   **/
    	g_return_if_fail (GTK_SPINBUTTONDISCRET (widget));
    	#ifdef CB_TEST
    		g_print ("gtk_spinbuttondiscret_get_preferred_height\n");
    	#endif
    	GtkRequisition requisition;
     
    	gtk_spinbutton_discret_size_request (widget, &requisition);
    	*minimal_height = *natural_height = requisition.height;
    }
     
    void gtk_spinbutton_discret_show_label(GtkSpinButtonDiscret *spin, gboolean show_label)
    {
    	g_return_if_fail (GTK_SPINBUTTONDISCRET(spin));
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_show_label\n");
    	#endif
    	spin->priv->show_label = show_label;
    	/** finalement la commande la plus simple est de jouer 
             * avec la visibilité du widget label **/
    	gtk_widget_set_visible(GTK_WIDGET(spin->priv->widget_label),show_label);
    }
     
    gboolean gtk_spinbutton_discret_get_label(GtkSpinButtonDiscret *spin)
    {
       g_return_val_if_fail(GTK_SPINBUTTONDISCRET(spin), 0);
       #ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_get_label\n");
       #endif
       return(spin->priv->show_label);
    }
     
    void gtk_spinbutton_discret_load_discret_list (GtkSpinButtonDiscret *spin,GList *discret_list)
    {
       g_return_if_fail (GTK_SPINBUTTONDISCRET(spin));
       #ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_load_discret_list\n");
       #endif
       spin->priv->discret_list = discret_list;
    }
     
    static void gtk_spinbutton_discret_realize(GtkWidget *widget) 
    {
    	/** cette fonction est au coeur du dispositif c'est ici que la fenêtre est créé
             * avec les bonnes dimensions
             * notamment  la couche de dessin est préparé avec le spinbutton plus son label
             * le widget label sera visible ou pas et créé dans tous les cas
             **/
    	g_return_if_fail (GTK_SPINBUTTONDISCRET (widget));
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_realize\n");
    	#endif
    	GtkSpinButtonDiscretPrivate *priv = GTK_SPINBUTTONDISCRET(widget)->priv;
     
    	GtkAllocation allocation;
    	GdkWindowAttr attributes;
    	guint attrs_mask;
    	gtk_widget_set_realized(widget, TRUE);
     
    	gtk_widget_get_allocation(widget, &allocation);
     
    	attributes.x           = allocation.x;
    	attributes.y           = allocation.y;
    	attributes.width       = allocation.width;
    	attributes.height      = allocation.height;
    	attributes.window_type = GDK_WINDOW_CHILD;
    	attributes.wclass      = GDK_INPUT_OUTPUT;
    	//attributes.event_mask  = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK;
    	attributes.event_mask = gtk_widget_get_events (widget);
    	attributes.event_mask |= GDK_BUTTON_PRESS_MASK
        | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
        | GDK_POINTER_MOTION_MASK;
    	attrs_mask = GDK_WA_X | GDK_WA_Y;
     
    	priv->window = gdk_window_new(gtk_widget_get_parent_window(widget),
    			   &attributes, attrs_mask);
    	gdk_window_set_user_data(priv->window, widget);
    	gtk_widget_set_window(widget, priv->window);
     
    	/**widget->style = gtk_style_attach(gtk_widget_get_style( widget ),
                                                             priv->window);
            //gtk_style_set_background(widget->style, priv->window, GTK_STATE_NORMAL);**/
     
     
    	/* Creation du conteneur principal */
    	GtkWidget *main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
     
    	priv->widget_label = gtk_label_new(NULL);
    	gtk_widget_set_no_show_all(priv->widget_label,TRUE);
     
    	GtkWidget * legende_label = gtk_label_new("Numéro du mois");
    	gtk_widget_set_no_show_all(legende_label,TRUE);
     
    	int expand = TRUE ;
    	int fill = TRUE;
    	int padding =1;
     
    	GtkWidget * spinbutton = gtk_spin_button_new(priv->adjustement,1,1);
     
     
    	 //pour le premier spin month
    	gtk_box_pack_start (GTK_BOX (main_box), spinbutton, !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_label, !expand, fill, padding);
    	gtk_box_pack_start (GTK_BOX (main_box), priv->widget_label, !expand, fill, padding);
     
     
    	priv->box = main_box;
     
    	/** 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, "output", G_CALLBACK (spin_button_output), priv->discret_list);
    	/** 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, "input", G_CALLBACK (spin_button_input), priv->discret_list); 
     
    	/**  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 (priv->adjustement, "value",
                                     priv->widget_label, "label",
                                     G_BINDING_SYNC_CREATE,
                                     value_to_label,
                                     NULL,
                                     NULL, NULL);
    	g_print ("\n gtk_spinbutton_discret_realize ligne SUCCESS %d\n", __LINE__);
    }
    static gboolean gtk_spinbutton_discret_draw (GtkWidget * widget, cairo_t *cairo)
    {
     
    	g_return_val_if_fail (GTK_SPINBUTTONDISCRET (widget),FALSE);
    	#ifdef CB_TEST
    		g_print ("gtk_spinbutton_discret_draw\n");
    	#endif
    	GtkAllocation allocation;
    	gtk_widget_get_allocation(widget, &allocation);
    	//GtkSpinButtonDiscretPrivate *priv = GTK_SPINBUTTONDISCRET(widget)->priv;
    	gint center_x = (allocation.width / 2) ;
    	gint center_y = (allocation.height / 2);
     
    	/** comment on s'y prend pour dessiner les différents widgets **/
    	cairo_arc(cairo, center_x, center_y, 50, 0, 2 * 3.14);
    	cairo_stroke(cairo);
    	return TRUE;
    }
    le code de test

    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
    #include <gtk/gtk.h>
    #include <glib/gi18n.h>
    #include <stdlib.h>
    #include "spinbuttondiscret.h"
     
    //test_spinbuttondiscret.c
     
    typedef struct
    {
      GList * list_day;
      GList * list_month;
    } listdaymonth_t;
     
    static void do_spinbutton (GtkApplication *app, G_GNUC_UNUSED 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 ");
     
    	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_spinbutton_discret_new(adjustement_button_month,1,1,list->list_month);
    	/**********************************************/
    	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 /\\");
     
    	/**********************************************/
    	GtkWidget * spinbutton_day = gtk_spinbutton_discret_new(adjustement_button_day,1,1,list->list_day);
    	/**********************************************/
    	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 /\\");
     
    	/** 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);
    	gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinbutton_day), TRUE);
     
    	int expand = TRUE ;
    	int fill = TRUE;
    	int padding =1;
     
    	GtkWidget * Separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), spinbutton_month, !expand, fill, padding);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), Separator, FALSE, FALSE, 0);
     
    	gtk_box_pack_start (GTK_BOX (vertical_box), spinbutton_day, !expand, fill, padding);	
     
    	/* Affichage de la fenetre principale */
    	gtk_widget_show_all (window);
    }
     
    static void do_shutdown (G_GNUC_UNUSED GtkApplication *app, gpointer list)
    {
    	// libération du tas
        g_slice_free(listdaymonth_t, list);
    }
     
    int main (int argc, char **argv)
    {
    	listdaymonth_t * list = g_slice_new (listdaymonth_t);
    	GList * value_list_day = NULL;
    	GList * value_list_month = NULL;
     
    	char * days[] = {"lundi", "mardi", "mercredi", "jeudi","vendredi","samedi",
    							"dimanche"};
    	for (guint i=0; i < G_N_ELEMENTS(days); i++)
    		value_list_day = g_list_prepend(value_list_day, days[i]);
     
    	char * months[] = {"January", "February", "March", "April","May","June",
    							"July","August","September","October","November", "December"};
    	for (guint i=0; i < G_N_ELEMENTS(months); i++)
    		value_list_month = g_list_prepend(value_list_month, months[i]);
     
    	list->list_month =value_list_month;
    	list->list_day =value_list_day;
     
        GtkApplication *app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
        g_signal_connect (app, "activate", G_CALLBACK (do_spinbutton), list);
        g_signal_connect (app, "shutdown", G_CALLBACK (do_shutdown), list);
        int status = g_application_run (G_APPLICATION (app), argc, argv);
        g_object_unref (app);
    	return status;
    }
    et pour finir meson build

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Tu cherches à faire quoi exactement ici ?

    J'obtiens deux cercles avec tout un tas de warnings en console. Si j'ai le malheur d'appuyer sur + ou - gtk_spinbutton_discret_draw(); est appelé sans cesse.

    T'as démonté le moteur puis remonté et il te reste un carton de pièces dont tu ne sais que faire ?

    Pardon, je te taquine . Plus sérieusement, quel est le but précis de cet exercice ?

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

    Informations forums :
    Inscription : Mars 2008
    Messages : 147
    Points : 88
    Points
    88
    Par défaut
    ben initialement j'ai produit un widget en forme classique voir plus haut la chaîne de post. tu avais même trouvé l'exercice intéressant. C'est toi qui m' a suggéré de faire un exercice de customisation. C'est ce que j'ai commencé à faire. Par contre arrivé à l'action gtk_spinbutton_discret_draw je ne sais pas trop comment m'y prendre pour afficher toute cette quincaillerie. Quelle piste est la meilleure ?

    dessiner "à la main" chaque widget ne me semble pas du tout optimal.

    Histoire de vérifier que le reste du code commence à fonctionner j'ai mis un truc bidon. Désolé si cela t'a fortement perturbé..

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

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

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Comme tu l'as compris le dessin d'un widget se fait via le signal "draw". Comme tu récupères le cairo context à l'intérieur du callback associé tu peux dessiner dessus.

    Il y a deux manières de voir les choses :

    1. soit tu dessines directement dans le callback. En général on fait comme ca si le dessin est relativement simple,
    2. soit tu disposes d'un cairo_surface* dans ton widget. Les fonctions internes construisent le dessin dessus et le callback associé au signal "draw" ne fait qu'afficher cette surface.

    La deuxième méthode à l'avantage d'utiliser un peu moins de charge processeur si la taille de la surface n'est pas gigantesque. La première méthode peut "ralentir" les processus d'affichage si le dessin est complexe.

    En résumé il n'y a pas de solution idéale. Pour ton exercice, comme c'est le dessin d'un widget, il ne sera pas forcément complexe. La première méthode me semble la mieux adaptée. Tu pourras ainsi faire varier la taille du dessin en fonction de celle du GtkWidget sans être obligé de détruire et construire une nouvelle surface à chaque fois.

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