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

Windows Forms Discussion :

DataGridView avec colonne CheckBox 2 (le retour xD)


Sujet :

Windows Forms

  1. #1
    Membre actif Avatar de DarkSeiryu
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2009
    Messages
    425
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2009
    Messages : 425
    Points : 275
    Points
    275
    Par défaut DataGridView avec colonne CheckBox 2 (le retour xD)
    Juste pour ceux qui auraient eu le même souci que moi (voir ce lien), en fait ça venait juste du fait que je ne mettais pas l'image correctement dans Access (je faisais un clique droit sur le champ, ajouter un fichier, à partir d'un fichier, ce qui me créait un package contenant surement le chemin d'accès à l'image (je pense vu que ça merdait pour l'afficher dans mon DataGridView), je pensais qu'il contenait l'image mais bon bref.

    Pour mettre votre image dans Access il ne faut pas cocher "A partir d'un fichier" mais sélectionner dans la liste du dessus "Image Bitmap" ou "Image Paintbrush". Cela vous ouvre Paint dans lequel vous pouvez coller l'image de votre choix en allant dans Edition/Coller à partir de...

    Voilà. Bon maintenant, autre souci, l'image qui s'affiche dans le DataGridView, c'est vraiment pas beau donc mon maître de stage a changé d'avis et me demande de faire en sorte qu'elle s'affiche à côté du DataGridView.
    Donc, j'en reviens à une de mes questions précédentes (je fais un copier/coller ^^).
    Citation Envoyé par DarkSeiryu
    J'ai mon DataGridView relié à ma table PictoClassification.
    Cette table contient 3 colonnes :
    1 - IdImgPictoClass (numérique)
    2 - NomPictoClass (string)
    3 - ImgPictoClass (byte), des images y sont donc sockées.

    Mon DataGridView a 2 colonnes :
    1 - NomPictoClass
    2 - Des CheckBox

    Je voudrais que lorsqu'on coche une CheckBox, l'image correspondante au texte de la première colonne soit affichée dans une PictureBox.
    Cela se fait surement à partir d'une requête dans le TableAdapter de ma DataTable, mais je ne sais pas comment faire pour que je dise que l'image que je veux est celle de la ligne que j'ai coché...
    Je patauge depuis une bonne heure, donc si une âme charitable pouvait me filer un coup de main, ça serait pas de refus...

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par DarkSeiryu Voir le message
    Cela se fait surement à partir d'une requête dans le TableAdapter de ma DataTable
    biiiip ! perdu, merci d'avoir joué

    Tu n'as pas besoin de faire une requête, vu que tu as déjà l'image dans ton DataTable. Je t'ai déjà donné dans ta discussion précédente le code pour obtenir une image à partir d'un tableau de byte (avec un MemoryStream).

    Donc a priori, ce qui te manque, c'est juste comment obtenir la ligne du DataTable correspondant à la ligne sélectionnée dans le DataGridView, c'est bien ça ?

    Tu peux obtenir la ligne courante du DGV avec la propriété CurrentRow, qui renvoie un objet DataGridViewRow. La classe DataGridViewRow a une propriété DataBoundItem, qui correspond à l'objet de données que cette ligne représente quand le DGV est en mode binding (DataSource défini).

    Quand ta source de données est une DataTable, DataBoundItem renvoie un DataRowView, qui est une vue d'un DataRow. A partir de là, tu as juste à prendre le champ qui t'intéresse... (ImgPictoClass en l'occurrence).

    Un petit bout de code pour rendre tout ça plus clair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    private void dgv_SelectedIndexChanged(object sender, EventArgs e)
    {
        DataRowView drv = dgv.CurrentRow.DataBoundItem as DataRowView;
        if (drv != null)
        {
            byte[] bytes = drv["ImgPictoClass"] as byte[];
            if (bytes != null)
            {
                picBox.Image = Image.FromStream(new MemoryStream(bytes));
            }
        }
    }
    Bon, ça c'était la solution compliquée
    Mais c'est toujours utile de savoir le faire...

    La solution simple (si tu utilises un BindingSource pour ton DataGridView) :
    - dans les propriétés de la PictureBox, déplie "(DataBindings)" (ça a peut-être un autre nom en français, je sais plus...)
    - pour la propriété Image, sélectionne le champ ImgPictoClass sur la BindingSource

    Et c'est tout

  3. #3
    Membre actif Avatar de DarkSeiryu
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2009
    Messages
    425
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2009
    Messages : 425
    Points : 275
    Points
    275
    Par défaut
    Merci pour ta réponse.
    Citation Envoyé par tomlev
    biiiip ! perdu, merci d'avoir joué
    J'aurais essayé
    Citation Envoyé par tomlev
    Donc a priori, ce qui te manque, c'est juste comment obtenir la ligne du DataTable correspondant à la ligne sélectionnée dans le DataGridView, c'est bien ça ?
    Non, je veux que lorsque je coche une CheckBox, l'image correspondante à la ligne apparaisse dans une PictureBox et si je décoche la case, la PictureBOx correspondante disparaît. Et j'ai 9 images et je voudrais qu'il soit possible à l'utilisateur d'afficher les 9.
    Citation Envoyé par tomlev
    Je t'ai déjà donné dans ta discussion précédente le code pour obtenir une image à partir d'un tableau de byte (avec un MemoryStream).
    Oui ! Mais je sais pas si tu te rappelles, quand je lui passe bytes en paramètre je me prenais une exception :
    ArgumentException : Le paramètre n'est pas valide.
    Et ben là c'est pareil lol Je te mets un screenshot de ce que contient bytes ^^
    Donc je me demandais, j'suis vraiment obligé de mettre mes images dans un tableau de bytes ? Parce que de ce que j'ai compris dans ma DataTable elles sont en bytes...

    Merci d'avance !

    PS : voici mon code (pas très net sur le screenshot)
    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
            private void dgv_classification_CurrentCellDirtyStateChanged(object sender, EventArgs e)
            {
                if (dgv_classification.CurrentCell.OwningColumn.Name == "ColCheckedBoxClass")
                {
                    if (dgv_classification.CommitEdit(DataGridViewDataErrorContexts.Commit))
                    {
                        bool isChecked = (bool)dgv_classification.CurrentCell.Value;
                        if (isChecked == true)
                        {
                            DataRowView drv_classification = dgv_classification.CurrentRow.DataBoundItem as DataRowView;
                            if (drv_classification != null)
                            {
                                byte[] bytes = drv_classification["ImgPictoClass"] as byte[];
                                if (bytes != null)
                                {
                                    PictureBox test = new PictureBox();
                                    tp_class.Controls.Add(test);
                                    test.Size = new Size(92, 106);
                                    test.Location = new Point(300, 90);
                                    test.BorderStyle = BorderStyle.FixedSingle;
                                    test.Image = Image.FromStream(new MemoryStream(bytes));
                                }
                            }
                        }
                        else
                        {
                            // Code pour cacher/supprimer les PictureBox lors d'un décochage de CheckBox
                        }
                    }
                }
            }

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par DarkSeiryu Voir le message
    Oui ! Mais je sais pas si tu te rappelles, quand je lui passe bytes en paramètre je me prenais une exception :
    Oui, mais si je me rappelle bien, c'était à cause de la façon dont tu mettais l'image dans la base... D'ailleurs la taille de bytes me semble beaucoup plus correcte maintenant.

    En fait, j'ai fait un petit test d'un cas similaire au tien. Avec le binding, ça marche nickel... je sais pas comment il se débrouille, mais il arrive à interpréter les données binaires pour en sortir une image. Par contre, j'ai moi aussi l'erreur quand j'essaie de faire Image.FromStream...

    J'ai donc enregistré les données binaires dans un fichier, et en l'ouvrant dans un éditeur hexa, ça donne ça :

    En fait, le bitmap proprement dit commence après la partie surlignée... les 78 premiers octets correspondent, je pense, à l'en-tête de l'objet OLE. Il faut donc les ignorer lors du décodage...

    Tu peux faire quelque chose comme ça :
    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
    ...
                                if (bytes != null)
                                {
                                    PictureBox test = new PictureBox();
                                    tp_class.Controls.Add(test);
                                    test.Size = new Size(92, 106);
                                    test.Location = new Point(300, 90);
                                    test.BorderStyle = BorderStyle.FixedSingle;
                                    byte[] bmpBytes = new byte[bytes.Length - 78];
                                    MemoryStream ms = new MemoryStream(bytes);
                                    ms.Read(bmpBytes, 0, 78); // on lit les 78 premiers bytes
                                    ms.Read(bmpBytes, 0, bmpBytes.Length); // on les écrase aussitôt avec la suite des données
                                    ms = new MemoryStream(bmpBytes); // et on recrée le MemoryStream avec le nouveau buffer
                                    test.Image = Image.FromStream(ms);
                                }
    ...
    EDIT: en fait, il y a pire : quand on utilise le binding pour afficher l'image, il modifie le contenu du champ image dans le DataRow pour supprimer l'en-tête OLE

  5. #5
    Membre actif Avatar de DarkSeiryu
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2009
    Messages
    425
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2009
    Messages : 425
    Points : 275
    Points
    275
    Par défaut
    Putain mec t'es un Dieu vivant !
    Le Dieu du C# !
    "Oh tomlev, indique nous le chemin du codage !" xD
    Ouais j'ai craqué mais c'est tellement beau !
    Merci t'as géré, désolé des contre-temps que ça t'a occasionné.

    Bon par contre là j'me demande un truc, comment je peux faire pour que chaque image apparaisse dans une PictureBox différente ?

    Voici mon code actuel :
    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
    private PictureBox test = new PictureBox();
            private void dgv_classification_CurrentCellDirtyStateChanged(object sender, EventArgs e)
            {
                if (dgv_classification.CurrentCell.OwningColumn.Name == "ColCheckedBoxClass")
                {
                    if (dgv_classification.CommitEdit(DataGridViewDataErrorContexts.Commit))
                    {
                        bool isChecked = (bool)dgv_classification.CurrentCell.Value;
                        if (isChecked == true)
                        {
                            DataRowView drv_classification = dgv_classification.CurrentRow.DataBoundItem as DataRowView;
                            if (drv_classification != null)
                            {
                                byte[] bytes = drv_classification["ImgPictoClass"] as byte[];
                                if (bytes != null)
                                {
                                    tp_class.Controls.Add(test);
                                    test.Size = new Size(92, 106);
                                    test.Location = new Point(300, 90);
                                    test.BorderStyle = BorderStyle.FixedSingle;
                                    byte[] bmpBytes = new byte[bytes.Length - 78];
                                    MemoryStream ms = new MemoryStream(bytes);
                                    ms.Read(bmpBytes, 0, 78); // On lit les 78 premiers bits.
                                    ms.Read(bmpBytes, 0, bmpBytes.Length); // On les écrase aussitôt avec la suite des données.
                                    ms = new MemoryStream(bmpBytes); // On récréé la stream avec le nouveau buffer
                                    test.Image = Image.FromStream(ms);
                                    test.Visible = true;
                                }
                            }
                        }
                        else
                        {
                            test.Visible = false;
                        }
                    }
                }
            }
    Cela ne me créé qu'une seule PictureBox.
    Or, mettons que je coche X CheckBox, il me faut X PictureBox qui contiennent chacune l'image de la ligne cochée. Et si je décoche une CheckBox, la PictureBox correspondante doit disparaître.

    Comment dois-je m'y prendre ?
    Merci d'avance...

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par DarkSeiryu Voir le message
    Bon par contre là j'me demande un truc, comment je peux faire pour que chaque image apparaisse dans une PictureBox différente ?
    Comme tu avais fait au début, en créant un nouveau PictureBox pour chaque image (au lieu de toujours réutiliser la même comme dans ton dernier code). Par contre il faut pas les mettre au même endroit, sinon tu verras que la dernière...
    Et bien sûr, il faut supprimer la PictureBox quand on décoche la ligne, il faut donc garder quelque part une référence liée à chaque ligne. Le plus simple pour faire ça, à mon avis, est d'utiliser un Dictionary<int, PictureBox> (la clé correspond à l'id de la ligne). Quand tu crées une PictureBox, tu l'ajoutes au dictionnaire, et tu la supprimes quand la ligne est décochée :
    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
    private Dictionary<int, PictureBox> pictureBoxes = new Dictionary<int, PictureBox>();
     
    ...
                        int id = (int)drv_classification["IdImgPictoClass"];
                        if (isChecked == true)
                        {
                            ...
                                if (bytes != null)
                                {
                                    PictureBox test = new PictureBox();
                                    tp_class.Controls.Add(test);
     
                                    pictureBoxes[id] = test;
                                    ...
                                }
                            }
                        }
                        else
                        {
                            if (pictureBoxes.ContainsKey(id))
                            {
                                PictureBox test = pictureBox[id];
                                pictureBoxes.Remove(id);
                                tp_class.Controls.Remove(test);
                            }
                        }
    Pour ce qui est de la disposition des PictureBox, plutôt que de les disposer manuellement, je te conseille de les mettre dans un FlowLayoutPanel

  7. #7
    Membre actif Avatar de DarkSeiryu
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2009
    Messages
    425
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2009
    Messages : 425
    Points : 275
    Points
    275
    Par défaut
    Heureusement que t'es là, j'aurais jamais pu trouver tout ça tout seul lol

    Bon sinon, ça marche, mais à moitié...
    Je m'explique, quand je coche une CheckBox, il m'affiche bien l'image correspondante dans une PictureBox, mais deux fois... Et quand je décoche la CheckBox, il ne m'en supprime qu'une... Et si je coche une autre CheckBox(ou la même), j'en ai de nouveau 2 etc.

    Voici mon code complet :
    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
    private FlowLayoutPanel flp_classification = new FlowLayoutPanel();
            private Dictionary<int, PictureBox> pictureBoxes = new Dictionary<int, PictureBox>();
            private void dgv_classification_CurrentCellDirtyStateChanged(object sender, EventArgs e)
            {
                if (dgv_classification.CurrentCell.OwningColumn.Name == "ColCheckedBoxClass")
                {
                    if (dgv_classification.CommitEdit(DataGridViewDataErrorContexts.Commit))
                    {
                        DataRowView drv_classification = dgv_classification.CurrentRow.DataBoundItem as DataRowView;
                        int id = (int)drv_classification["IdPictoClass"];
                        bool isChecked = (bool)dgv_classification.CurrentCell.Value;
                        if (isChecked)
                        {
                            if (drv_classification != null)
                            {
                                byte[] bytes = drv_classification["ImgPictoClass"] as byte[];
                                if (bytes != null)
                                {
                                    flp_classification.Location = new Point(288, 78);
                                    flp_classification.Size = new Size(572, 245);
                                    tp_class.Controls.Add(flp_classification);
     
                                    PictureBox pb_picto_class = new PictureBox();
                                    pb_picto_class.Size = new Size(92, 106);
                                    pb_picto_class.BorderStyle = BorderStyle.FixedSingle;
                                    pb_picto_class.SizeMode = PictureBoxSizeMode.StretchImage;
                                    flp_classification.Controls.Add(pb_picto_class);
                                    pictureBoxes[id] = pb_picto_class;
     
                                    byte[] bmpBytes = new byte[bytes.Length - 78];
                                    MemoryStream ms = new MemoryStream(bytes);
                                    ms.Read(bmpBytes, 0, 78); // On lit les 78 premiers bits.
                                    ms.Read(bmpBytes, 0, bmpBytes.Length); // On les écrase aussitôt avec la suite des données.
                                    ms = new MemoryStream(bmpBytes); // On récréé la stream avec le nouveau buffer
                                    pb_picto_class.Image = Image.FromStream(ms);
                                }
                            }
                        }
                        else
                        {
                            if (pictureBoxes.ContainsKey(id))
                            {
                                PictureBox pb_picto_class = pictureBoxes[id];
                                pictureBoxes.Remove(id);
                                flp_classification.Controls.Remove(pb_picto_class);
                            }
                        }
                    }
                }
            }
    J'ai mis un point d'arrêt sur cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PictureBox pb_picto_class = new PictureBox();
    et j'ai lancé le déboguage. Et là je me suis aperçu qu'il passait deux fois par la création de le PictureBox à chaque cochage de CheckBox.

    Je ne vois pas pourquoi ça fait ça vu que je n'ai pas de boucle...

    Merci d'avance !

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Ah ok, je crois savoir pourquoi...
    L'évènement CurrentCellDirtyStateChanged se produit quand la valeur de la propriété IsCurrentCellDirty change... IsCurrentCellDirty signifie, en gros : est-ce que la cellule courante est "sale", autrement dit, est-ce qu'elle a des modifications non validées. Et l'appelle à CommitEdit modifie la valeur de cette propriété il me semble... (ça la passe de true à false)
    Donc en gros, avant le CommitEdit, il faudrait vérifier si IsCurrentCellDirty est true. Si c'est false, tu sors de la fonction

  9. #9
    Membre actif Avatar de DarkSeiryu
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2009
    Messages
    425
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Janvier 2009
    Messages : 425
    Points : 275
    Points
    275
    Par défaut
    Après 3 jours de galères, ça marche enfin parfaitement !

    Merci beaucoup tomlev t'as assuré !

    T'es le Dieu du C# xD

    Merci encore ^^

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [VB.NET] DatagridView avec colonnes de type RichTextBox
    Par ZoomBox dans le forum Windows Forms
    Réponses: 5
    Dernier message: 15/05/2012, 11h14
  2. Réponses: 8
    Dernier message: 30/03/2010, 17h01
  3. DatagridView et colonne checkBox
    Par amirad dans le forum VB.NET
    Réponses: 1
    Dernier message: 16/03/2010, 17h01
  4. Datagridview avec colonne de plusieurs types
    Par Laur3nT dans le forum Windows Forms
    Réponses: 3
    Dernier message: 08/07/2008, 16h33
  5. gridview avec colonne checkbox
    Par questlove dans le forum Windows Forms
    Réponses: 4
    Dernier message: 13/06/2008, 14h35

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