paintbox freihandlinie zeichnen



  • Kannst du mir mit std::vector etwas Beispielcode geben? Danke!





  • Verstehe ich das richtig, dass dann aber OnPaint immer wieder aufgerufen werden muss und dort jedesmal die kompletten Linienstücke neu gezeichnet werden müssen?



  • Weder sollst du OnPaint selbst aufrufen (das macht das Betriebssystem für dich), noch sollst du in irgendwelchen anderen Eventhandlern wie OnMouseDown / OnMouseMove OnMouseUp irgendwelche Zeichenroutinen aufrufen. Alle Zeichenvorgänge haben in OnPaint stattzufinden, sonst hast du undefiniertes und wahrscheinlich inkonsistentes Verhalten. Und ja, du mußt immer alle Linienstücke zeichnen. (Das ist nicht ganz korrekt; eigentlich solltest du das Canvas nach einem Clipping-Rechteck fragen, um zu erfahren, welchen Teilbereich des Bildes du neuzeichnen mußt. Aber das macht die Sache jetzt nur unnötig kompliziert, und das einfachste ist, du zeichnest immer alles.)



  • Dann ist also mein obiger Code Müll?
    Und ich müsste in OnPaint in z.B. einem dyn. Vector jede Linie, die ich mit der Mouse zeichne (inkl. Stiftfarbe, Strichstärke,..) speichern, solange ich einen weiteren Strich hinzufüge? Und wenn ich die Zeichnung löschen will, dann wird auch der Inhalt des Vectors wieder gelöscht?
    Hört sich kompliziert an. Gibt es hierfür evtl. irgendwo eine "Musterlösung"?
    Danke!



  • williman schrieb:

    Und ich müsste in OnPaint in z.B. einem dyn. Vector jede Linie, die ich mit der Mouse zeichne (inkl. Stiftfarbe, Strichstärke,..) speichern, solange ich einen weiteren Strich hinzufüge? Und wenn ich die Zeichnung löschen will, dann wird auch der Inhalt des Vectors wieder gelöscht?

    Entweder das, oder du zeichnest deine Linien einfach auf ein transparentes Bitmap, das du dann wiederum in OnPaint aufs Canvas zeichnest. Hat beides Vor- und Nachteile, aber letzteres ist einfacher umzusetzen und auch effizienter.

    williman schrieb:

    Hört sich kompliziert an. Gibt es hierfür evtl. irgendwo eine "Musterlösung"?

    In den C++Builder-Demoprojekten gibt es ein Projekt namens "Graphex", das demonstriert, wie man in das Bitmap einer TImage -Komponente zeichnet. Das geht ganz analog mit deinem eigenen Bitmap. Um in OnPaint dein transparentes Bitmap aufs Canvas zu zeichnen, verwende TCanvas::Draw() .



  • Danke audacia,

    genau das meinte ich.



  • Deinen Vorschlag mit dem malen aufs transparente Bitmap und am Ende per OnPaint in Paintbox per Draw habe ich nun getestet u. funktioniert auch, allerdings bekomme ich das Bitmap nicht transparent gemacht. Das Bitmap hat immer die Hintergrundfarbe weiß. Ein dahinter liegendes Timage sollte aber hindurch scheinen:

    TForm1...
    	DrawingBoard = new Graphics::TBitmap;
    	DrawingBoard->Width = PaintBox1->Width;
    	DrawingBoard->Height = PaintBox1->Height;
    	DrawingBoard->Transparent = true;  // <-- damit sollte das Bitmap 
                                    //transparent sein, wird es aber nicht !!!
    	DrawingBoard->TransparentMode = tmAuto;
    	DrawingBoard->Canvas->Pen->Color = PaintBox1->Canvas->Pen->Color;
    	DrawingBoard->Canvas->Pen->Width = PaintBox1->Canvas->Pen->Width;
    
    // ---------------------------------------------------------------------------
    void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
    {
    
       PaintBox1->Canvas->Draw(0, 0, DrawingBoard);
    
    }
    // ---------------------------------------------------------------------------
    
    void __fastcall TForm1::PaintBox1MouseMove(TObject *Sender, TShiftState Shift,
    	int X, int Y) {
    	if (IsDrawing)
    	{
    		PaintBox1->Canvas->LineTo(X, Y); // only draw if mouse is down
    		DrawingBoard->Canvas->LineTo(X, Y);
    	}
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::PaintBox1MouseDown(TObject *Sender, TMouseButton Button,
    	TShiftState Shift, int X, int Y) {
    
    	IsDrawing = True;
    	PaintBox1->Canvas->MoveTo(X, Y);
    	DrawingBoard->Canvas->MoveTo(X, Y);
    
    }
    // ---------------------------------------------------------------------------
    
    void __fastcall TForm1::PaintBox1MouseUp(TObject *Sender, TMouseButton Button,
    	TShiftState Shift, int X, int Y) {
    
    	if( IsDrawing )
        {
    		PaintBox1->Canvas->Draw(0, 0, DrawingBoard);
    		IsDrawing = False;
        }
    }
    

    Wie bekomme ich die Transparenz bei Drawingboard hin?



  • Einfacher Test:

    // MainUnit.h
    #include <memory>
    
    class TForm1 : public TForm
    {
        ...
        void __fastcall PaintBox1Paint(TObject *Sender);
    private:	// Anwender-Deklarationen
        std::unique_ptr<Graphics::TBitmap> bmp; // <-- bitte einen Smartpointer nehmen!
        ...
    };
    
    // MainUnit.cpp
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        bmp.reset(new Graphics::TBitmap());
    
            // SetSize() ist effizienter als das separate Setzen von Width/Height
        bmp->SetSize(Image1->Picture->Width, Image1->Picture->Height);
        bmp->Transparent = true;
        bmp->TransparentColor = clFuchsia;
    
            // Bitmap löschen und transparent machen
        bmp->Canvas->Brush->Color = clFuchsia;
        bmp->Canvas->FillRect(Rect(0, 0, bmp->Width, bmp->Height));
    
            // irgendwas zeichnen
        bmp->Canvas->Ellipse(50, 50, 300, 200);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
    {
        PaintBox1->Canvas->Draw(0, 0, bmp.get());
    }
    


  • Eine gezeichnete Linie ist leider sehr zackig. Leider ist wohl eine Kantenglättung (Antialiasing) hierbei nicht möglich. Hierfür müsste man GDI+ verwenden. Auch nach langer Recherche komme ich noch nicht sehr weit. Ich müsste GDI+ mit der PaintBox kombinieren.
    Initialisierung von GDI+ funzt. Aber wie gehts weiter? Wo packe ich ein Drawline hin bzw. wie müssten die PaintBox-Events geändert werden?
    Danke!


Anmelden zum Antworten