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

C++Builder Discussion :

Défaire ou refaire ce qui figure sur un Canvas


Sujet :

C++Builder

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 69
    Par défaut Défaire ou refaire ce qui figure sur un Canvas
    Bonjour à tous!
    Je voudrais savoir s'il existait une fonction qui servirait à défaire où refaire ce que l'on a dessiné sur un canvas.
    Par exemple:
    -pour un composant TEdit on fait Edit1->Undo();
    -pour un TMemo un on envoit un message Windows WM_UNDO:
    SendMessage(Memo->Handle,WM_UNDO,0,0);
    mais pour le Canvas je n'ai rien trouvé.
    Merci de m'aider
    Bon courage à tous!

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Avec ma version BCB3 Pro, ça n'existe pas.
    En fait, il faut le mettre en place soi-même en objétisant les actions.
    Par exemple, si à un instant T on a effectué un CopyRect il faudrait pour bien faire mémoriser le contenu du rectangle source dans un bitmap afin de le rétatblir en cas d'undo.

    Pour des situations beaucoup plus critiques (dessin par accumulation de primitives etc...) on aurait intérêt à modiliser les objets graphiques de manière à jongler avec deux listes (l'une dont les objets sont dessinés et l'autre qui contient les objets temporairement retirés pour ensuite ou éventuellement autoriser un redo).

    A plus !

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 69
    Par défaut
    Merci henderson de m'avoir répondu mais j'avoue que ça me parrait compliqué surtout que je ne suis qu'une débutante en programmation orientée objet.
    N'y aurait-il pas une solution plus abordable?

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    La solution abordable est au bout de tes doigts : la POO !

    Défaire quoi au juste ?

    A plus !

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 69
    Par défaut
    Lors d'un click sur le canvas d'un TImage, un bitmap en forme de réctangle se dessine à l'emplacement du click de la souris. Après plusieurs clicks j'aimerais faire un Undo. Et le problème est justement là..
    Merci!

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 69
    Par défaut
    Alors..Personne n'a jamais eu affaire à ce problème?
    ok si pas de solution rapide, comment pourrais-je le faire en programmant?

  7. #7
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2002
    Messages
    1 407
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 1 407
    Par défaut
    Salut !

    Voici un exemple très minimaliste qui montre comment objétiser des actions.
    Ici je n'ai développé qu'une seule action qui consiste à dessiner un bitmap quelconque à un endroit quelconque.

    La classe jAction dérive de TComponent pour ne pas avoir à détruire ces objets manuellement; c'est leur propriétaire (dérivé de TComponent lui aussi) qui s'en chargera lors de sa propre destruction.
    Comme on peut le voir, cette classe va permettre de mémoriser :
    - un bitmap (celui que l'on va incruster)
    - une position
    - un canvas, en tant que support de l'incrustation

    L'objet dispose également d'une méthode Do qui va précisément réaliser l'incrustation.

    En plus, on dispose d'une méthode HasFocus pour détecter si l'objet graphique c'est à dire le résultat de la copie du bitmap, est sous le curseur.
    On pourra donc sélectionner une action (via le résultat graphique) ce qui sera pratique pour sa suppression.

    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
     
    class jAction : public TComponent
    {
    private :
     
    public :
     
    Graphics::TBitmap *Bitmap; //simple pointeur
    TCanvas *Canvas; //simple pointeur
    TPoint Pos;
     
        //On initialise dès la construction
        __fastcall jAction(TComponent *AOwner,
                           Graphics::TBitmap *B,
                           TCanvas *C,
                           TPoint P);
        __fastcall ~jAction();
        bool __fastcall HasFocus(TRect R);
        void __fastcall Do();
    };

    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
     
    __fastcall jAction::jAction(TComponent *AOwner, Graphics::TBitmap *B, TCanvas *C, TPoint P)
        : TComponent(AOwner)
    {
    Bitmap = B;
    Canvas = C;
    Pos = P;
    }
     
    __fastcall jAction::~jAction()
    {
    }
     
    void __fastcall jAction::Do()
    {
    Canvas->Draw(Pos.x, Pos.y, Bitmap);
    }
     
    bool __fastcall jAction::HasFocus(TRect R)
    {
    // Je montre en détail mais ça se simplifie...
    int left = Pos.x;
    int top = Pos.y;
    int right = left + Bitmap->Width;
    int bottom = top + Bitmap->Height;
    return((left < R.Right) &&
           (right >= R.Left) &&
           (top < R.Bottom) &&
           (bottom >= R.Top));
    }

    J'ai volontairement pris comme support du dessin une classe dérivée de TCustomControl..., c'est juste pour l'exemple !

    On va donner à ce jPaintBox de quoi :
    - mémoriser une image de fond
    - mémoriser les actions
    - remonter la séquence des opérations
    - sélectionner/supprimer ou ajouter une action


    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
     
    class jPaintBox : public TCustomControl
    {
    private :
     
    int FStep; // pour caler la sequence des actions
    TList *Actions; // la liste des actions (du type jAction)
    Graphics::TBitmap *FImage; //simple pointeur vers une image de fond (bitmap)
     
    protected :
        //méthodes Set pour les propriétés
        void __fastcall SetStep(int Value);
        void __fastcall SetImage(Graphics::TBitmap *Value);
     
    public :
     
    TImage *Target; //Cible (l'image à incruster) que l'utilisateur devra fournir
     
        __fastcall jPaintBox(TComponent *AOwner);
        __fastcall ~jPaintBox();
     
        // pour se peindre lui-même, il suffit de surcharger la méthode Paint
        void __fastcall Paint();
        // pour ajouter une action
        void __fastcall Add(Graphics::TBitmap *I, TPoint P);
        // pour ajouter une action lors du MouseDown sur l'objet
        void __fastcall OnMouseDownAdd(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y);
        // pour aller chercher un objet sous le curseur
        jAction* __fastcall HasFocus(TRect R);
        // la méthode tant espérée
        void __fastcall Undo();
     
        //Les propriétés visibles par l'utilsateur
        //A ce stade... nous sommes les concepteurs du bidule donc ...
        __property Graphics::TBitmap *Image={read=FImage, write=SetImage};
        __property int Step={read=FStep, write=SetStep};
     
    };
    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
     
    __fastcall jPaintBox::jPaintBox(TComponent *AOwner)
        : TCustomControl(AOwner)
    {
    if(AOwner->InheritsFrom(__classid(TWinControl))) Parent = (TWinControl*)AOwner;
    Actions = new TList;
    OnMouseDown = OnMouseDownAdd;
    }
     
    __fastcall jPaintBox::~jPaintBox()
    {
    Actions->Clear();
    delete Actions;
    Actions = NULL;
    }
     
    void __fastcall jPaintBox::SetStep(int Value)
    {
    FStep = Value;
    Repaint(); //pour rendre la modification visible immédiatement
    }
     
    void __fastcall jPaintBox::SetImage(Graphics::TBitmap *Value)
    {
    FImage = Value;
    Repaint(); //pour rendre la modification visible immédiatement
    }
     
    void __fastcall jPaintBox::Paint()
    {
    if(Image != NULL)
        {
        Canvas->Draw(0,0,Image);
        }
    else
        {
        Canvas->Brush->Style = bsSolid;
        Canvas->Brush->Color = Brush->Color;
        Canvas->FillRect(Rect(0,0,Width,Height));
        }
    if(Actions != NULL) // par sécurité
        {
        for(int j = 0; (j < Step) && (j < Actions->Count); j++)
            {
            ((jAction*)Actions->Items[j])->Do();
            }
        }
    }
     
    void __fastcall jPaintBox::Add(Graphics::TBitmap *I, TPoint P)
    {
    jAction *Action = new jAction(this, I, Canvas, P);
    Actions->Add(Action);
    Step = Actions->Count; //Step = Count à chaque ajout
    }
     
    void __fastcall jPaintBox::OnMouseDownAdd(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
    {
    // pour faire la distinction entre sélectionner/supprimer et ajouter
    if(Button == mbRight)
        {
        jAction *Action = HasFocus(Rect(X,Y,X,Y));
        if(Action != NULL)
            {
            if (MessageDlg("Supprimer l'action ?", mtConfirmation,
                     TMsgDlgButtons() << mbYes << mbNo, 0) == mrYes)
                {
                Actions->Delete(Actions->IndexOf(Action));
                delete Action; // suppression manuelle ici
                Step = Step - 1; // pour une suppression réaliste
                }
            }
        }
    else
        {
        Add(Target->Picture->Bitmap, Point(X,Y));
        }
    }
     
    /*
    Ici, on va travailler en mode rétro simplement par ce que chaque action est
    dessinée sous la suivante.
    */
     
    jAction* __fastcall jPaintBox::HasFocus(TRect R)
    {
    jAction *Action;
    int max = Actions->Count - 1;
    if(Step < max) max = Step;
    for(int j = max; j >=0; j--)
        {
        Action = (jAction*)Actions->Items[j];
        if(Action->HasFocus(R)) return Action;
        }
    return NULL;
    }
    A ce stade, voici ce que j'ai rajouté pour tester l'ensemble :
    - 4 TImages (Image1...4). Pour ces 4 images, un simple clic sur l'une d'elles
    permet de la mémoriser en tant que cible pour une éventuelle action.
    L'action est effective dès que l'on clique sur l'objet PaintBox.
    - 1 TImage (Image5) qui me permet de rajouter un fond pour le PaintBox. Cette image est invisible pour l'utilisateur et le PaintBox vient se positionner au dessus.
    - 1 TScrollBar pour remonter la séquence des actions.

    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
     
    jPaintBox *PaintBox;
     
    //---------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    PaintBox = new jPaintBox(this);
    //REM : Image5 sert pour le fond
    PaintBox->SetBounds(Image5->Left, Image5->Top, Image5->Width, Image5->Height);
    PaintBox->Image = Image5->Picture->Bitmap;
    PaintBox->Target = Image1; // pour éviter un NULL
    }
    //---------------------------------------------
     
    void __fastcall TForm1::Image1Click(TObject *Sender)
    {
    PaintBox->Target = (TImage*)Sender;
    }
    //---------------------------------------------
     
    void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
    {
    PaintBox->Step = ScrollBar1->Position;
    }
    //---------------------------------------------
    Ce que je montre ici, est déclinable pour les primitives de TCanvas.
    Par contre, dans ce cas, il faudra passer par une classe de base et aménager les classes dérivées de manière à ce qu'elles réalisent l'action.
    Par ailleurs, on peut aussi rajouter d'autres fonctionnalités (le Drag, par exemple, est simple à mettre en place).

    A plus !

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 69
    Par défaut
    Je vous remercie Henderson pour l'aide que vous m'avez apportée. J'ai testé votre programme et ça marche vraiment comme je voulais.
    Il y a cependant un petit détail, lorsque je reviens en arrière (Undo) tout se passe comme prévu mais quand je veux rajouter une image (dessin), l'image est rajoutée mais au dernier état de mon PainBox.
    C'est à dire que si j'avais 3 bitmaps dessinés et que je reviens à l'état où j'en avais qu'un seul, en ajoutant un autre bitmap, les 2 images supprimées réaparraissent et j'ai finalement 4 bitmaps dessinés.
    Merci encore pour votre effort.
    Bon courage!

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 24/05/2013, 13h32
  2. [CV] Projets qui peuvent figurer sur un CV
    Par afrikha dans le forum CV
    Réponses: 20
    Dernier message: 09/12/2005, 06h34
  3. Qui vient sur developpez.com ?
    Par chess dans le forum Evolutions du club
    Réponses: 29
    Dernier message: 11/09/2004, 13h31
  4. application qui connecte sur une page web
    Par spoolz dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 14/04/2004, 09h47
  5. LABEL QUI DISPARAIT SUR UN PICTUREBOX !
    Par Sophie42 dans le forum MFC
    Réponses: 2
    Dernier message: 13/01/2004, 12h10

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