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 :

Typage des données/manipulation des données


Sujet :

GTK+ avec C & C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut Typage des données/manipulation des données
    Bonjour à tous,

    Je reviens avec une nouvelle difficulté.
    En fait, je cherche à représenter/dessiner une sorte de diagramme dans mon projet. Je dispose déjà de fonctions de dessin grâce à la bibliothèque Cairo, là n'est pas le problème. Le souci est plutôt comment gérer les données pour pouvoir le faire. Le diagramme doit être constitué ainsi :
    - il est constitué de plusieurs cases.
    - chaque case porte un nom et un id unique.
    - chaque case renferme un nombre connu à l'avance de "connecteurs" en entrée (à gauche de la case) et en sortie (à droite de la case) ; ils disposeront d'un nom et d'un "id" qui ne sera pas unique (voir plus bas).

    Cela serait simple ainsi sauf qu'il y a une précision importante : chaque connecteur peut être connecté avec un ou des autres opposés, càd un connecteur en sortie ne peut être connecté qu'avec un ou plusieurs connecteurs en entrée d'une autre case, et vice versa. Les connecteurs qui auront le même id (comme énoncé) seront alors connectés entre eux.

    Il faut donc lors de l'affichage que j'arrive à représenter les connexions par les lignes, il faut donc que je gère les données proprement et rapidement pour ne pas altérer les performances d'affichage.

    Je sollicite donc votre aide pour savoir quelle est la meilleure solution. Mon problème me fait penser à l'utilisation de la programmation orientée objet, mais je souhaite rester en C/GTK. Il y aussi ce tutoriel http://nicolasj.developpez.com/gobject/classe/#LV mais je trouve l'utilisation de GObject assez rebutante. Est-ce possible d'utiliser le typage abstrait classique des données ici ?

  2. #2
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    Bon voilà comment j'essaie de me débrouiller en typage abstrait classique des données :

    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
    typedef struct
    {
        gchar    *BoxName;
        gchar    *ID;
        GList    *pIN;
        GList    *pOUT;
    } stBox;
     
    typedef struct
    {
        gchar                          *BoxParent;
        gchar                          *ID;
        gchar                          *Name;
        guint                           X;
        guint                           Y;
    } stIN;
     
    typedef struct
    {
        gchar                          *BoxParent;
        gchar                          *ID;
        gchar                          *Name;
        guint                           X;
        guint                           Y;
    } stOUT;
    En gros, je place chaque Box dans une structure qui sont tous ensuite regroupé dans une GList. J'ai crée aussi une structure pour les petits connecteurs, une pour les entrées, une pour les sorties, qui seront eux aussi placés dans une GList. Ça fait beaucoup de GList et j'ai un peu peur que cela soit lourd et complexe à gérer en plus d'impacter les performances. Quelqu'un aurait peut-être une solution plus élégante ?

  3. #3
    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
    Citation Envoyé par Moravski Voir le message
    Mon problème me fait penser à l'utilisation de la programmation orientée objet, mais je souhaite rester en C/GTK.
    GTK est en C et orienté objet. Tu peux faire de la POO en C, avec ou sans GObject. C'est sûr que sans GObject tu es assez limité, mais le programmation orienté objet, ce n'est pas que l'héritage. Avoir une structure où tu rassembles des données cohérentes entre elles et des fonctions qui manipulent cette structure, c'est déjà de la programmation orienté objet.

    Bon, pour ton problème, il est clair que les listes chaînées c'est sympa un moment, mais c'est très long à parcourir quand tu as beaucoup d'éléments. Il est en revanche très rapide de supprimer un élément.

    Les tableaux sont rapides pour ajouter un élément, mais lents pour en supprimer un quand ce n'est pas le dernier. A parcourir, c'est moins long que la liste, mais c'est pas encore la panacée.

    Les tables de hachage sont rapides pour chercher un élément, mais moins rapides à parcourir que les tableaux.

    Je te conseille tout de même de regarder du côté des projets gstreamer et conduit. GStreamer a cette notion d'éléments (tes boites) et de pads (tes connecteurs). Conduit fait à peu près ce que tu veux faire au niveau graphique.

    J'ai des commentaires à faire sur tes structures et sur ce que tu pourrais adopter comme solution, mais je n'ai pas trop le temps là, je ferai ça plus tard.
    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)

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    OK c'est déjà sympa de m'aider. En fait je me rend compte que j'ai déjà manipuler GObject... en ayant crée un widget perso ! Du coup, je vois comment cela fonctionne, même si le problème est différent. Je tenterai probablement les deux voies (celle en cours et celle de GObject). et voir quelles est la solution la plus idéale.
    J'ai déjà décortiqué Conduit, mais c'est du Python, j'en ai qu'une vague connaissance... mais promis, j'apprendrai le Python quand j'aurai plus le temps !
    Pour Gstreamer, je ne savais pas, je vais consulter ça.

  5. #5
    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
    Pour gstreamer, c'est plus pour le principe: tu n'auras pas de code à en tirer, mais ce que tu veux faire ressemble furieusement aux concepts d'éléments, pads et sinks de gstreamer. D'ailleurs, tu as gst-editor qui est une application graphique (jamais fiinie, elle est restée en version 0.0.2) de configuration de pipeline gstreamer. Voici ce que ça donne:



    C'est en python aussi, mais ça se lit facilement car du gtk en python ou en C, ça reste du GTK. Les noms de fonctions et d'object sont quasi identiques.
    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)

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    Hello,

    J'ai fait un schéma de mes données avec leurs typages pour que ce soit plus clair :



    Mes structures stIN et stOUT ont été modifiées, j'ai mis une variable type pointrices pour X et Y. Je vais m'expliquer progressivement pourquoi.

    Voici comment je m'oriente pour procéder à ce que je veux, et le stade d'avancement :
    1. Listage des box ------------------------------> fait
    2. Listage des connecteurs de chaque box -------> fait
    3. Dessin des box -------------------------------> fait, mais à modifier pour que l'étape suivante puisse marcher
    4. Liaison des connecteurs avec une ligne --------> pas encore possible

    A l'étape 1, je récupère les noms, id etc. de chaque box. A l'étape 2, ce sont les connecteurs. Attention, à ce stade, je ne peux pas savoir à l'avance quelle sera la position x et y sur le plan de dessin.
    A l'étape 3, c'est la fonction de dessin, et même si je ne l'ai pas encore fait, je peux récupérer les données x et y de chaque connecteur qui seront nécessaire pour pouvoir dessiner la ligne de connexion. C'est justement là où j'ai des soucis. Vu que je fait appel à une fonction extérieure pour dessiner, il faut que je puisse modifier la structure du ou des connecteurs pour leur attribuer une valeur x et y, une fois chaque box dessinée. Donc j'ai pensé à utiliser des variables pointrices. Est-ce la bonne idée, puisque je n'y arrive pas ?
    Images attachées Images attachées  

  7. #7
    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
    Je pense que tu devrais passer plus de temps à réfléchir à tes structures de données et remettre ton problème à plat, sans penser à ce que tu as déjà fait...
    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)

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    Donc tu penses que ce n'est pas la bonne solution et donc que je dois revoir mon code en entier
    Finalement, j'y arrive ainsi petit à petit... Je continue, uniquement par expérience, mais de toute façon, tu n'as pas tort, je réviserai une fois que j'ai compris comment arriver à ce que je veux. Ma structure des petits connecteurs est fausse, il fallait bien rester à un simple guint et pas une variable pointrice.

  9. #9
    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
    Il n'y a pas de "vrai" ou de "faux", il y a plusieurs chemins qui peuvent mener à la solution. Mais rien que le fait que tes deux structures stIN et stOUT soient identiques me font penser que tu n'as pas encore assez réfléchi au problème avant de te mettre à coder. Le premier pas est vraiment d'être au point sur tes structures de données par rapport à tes besoins.

    Par exemple, dans GStreamer, une entrée ou sortie s'appelle un "Pad". C'est le même objet, et cela se voit bien dans tes structures que c'est identique. Je renouvelle mon conseil de lire attentivement la doc gstreamer au niveau des concepts évoqués:
    http://gstreamer.freedesktop.org/dat...ro-basics.html
    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)

  10. #10
    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
    Voici quelques remarques à propos de tes structures de données:

    stBox
    Pourquoi tu as des champs id et name séparés, alors que tu indiques que le nom est obligatoirement unique ? Un identifiant, c'est quelque chose d'unique qui identifie un objet, alors pourquoi avoir deux identifiants ? A la rigueur, j'aurais pu comprendre si ID avait été du type GQuark pour faire des comparaisons/recherches rapides, mais là ils sont du même type...

    Pour les champs pIN et pOUT: une GList ne me parait pas être une bonne idée pour stocker des éléments si tu connais leur nombre et que tu dois les parcourir fréquemment (pour retracer tes lignes par exemple). Je m'orienterai plutôt vers du GPtrArray pour stocker les structures d'entrée/sortie.

    Pour moi, ta structure stBox (un Element chez GStreamer) devrait ressembler à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef struct
    {
        gchar    *name;
        GPtrArray *in;
        GPtrArray *out;
    } stBox;
    ou bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typedef struct
    {
        gchar    *name;
        GPtrArray *pads;
    } stBox;
    stIN/stOUT
    Comme je te l'ai dit, tes deux structures sont actuellement identiques... Une entrée et une sortie, c'est la même chose. Ce sont juste deux "Pads" que l'on peut connecter. C'est le conteneur, ton stBox, qui donne la direction de la connexion entrée -> sortie. Tu n'as donc besoin que d'une seule structure, appelons la "stPad" par exemple.

    Ensuite, tu as un champ BoxParent qui identifie le conteneur qui contient le Pad. Bon, déjà, on peut utiliser juste "parent" pour le décrire. Un objet évite en général de faire des suppositions sur ce qui le contient, parce qu'il sait ce que lui utilise, mais qu'il n'a pas à savoir qui l'utilise. En revanche, si son parent est toujours un stBox, alors autant l'indiquer via son type, et prendre un pointeur vers une stBox.
    Pour le nom, c'est ok.
    Pour l'id, ton but était de le propager pour que tous les pads connectés entre eux aient le même id. Mais quel est l'intérêt ? Cela te permet de savoir simplement si deux pads sont connectés entre eux, mais tu ne peux pas savoir directement à quels pads est connecté un pad. Le mieux je pense donc de conserver dans chaque pad à quels autres pads il est connecté. On a donc la encore un tableau de pads.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GPtrArray *connections;
    Pour X et Y, je ne sais pas à quoi ils servent, je ne peux donc pas me prononcer sur leur utilité. Je me demande juste pourquoi il s'agit de pointeurs.
    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)

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    Tout d'abord je te remercie beaucoup pour ta réflexion, je comprend mieux !

    Citation Envoyé par liberforce Voir le message
    stBox
    Pourquoi tu as des champs id et name séparés, alors que tu indiques que le nom est obligatoirement unique ? Un identifiant, c'est quelque chose d'unique qui identifie un objet, alors pourquoi avoir deux identifiants ? A la rigueur, j'aurais pu comprendre si ID avait été du type GQuark pour faire des comparaisons/recherches rapides, mais là ils sont du même type...
    En fait, j'ai besoin des deux, il peut exister deux box ayant le même nom mais pas la même id, qui du coup permettra de les différencier.

    Citation Envoyé par liberforce Voir le message
    Pour les champs pIN et pOUT: une GList ne me parait pas être une bonne idée pour stocker des éléments si tu connais leur nombre et que tu dois les parcourir fréquemment (pour retracer tes lignes par exemple). Je m'orienterai plutôt vers du GPtrArray pour stocker les structures d'entrée/sortie.
    Ah, voilà quelque chose de nouveau que j'apprend ! Ne connaissant pas encore tout de GTK (et du C en général), je ne voyais pas d'autres solutions qu'une GList ou une GHashTable ! Je ne connaissais pas les GPtrArray. J'ai quelques questions dessus : il y a-t-il besoin de gérer le transtypage comme pour les GList ou c'est inutile ?
    Je m'explique : exemple pour récupérer le nom d'un pad dans le tableau d'indice i

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (gchar *)((stBox *)g_ptr_array_index (IDPatches, i))->Name
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_ptr_array_index (IDPatches, i)->Name ?
    Sinon, à vrai dire, je me rend compte aussi je ne sais pas pourquoi je suis parti avec deux structures différentes pour les petits connecteurs...

    Citation Envoyé par liberforce Voir le message
    stIN/stOUT
    Comme je te l'ai dit, tes deux structures sont actuellement identiques... Une entrée et une sortie, c'est la même chose. Ce sont juste deux "Pads" que l'on peut connecter. C'est le conteneur, ton stBox, qui donne la direction de la connexion entrée -> sortie. Tu n'as donc besoin que d'une seule structure, appelons la "stPad" par exemple.
    Je pencherai tout de même plus pour 2 structures au total : 1 pour les box et une pour les petits connecteurs, car j'ai bien peur qu'on ne s'y retrouve plus dans mon code.

    Citation Envoyé par liberforce Voir le message
    Ensuite, tu as un champ BoxParent qui identifie le conteneur qui contient le Pad. Bon, déjà, on peut utiliser juste "parent" pour le décrire. Un objet évite en général de faire des suppositions sur ce qui le contient, parce qu'il sait ce que lui utilise, mais qu'il n'a pas à savoir qui l'utilise. En revanche, si son parent est toujours un stBox, alors autant l'indiquer via son type, et prendre un pointeur vers une stBox.
    OK.

    Citation Envoyé par liberforce Voir le message
    Pour le nom, c'est ok.
    Pour l'id, ton but était de le propager pour que tous les pads connectés entre eux aient le même id. Mais quel est l'intérêt ? Cela te permet de savoir simplement si deux pads sont connectés entre eux, mais tu ne peux pas savoir directement à quels pads est connecté un pad. Le mieux je pense donc de conserver dans chaque pad à quels autres pads il est connecté. On a donc la encore un tableau de pads.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GPtrArray *connections;
    Effectivement, c'est mieux.

    Citation Envoyé par liberforce Voir le message
    Pour X et Y, je ne sais pas à quoi ils servent, je ne peux donc pas me prononcer sur leur utilité. Je me demande juste pourquoi il s'agit de pointeurs.
    En fait, j'en ai besoin pour savoir leurs positions pour dessiner les lignes de connexion. Mais je me pose la question, sachant que leur position est dépendante de celle du box parent et donc d'une formule simple, s'il vaut mieux stocker leurs valeurs courantes au sein de leur structure, ou alors de recalculer en fonction du x et y du box parent, sachant aussi qu'il va falloir gérer le redessinement lorsque l'utilisateur déplace une box.

    P.S. : j'ai commencé à recoder, et finalement, c'est pas plus mal, ça permet d'améliorer voire rectifier certaines portions du code.

  12. #12
    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
    Citation Envoyé par Moravski Voir le message
    En fait, j'ai besoin des deux, il peut exister deux box ayant le même nom mais pas la même id, qui du coup permettra de les différencier.

    Dans ce cas, utilise un id numérique, pas une chaine de caractère. Tu accélèreras les recherches et comparaisons entre 2 IDs.

    Citation Envoyé par Moravski Voir le message
    Ah, voilà quelque chose de nouveau que j'apprend ! Ne connaissant pas encore tout de GTK (et du C en général), je ne voyais pas d'autres solutions qu'une GList ou une GHashTable ! Je ne connaissais pas les GPtrArray.
    Les type de données de bases sont dans la GLib, la bibliothèque sur laquelle repose GTK+.
    http://library.gnome.org/devel/glib/stable/index.html
    Elle propose plein de types un peu élaborés: listes chaînées (simplement et doublement), piles, tables de hachage, tableaux dynamiques (d'éléments, de pointeurs, d'octets), etc.
    http://library.gnome.org/devel/glib/...ata-types.html


    Citation Envoyé par Moravski Voir le message
    J'ai quelques questions dessus : il y a-t-il besoin de gérer le transtypage comme pour les GList ou c'est inutile ?
    Je m'explique : exemple pour récupérer le nom d'un pad dans le tableau d'indice i

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (gchar *)((stBox *)g_ptr_array_index (IDPatches, i))->Name
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    g_ptr_array_index (IDPatches, i)->Name ?
    GPtrArray stocke des gpointer (en d'autres termes: des void*), donc elle ne conserve pas le type.

    Je te conseille donc la syntaxe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    stBox *box = g_ptr_array_index (IDPatches, i);
    g_assert (box != NULL);
    g_assert (box->Name != NULL);
    g_debug ("%s", box->Name);

    Citation Envoyé par Moravski Voir le message
    Je pencherai tout de même plus pour 2 structures au total : 1 pour les box et une pour les petits connecteurs, car j'ai bien peur qu'on ne s'y retrouve plus dans mon code.
    Oui, oui, je me suis mal fait comprendre, mais c'est ce que je t'ai dit: une structure pour les conteneurs, une pour les connecteurs.

    Citation Envoyé par Moravski Voir le message
    En fait, j'en ai besoin pour savoir leurs positions pour dessiner les lignes de connexion. Mais je me pose la question, sachant que leur position est dépendante de celle du box parent et donc d'une formule simple, s'il vaut mieux stocker leurs valeurs courantes au sein de leur structure, ou alors de recalculer en fonction du x et y du box parent, sachant aussi qu'il va falloir gérer le redessinement lorsque l'utilisateur déplace une box.
    En général, on évite de stocker la partie fonctionnelle (celle qui gère la logique) et la partie présentation (celle qui gère l'affichage) au même endroit. Je te déconseille donc de stocker les coordonnées dans ton connecteur, car cela dépend grandement du type de "vue" que tu souhaite utiliser (voir le modèle MVC). Imagine que tu souhaites présenter tes informations dans une arborescence par exemple, tes coordonnées n'ont plus de sens. Crée donc un autre objet dont le rôle sera dédié à dessiner tes conteneurs et les connecteurs associés.
    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)

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    [quote=liberforce;5592077]
    Les type de données de bases sont dans la GLib, la bibliothèque sur laquelle repose GTK+.
    http://library.gnome.org/devel/glib/stable/index.html
    Elle propose plein de types un peu élaborés: listes chaînées (simplement et doublement), piles, tables de hachage, tableaux dynamiques (d'éléments, de pointeurs, d'octets), etc.
    http://library.gnome.org/devel/glib/...ata-types.html

    Oui, je m'appuie beaucoup sur la GLib (et même exclusivement, j'évite d'avoir trop de dépendance), normal, je n'ai pas forcément le temps ni l'énergie pour tout recoder !
    Mais bon, j'avais bien lu la doc, mais je suis passer un peu à côté des pointeurs quand j'ai commencé à coder le programme, peut-être parce que j'étais frileux sur les pointeurs Maintenant c'est bon.

    Citation Envoyé par liberforce Voir le message
    GPtrArray stocke des gpointer (en d'autres termes: des void*), donc elle ne conserve pas le type.

    Je te conseille donc la syntaxe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    stBox *box = g_ptr_array_index (IDPatches, i);
    g_assert (box != NULL);
    g_assert (box->Name != NULL);
    g_debug ("%s", box->Name);
    Oui, il faut que je gère les problème éventuels d'assertion. Il y a des chances que ça arrive dans mon cas, donc j'ai implémenté dès le début l'éventualité, sinon c'est un coup à ne plus se retrouver pourquoi ça ne marche pas.

    Citation Envoyé par liberforce Voir le message
    En général, on évite de stocker la partie fonctionnelle (celle qui gère la logique) et la partie présentation (celle qui gère l'affichage) au même endroit. Je te déconseille donc de stocker les coordonnées dans ton connecteur, car cela dépend grandement du type de "vue" que tu souhaite utiliser (voir le modèle MVC). Imagine que tu souhaites présenter tes informations dans une arborescence par exemple, tes coordonnées n'ont plus de sens. Crée donc un autre objet dont le rôle sera dédié à dessiner tes conteneurs et les connecteurs associés.
    Oui, je me rend compte que pour bien gérer ce qu'il faut faire, il faut que je sépare complètement mes données de la gestion d'affichage, ne serait-ce que pour le traitement des données en dehors des interactions de l'utilisateur final, et le maintien du code.

    Je te remercie encore une fois ça fait du bien de temps en temps d'être "guidé" face à quelques difficultés ! Ca sort un peu du cadre GTK mais vu qu'on utilise les outils GLib/GTK pour répondre à un problème... Je tâcherai de faire part régulièrement de mes questionnements, en espérant que ça aidera certains.

  14. #14
    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
    Souvent le code n'est pas le plus intéressant, c'est plutôt le cheminement qui permet d'apprendre comment s'y prendre
    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)

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    OK, bon c'était plus facile à dire qu'à faire, non pas que ce que j'ai fait jusque là ne marche pas, au contraire, mais pour séparer données/présentation. En fait, je me rend compte qu'il faut que j'utilise une autre structure pour la présentation des données, pointant sur les "vraies" données. N'est-ce pas possible d'utiliser directement les données sans passer par cet intermédiaire ?
    Comment alors gérer le redessinement sans stocker des valeurs de type x et y ?

  16. #16
    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
    Tu crées juste tes types graphiques qui encapsulent par aggrégation tes types contenant la logique, le fonctionnel.

    Ton type graphique aura en plus les informations relatives à la représentation des données (coordonnées, couleur, type de connecteurs, etc.). Il te suffit alors de déléguer les appels à classe graphique vers ta classe contenant l'intelligence.
    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)

  17. #17
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    OK, bon me revoilà "à la charge".
    Maintenant que j'ai bien structuré mes données, que j'arrive à les représenter et à récupérer les données à travers l'interaction de l'utilisateur, je me pose la question du redessinement. Lorsque l'utilisateur déplace une boite, il faut actualiser la position des lignes représentant la connexion entre les petits connecteurs. Dois-je utiliser une simple boucle traitant ligne par ligne de la boite déplacée ou dois-je "paralléliser" la mise à jour de la position de chaque ligne partant de la boite déplacée ? Ce n'est pas que je programme un jeu vidéo et qu'il y a une nécessité d'un maximum de performance, mais quand même, n'ayant jamais été confronté à ce type de problème, je me pose la question.

  18. #18
    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
    En pratique, cela ne devrait poser problème que lorsque tu déplaces une boîte qui a énormément de connecteurs.

    J'ai fini par regarder un peu le code python des projets que je t'avais indiqué, il semble qu'ils utilisent GooCanvas pour la gestion du graphisme.
    http://live.gnome.org/GooCanvas
    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)

  19. #19
    Nouveau membre du Club
    Homme Profil pro
    Géomaticien
    Inscrit en
    Février 2010
    Messages
    63
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Géomaticien

    Informations forums :
    Inscription : Février 2010
    Messages : 63
    Points : 25
    Points
    25
    Par défaut
    Salut liberforce (bonne année et meilleurs voeux au passage),

    Bon tout avance bien, j'ai fait un nettoyage du code pour respecter et me rapprocher de tes recommandations.
    Me voilà à l'étape douloureuse de la libération de mémoire lorsqu'on a par exemple besoin de détruire une donnée.
    Ainsi, si je cherche à détruire une box, j'ai commencé à faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void
    box_destroy (stBox *Box)
    {
        g_free (Box->ID);
        g_free (Box->Name);
    }
    La structure typée est la même que celle que tu m'as conseillé pour stBox. Arrive le moment de libérer le GPtrArray pour mes petits connecteurs, avant de pouvoir faire g_slice_free sur la structure stBox. Il faut donc que je parcours un à un mes petits connecteurs pour pouvoir les détruire. Il me semble que je dois utiliser g_ptr_array_foreach, mais je n'ai pas compris ce qu'il fallait lui passer en tant que gpointer, et comme détruire toutes les données des petits connecteurs. Tu as une idée ?

    Merci à toi.

  20. #20
    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 Moravski,

    plusieurs remarques.
    1. les fonctions de libération d'un objet, je les appelle plutôt *_free, de la même manière que ce que fait gtk. Ça permet de rester uniforme.
    2. Ensuite, n'oublie pas de vérifier ton pointeur... Box->ID crashe si box vaut NULL.
    3. Une fois les données de la structure détruites, il faut détruire la structure elle-même...
    4. Pour fignoler, tu peux utiliser la macro G_LIKELY de la GLib qui permet d'indiquer quand une condition a plus de chances d'être vraie (permet au compilateur d'optimiser pour cette valeur de condition)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void 
    box_free (stBox *Box)
    {
        if G_LIKELY (Box != NULL)
        {
            g_free (Box->ID);
            g_free (Box->Name);
            g_free (Box);
        }
    }
    Pour libérer tous les éléments de ta GPtrArray, il faut effectivement utiliser g_ptr_array_foreach.

    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
     
    void 
    destroy_boxes (gpointer data, gpointer user_data)
    {
        box_free (data);    
    }
    /*....*/
    {
        stBox *boxes = g_ptr_array_new ();
     
        /* Ajouter ici du code pour ajouter/manipuler les boîtes */
     
        g_ptr_array_foreach (boxes, destroy_boxes, NULL);
        g_ptr_array_free (boxes, TRUE); /* Libère le tableau */
    }
    Pour éviter d'avoir une callback par type à effacer, tu peux aussi passer la fonction à utiliser pour détruire la donnée en paramètre user_data.

    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
     
    void 
    destroy_ptr_array_element (gpointer data, gpointer user_data)
    {
        GFreeFunc f = user_data;
        g_assert (f != NULL);
        g_assert (*f != NULL);
        (*f) (data);    
    }
    /*....*/
    {
        GPtrArray *boxes = g_ptr_array_new ();
     
        /* Ajouter ici du code pour ajouter/manipuler les boîtes */
     
        /* Destruction des boîtes */
        g_ptr_array_foreach (boxes, destroy_ptr_array_element, box_free);
     
        /* Destruction du tableau */
        g_ptr_array_free (boxes, TRUE); /* Libère le tableau */
    }
    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)

Discussions similaires

  1. Réponses: 5
    Dernier message: 09/05/2014, 11h47
  2. Manipuler des TDateTime comme des entiers?
    Par toufou25 dans le forum C++Builder
    Réponses: 8
    Dernier message: 22/06/2006, 15h52
  3. Réponses: 1
    Dernier message: 27/11/2005, 14h30
  4. Fonctions de manipulation des chaines et des dates
    Par Fares BELHAOUAS dans le forum Débuter
    Réponses: 3
    Dernier message: 09/11/2002, 22h43

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