Laden...

Bewegte Objekte auf Transparentem Hintergrund zeichnen

Erstellt von Console32 vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.616 Views
C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren
Bewegte Objekte auf Transparentem Hintergrund zeichnen

Hallo Community:

Ich habe in einem Userdefined Control mit Transparentem Hintergrund einen Drehgeber abgebildet,

mit:

        
       protected override void OnPaintBackground(PaintEventArgs e)
        {
            //base.OnPaintBackground(e);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x20; //WS_EX_TRANSPARENT
                return cp;
            }
        }

Wird das ganze auch wunderbar Transparent und man sieht im Hintergrund das Bauteil auf dem der Drehgeber sitzt, nun mache ich im OnPaint meine Ganzen Zeichnungen. Soweit so gut, solange der Drehgeber steht sieht das wunderbar aus,

Bei bewegung bleiben jedoch die alten linien erhalten.
Mein erster Gedanke war ein graphics.Clear(Color.Transparen) dadurch wird das ganze aber schwarz?!

Weiss jemand wie man ein Transparentes Control "Cleart" ?

mfg

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo Console32,

zeichne besser alles in einem Control (also Hintergrund + Vordergrund).
Dann ersparst du dir einiges an Ärger.

Ansonsten könnte an dem das Auskommentieren des Aufrufs von "base.OnPaintBackground" Schuld sein.

C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren
this.Invalidate(new Rectangle(this.rotaryEncoder1.Location, this.rotaryEncoder1.Size), true);

Dadurch wird das DrawBackground aufgerufen und man erhält wieder den Transparenten Hintergrund

Habs zuerst im OnPaint versucht:
this.Parrent.Invalidate(...)
Das endet in Flimmern da der GUI Thread nichts anderes mehr macht als das Control neu zu zeichnen.

mfg

EDIT: war gestern zu schnell wollte noch sagen das auf dem hintergrund zeichnen nicht so flexibel ist wie ein skalierendes UserControl, das ich mir nur aufs Bild ziehen muss.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Console32,

da Transparenz in Windows Forms nicht vollständig unterstützt wird und man z.B. durch ein transparentes Control nicht die dahinter liegenden Controls sieht, sondern nur den Hintergrund des Parents, ist der Vorschlag von winSharp93 letztlich wohl doch besser.

herbivore

C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren

Ich versteh nicht was du meinst ich seh die PicktureBox / Labels hinter meinem UserControl

Hier hab ichs gefunden:http://www.bobpowell.net/transcontrols.htm

Hinweis von herbivore vor 12 Jahren

Ich versteh nicht was du meinst

Du verstehst nicht, was ich meine, obwohl im ersten Absatz im Link genau das gleiche steht, was ich geschrieben habe?

The transparency feature of the Windows Forms control leaves much to be desired and is a blatant fudge. The control is not really transparent, it just pretends to be by looking at the background of it's parent control [...] This means that a "transparent" control placed on top of another on the same parent will in fact obscure the other child controls.

Zu Deutsch etwa: Die Transparenz-Fähigkeit der Windows Forms Controls lässt viele Wünsche offen und ist eine offenkundige Schummelei. Das Control ist nicht wirklich transparent, es täuscht nur vor, dass man auf den Hintergrund des Parent Controls schaut ... Das bedeutet, dass ein "transparentes" Control, das über einem anderen desselben Parent platziert wird, tatsächlich die anderen Kind-Controls verdeckt.

Also wirklich sehr genau, was ich auch geschrieben hatte. Aber wie dem auch sei ...

5.742 Beiträge seit 2007
vor 12 Jahren

Ich versteh nicht was du meinst ich seh die PicktureBox / Labels hinter meinem UserControl

So macht man es aber trotzdem nicht.

C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren

So macht man es aber trotzdem nicht.

Wenn ich noch verstehen darf warum, mach ich es gerne anderes. (Performance ist für mich kein Grund)

5.742 Beiträge seit 2007
vor 12 Jahren

Wenn ich noch verstehen darf warum, mach ich es gerne anderes.

Das Vorgehen passt einfach nicht zu dem, was Windows vorsieht:
Controls zeichnen sich (vereinfacht gesagt), wenn sie WM_PAINT erhalten. Dabei sorgt das Betriebssystem dafür, dass diese Nachricht automatisch gesendet wird, wenn z.B. verdeckte Bereiche des Fensters wieder sichtbar werden etc.
Dabei erfolgt das Zeichnen unmittelbar aufgrund der erhaltenen Nachricht und der Bereich, der tatsächlich neugezeichnet wird, wird auf eben diesen nun sichtbaren Bereich beschränkt.

Selbst auslösen kann man das Zeichnen (letztlich durch den Aufruf von Invalidate) beispielsweise, wenn sich der Inhalt komplett geändert hat.
Dann wird aber der gesamte Bereich des Controls neu gezeichnet.

Probiere mal testweise, den Interval des Timers ein wenig hochzsetzen (um die Effekte besser erkennen zu können), und platziere dein Control z.B. in einem scrollbaren Bereich und scrolle etwas herum.
Oder verschiebe das Fenster aus dem sichtbaren Bereich des Bildschirms heraus und wieder herein und beobachte, was passiert.

Ich bin sicher, die Transparenz sieht nicht so einwandfrei aus, wie sie aussehen könnte, wenn du es "richtig" machen würdest.

Kurzum: Es ist einfach unsauber, das gesamte Control jede halbe Sekunde komplett neu zu zeichnen, obwohl das eigentlich überhaupt nicht nötig ist.

C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren

Also mir ist klar das es nicht besonders sauber ist immer alles neu zu zeichnen, aber ich verstehe gerade nicht was sich daran ändern würde wenn ich meinen Hintergrund (Eine PiktureBox) und meinen Drehgeber in einem Control zeichnen würde,

sobald sich ein wert ändert muss ich den Bereich des Hintergrunds über den ich Zeichne erstmal neu zeichnen(damit die "veralteten" linien Verschwinden) und dann muss ich wieder meinen gesamten Drehgeber neu Zeichnen ? Oder habe ich was falsch verstanden?

EDIT:
Zum Skallieren etc / man merkt schon das Windows Forms nicht dafür gemacht ist, trotz Zeichnen in einem Buffer fängt das ganze relativ schnell zu flimmern an wenn man viele OnPaint aufrufe hat.

EDIT2:
Ich verwende keinen TickHandler so wie in dem Link oben sonder ich rufe das Invalidate selbst auf wenn sich werte geändert haben (Was durch Hardware auf 1-2 mal die Sekunde limitiert ist)

5.742 Beiträge seit 2007
vor 12 Jahren

Zum Skallieren etc / man merkt schon das Windows Forms nicht dafür gemacht ist, trotz Zeichnen in einem Buffer fängt das ganze relativ schnell zu flimmern an wenn man viele OnPaint aufrufe hat.

Wenn man es richtig macht, tritt dieser Fall allerdings erst recht spät ein.

sobald sich ein wert ändert muss ich den Bereich des Hintergrunds über den ich Zeichne erstmal neu zeichnen(damit die "veralteten" linien Verschwinden) und dann muss ich wieder meinen gesamten Drehgeber neu Zeichnen ?

Nein, es reicht in diesem Fall, nur die geänderten Bereiche neu zu zeichnen.
Zudem kann der DoubleBuffer dann auf die gesamte Zeichnung angewandt werden.

C
Console32 Themenstarter:in
258 Beiträge seit 2011
vor 12 Jahren

Nein, es reicht in diesem Fall, nur die geänderten Bereiche neu zu zeichnen.

Das muss ich aber selbst implementieren das er nur den Veränderten bereich neu zeichnet. Das könnte ich aber ebenfalls bei meinem Control machen oder nicht?

Wenn ich in meinem UserControl ein Rechteck berechne das mir den gänderten Bereich speichert Löse ich das Invalidate nur noch auf diesen Bereich aus?

Wenn man es richtig macht, tritt dieser Fall allerdings erst recht spät ein.

Richtig Buffern oder Richtig im Hintergrund zeichnen ?

5.742 Beiträge seit 2007
vor 12 Jahren

Richtig Buffern oder Richtig im Hintergrund zeichnen ?

Beides.

Aber wie gesagt: Mein Rat ist, es gleich richtig zu machen, da sich so viele Probleme erst gar nicht stellen.