Discussion:
Zeichnen in zur Laufzeit erstellter Picturebox
(zu alt für eine Antwort)
luzian
2006-03-21 10:51:29 UTC
Permalink
hallo

ich versuche mit klick auf einen button eine picturebox zu erstellen
und darin eine linie zu zeichnen und anzuzeigen. wenn ich das mache,
wird wohl die picturebox erstellt und angezeigt, aber die linie wird
nicht sichtbar- oder nur ganz kurz und verschwindet dann wieder.

parallel dazu habe ich nun zum testen eine picturebox schon auf der
form angelegt und zeichne gleichzeitig auch dahinein. dort bleibt der
strich sichtbar, in der anderen verschwindet er.

kann mir jemand helfen, ich sehe es einfach nicht? was muss ich machen,
damit ich den strich auch sehe?

besten dank
luzian

hier mein code, der bei klick auf den button ausgeführt wird.


Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click

Dim pb As PictureBox
Dim g As Graphics
pb = New PictureBox

pb.Height = 100
pb.Width = 100
pb.BorderStyle = BorderStyle.FixedSingle
pb.Location = New System.Drawing.Point(200, 10)

Register2.Controls.Add(pb)
pb.Visible = True

' Zeichnen auf vorhandener Picturebox
g = PictureBox1.CreateGraphics()
g.DrawLine(Pens.Black, 0, 0, 100, 100)
g.Dispose()

' Zeichnen auf erstellter Picturebox
g = pb.CreateGraphics()
g.DrawLine(Pens.Black, 0, 0, 100, 100)
g.Dispose()

End Sub
Armin Zingler
2006-03-21 11:14:50 UTC
Permalink
Post by luzian
ich versuche mit klick auf einen button eine picturebox zu erstellen
und darin eine linie zu zeichnen und anzuzeigen. wenn ich das mache,
wird wohl die picturebox erstellt und angezeigt, aber die linie wird
nicht sichtbar- oder nur ganz kurz und verschwindet dann wieder.
parallel dazu habe ich nun zum testen eine picturebox schon auf der
form angelegt und zeichne gleichzeitig auch dahinein. dort bleibt
der strich sichtbar, in der anderen verschwindet er.
kann mir jemand helfen, ich sehe es einfach nicht? was muss ich
machen, damit ich den strich auch sehe?
Du musst die Linie zeichnen, wenn dich Windows dazu auffordert. Das merkst
du dadurch dass das Paint-Ereignis der Picturebox ausgelöst wird. Um ein
Ereignis zu behandeln, füge eine Ereignisprozedur zum Ereignis hinzu. Das
geht mit der AddHandler-Anweisung.


Armin

P.S.: Hier ist es üblich, den vollständigen Namen einzutragen und die
Shift-Taste zu benutzen. Liest sich leichter. Nur als Info.
luzian
2006-03-21 14:16:09 UTC
Permalink
Hallo Armin,

vielen Dank für Deine Antwort, auch wenn ich nur ahne was ich machen
muss.
Ich glaube so ganz habe ich das nicht verstanden.

Ich kann also erst dann in meine, während der Laufzeit erstellten,
PictureBox zeichnen, wenn
Windows mir das erlaubt?

Was ist nun mein Ereignis und was muss meine Ereignisprozedur sein?

mit "AddHandler pb.Click, AddressOf ???" komme ich nicht wirklich
weiter. Und die Hilfe verstehe ich auch nicht wirklich.
Muss ich das Zeichnen also g.drawline ... usw. in eine
"Ereignisprozedur" auslagern und diese dann mit dem addHandler
aufrufen?

Danke für ein paar erleuchtende Worte.

Luzian
Stefan Simon
2006-03-21 14:55:44 UTC
Permalink
Post by luzian
Hallo Armin,
vielen Dank für Deine Antwort, auch wenn ich nur ahne was ich machen
muss.
Ich glaube so ganz habe ich das nicht verstanden.
Ich kann also erst dann in meine, während der Laufzeit erstellten,
PictureBox zeichnen, wenn
Windows mir das erlaubt?
So würde ich das nicht formulieren. Objektorientierte Programmierung lebt
nun mal von Ereignissen. (Tue was, wenn auf einen Button geklickt wird, tue
was, wenn die Mouse bewegt wird, male was, wenn sich die Oberfläche ändert
usw)
Du musst auch nicht auf das Ereignis warten, sondern kannst es selbst
auslösen (Invalidate, Invoke, Refresh, ...) Oder du lagerst das, was im
Eventhandler passieren soll, in eine Sub aus (siehe unten).
Post by luzian
Was ist nun mein Ereignis und was muss meine Ereignisprozedur sein?
mit "AddHandler pb.Click, AddressOf ???" komme ich nicht wirklich
weiter. Und die Hilfe verstehe ich auch nicht wirklich.
Muss ich das Zeichnen also g.drawline ... usw. in eine
"Ereignisprozedur" auslagern und diese dann mit dem addHandler
aufrufen?
Den Eventhandler gibst du einmal beim Erstellen des Objekts an. Solange es
lebt wird das angegebene Ereignis vom angegebenen Delagaten behandelt (Man
kann den Eventhandler natürlich auch wieder entfernen, wenns nötig ist).

Für dein Beispiel sähe das etwa so aus:

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim pb As PictureBox
Dim g As Graphics
pb = New PictureBox
AddHandler pb.Paint, AddressOf pb_Paint

pb.Height = 100
pb.Width = 100
pb.BorderStyle = BorderStyle.FixedSingle
pb.Location = New System.Drawing.Point(200, 10)

Register2.Controls.Add(pb)
pb.Visible = True

' Zeichnen auf vorhandener Picturebox
g = PictureBox1.CreateGraphics()
g.DrawLine(Pens.Black, 0, 0, 100, 100)
g.Dispose()

' Zeichnen auf erstellter Picturebox
' g = pb.CreateGraphics
' MalePB(g)
' g.dispose
End Sub

Private Sub pb_Paint(ByVal sender As Object, ByVal e As PaintEventArgs)
' Zeichnen auf erstellter Picturebox
MalePB(g)
End Sub

private sub MalePB(byval g as Graphics)
e.Graphics.DrawLine(Pens.Black, 0, 0, 100, 100)
end sub


Stefan
Armin Zingler
2006-03-21 14:59:45 UTC
Permalink
Post by luzian
Hallo Armin,
vielen Dank für Deine Antwort, auch wenn ich nur ahne was ich machen
muss.
Ich glaube so ganz habe ich das nicht verstanden.
Ich kann also erst dann in meine, während der Laufzeit erstellten,
PictureBox zeichnen, wenn
Windows mir das erlaubt?
Nein, nicht erlaubt, sondern dich dazu auffordert. Zumindest dann musst du
zeichnen. Es ist aber auch zu jedem anderen beliebigen Zeitpunkt möglich -
sofern das Control sichtbar ist, sonst wär's a bisserl unsinnig.
Post by luzian
Was ist nun mein Ereignis
Das Paint-Ereignis der Picturebox.
Post by luzian
und was muss meine Ereignisprozedur sein?
Die musst du schreiben. Sieht dann z.B. so aus:

Private Sub OnPictureBoxPaint( _
ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs)

End Sub
Post by luzian
mit "AddHandler pb.Click, AddressOf ???"
AddHandler pb.Paint, AddressOf OnPictureBoxPaint
Post by luzian
komme ich nicht wirklich
weiter. Und die Hilfe verstehe ich auch nicht wirklich.
Muss ich das Zeichnen also g.drawline ... usw. in eine
"Ereignisprozedur" auslagern
Ja.

Konkret:

e.graphics.DrawLine ...
Post by luzian
und diese dann mit dem addHandler
aufrufen?
Mit Addhandler fügst du einen Ereignishandler zu einem Ereignis hinzu. Das
hat zur Folge, dass der Ereignishandler aufgerufen wird, wenn das Objekt das
Ereignis auslöst.

Wenn du mit Addhandler, wie oben gezeigt, die Prozedur OnPictureboxPaint zum
Paint-Ereignis hinzugefügt hast, bedeutet das, dass diese Prozedur
aufgerufen wird, wenn das Paint-Ereignis auftritt.

Ein Ereignis ist somit nichts weiter als der Aufruf der Prozeduren, die sich
für das Ereignis in eine Liste eingetragen haben. Das Hinzufügen zu der
Liste geschieht eben mit Addhandler. Das Entfernen mit RemoveHandler.
Post by luzian
Danke für ein paar erleuchtende Worte.
Bitte.


Armin
Karsten Sosna
2006-03-21 15:12:09 UTC
Permalink
vielen Dank für Deine Antwort, auch wenn ich nur ahne was ich machen
muss.
Ich glaube so ganz habe ich das nicht verstanden.

Ich kann also erst dann in meine, während der Laufzeit erstellten,
PictureBox zeichnen, wenn
Windows mir das erlaubt?

Was ist nun mein Ereignis und was muss meine Ereignisprozedur sein?

mit "AddHandler pb.Click, AddressOf ???" komme ich nicht wirklich
weiter. Und die Hilfe verstehe ich auch nicht wirklich.
Muss ich das Zeichnen also g.drawline ... usw. in eine
"Ereignisprozedur" auslagern und diese dann mit dem addHandler
aufrufen?

========
Erstens stelle bitte Deinen vollen Namen ein, Danke.

Zweitens: "Erlaubt" ist der falsche Begriff, Windows teilt Dir mit, wann Du
Teile neu zeichnen solltest.
Hier als Beispiel
\\\
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim PB As New PictureBox
PB.Size = New Size(100, 100)
AddHandler PB.Paint, AddressOf PB_Paint
Me.Controls.Add(PB)
End Sub

Private Sub PB_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs)
e.Graphics.DrawLine(Pens.Blue, 0, 0, 100, 100)
End Sub
///
Da neu erstellte Controls noch keine Ereignis-Handler besitzen musst Du
diese hinzufügen(AddHandler). AddressOf ist dann der Delegate der weiss
welche Prozedur bei welchen Event aufgerufen werden.
Hier also, wenn PB.Paint ausgelöst wird rufe bitte PB_Paint auf.
PB.Paint wird immer dann ausgelöst, wenn in diesem Fall Teile(siehe
e.ClipRectangle) der PictureBox neugezeichnet werden sollten.
--
Gruß Scotty
Luzian Jatsch
2006-03-21 15:35:58 UTC
Permalink
Danke Armin, Danke Scotty

ich denke jetzt habe ich es verstanden. Bisher habe ich meine
Anwendungen in Delphi programmiert und habe leichtsinnigerweise gedacht
ich versuch es mal mit Visual Basic 2005.
Na ich werde noch hinter die Feinheiten steigen, aber Euch erst mal
vielen Dank.

Ich hoffe das mit dem Namen habe ich nun an der richtigen Stelle
angepasst.

Gruss Luzian
Karsten Sosna
2006-03-21 15:45:35 UTC
Permalink
Post by Luzian Jatsch
ich denke jetzt habe ich es verstanden. Bisher habe ich meine
Anwendungen in Delphi programmiert und habe leichtsinnigerweise gedacht
ich versuch es mal mit Visual Basic 2005.
VB.Net ist doch schön. ;=)
Post by Luzian Jatsch
Na ich werde noch hinter die Feinheiten steigen, aber Euch erst mal
vielen Dank.
Es ist noch kein Meister vom Himmel gefallen.
Post by Luzian Jatsch
Ich hoffe das mit dem Namen habe ich nun an der richtigen Stelle
angepasst.
Ja, Danke. Auch die Quotes passen jetzt.
--
Gruß Scotty
Luzian Jatsch
2006-03-22 12:05:18 UTC
Permalink
Ich bin doch noch mal da,

ich möchte nun nicht eine PictureBox mit einer Linie erstellen,
sondern eine erst während der Laufzeit festgelegte Anzahl Pictureboxen
mit je einer Linie.
Legen wir diese mal für den Moment auf 20 fest.

Ich definiere nun:

Dim pb(20) As PictureBox

und kann diese auch schön auf der Form nebeneinander positionieren.
Nun muss ich wieder die Prozedur zum Zeichnen der Linie aufrufen.

AddHandler PB(i).Paint, AddressOf PB_Paint

In der Routine PB_Paint steht ja momentan nur der e.Graphic.DrawLine
Befehl mit fixen Parametern. Wie bekomme ich es nun hin, dass ich für
jeder der 20 Boxen eine andere Linie zeichnen kann?

Die Idee war die PB_Paint Routine aus dem AddHandler mit Parametern
für die Koordinaten aufzurufen. Die Parameter liessen sich in der
Routine auch problemlos definieren, aber aufrufen konnte ich sie nicht.
Als Fehler kam dort immer "Der Parameter e muss übergeben werden". Was
ich da auch reinschrieb, er wollte es nicht.

Habt Ihr ne Idee?

Vielleicht bin ich ja ganz und gar auf dem Holzweg.
Eigentlich möchte ich nur Linien (oder Balken in Form von Rechtecken)
nebeneinander darstellen. Die Anzahl der Linien und die Höhe ist
variabel. Nun möchte ich aber mit ToolTip noch individuelle Texte je
Linie anzeigen, wenn man mit der Maus darüber fährt. Ich war leider
nicht in der Lage einer Linie ein Tooltip zuzuweisen und wollte nun
halt für jede Linie eine PaintBox erstellen, der ich den ToolTip
zuweisen kann.

Nochmal Danke für Euren Input
Luzian
Stefan Simon
2006-03-22 15:10:48 UTC
Permalink
Post by Luzian Jatsch
ich möchte nun nicht eine PictureBox mit einer Linie erstellen,
sondern eine erst während der Laufzeit festgelegte Anzahl Pictureboxen
mit je einer Linie.
Wie bekomme ich es nun hin, dass ich für
jeder der 20 Boxen eine andere Linie zeichnen kann?
Die Idee war die PB_Paint Routine aus dem AddHandler mit Parametern
für die Koordinaten aufzurufen.
Du kannst natürlich von PaintEventArgs erben und deine Parameter dazutun,
aber das ist nicht wirklich nötig, schätze ich.

Du kannst entweder eine Struktur mitführen, in der du alles nötige
speicherst:

Private Structure Box
Friend LineFrom As Point
Friend LineTo As Point
End Structure

Private lst(3) As Box
Private Const pb_Width As Integer = 20
Private Const pb_Height As Integer = 20
Private TT As New ToolTip

und füllst es entsprechend:

For i As Integer = 0 To lst.Length - 1
With lst(i)
Dim pb As New PictureBox
pb.Tag = i
pb.Location = New Point(i * pb_Width + 10, 10)
pb.Size = New Size(pb_Width, pb_Height)
.LineFrom = New Point(pb_Width \ (i + 1) * 2, 0)
.LineTo = New Point(pb_Width - pb_Width \ (i + 1) * 2 _
, pb_Height)
TT.SetToolTip(pb, "Line " & i)
Me.Controls.Add(pb)
AddHandler pb.Paint, AddressOf PB_Paint
End With
Next


Im Paint-Handler kuckst du nach dem Sender und in der Liste nach den
entsprechenden Koordinaten.

Dim pb As Box = lst(CInt(CType(sender, PictureBox).Tag))
e.Graphics.DrawLine(Drawing.SystemPens.WindowText, pb.LineTo, _
pb.LineFrom)


Am cleversten löst du dein Problem jedoch mit einem eigenen Steuerelement.

Public Class MyBox
Inherits PictureBox

Private pLineFrom As New Point(0, 0)
Private pLineTo As New Point(0, 0)

Friend Property LineFrom() As Point
Get
Return pLineFrom
End Get
Set(ByVal value As Point)
If Not IsNothing(value) Then
pLineFrom = value
End If
End Set
End Property

Friend Property LineTo() As Point
Get
Return pLineTo
End Get
Set(ByVal value As Point)
If Not IsNothing(value) Then
pLineTo = value
End If
End Set
End Property

Public Event p(ByVal sender As Object, ByVal e As PaintEventArgs)

Protected Overrides ReadOnly Property DefaultSize() As
System.Drawing.Size
Get
Return New Size(20, 20)
End Get
End Property

Protected Overrides Sub OnPaint(ByVal pe As
System.Windows.Forms.PaintEventArgs)
pe.Graphics.DrawLine(Drawing.SystemPens.WindowText, Me.pLineTo,
Me.pLineFrom)
End Sub
End Class

Deine Initalisierung sieht etwas aufgeräumter aus und du brauchst keinen
Eventhandler mehr.

For i As Integer = 0 To 19
Dim pb As New MyBox
pb.Location = New Point(i * pb.Width + 10, 10)
pb.LineFrom = New Point(pb.Width \ 2, 0)
pb.LineTo = New Point(pb.Width \ 2, pb.Height \ (i + 1))
TT.SetToolTip(pb, "Line " & i)
Me.Controls.Add(pb)
Next


Stefan
Luzian Jatsch
2006-03-22 15:23:14 UTC
Permalink
Hallo Stefan

wie macht Ihr das nur immer? Echt super.
Danke für Deine Antwort, der Code funktioniert jetzt gehe ich da mal
langsam durch und versuche es zu verstehen.

Luzian
Luzian Jatsch
2006-03-22 15:23:48 UTC
Permalink
Hallo Stefan

wie macht Ihr das nur immer? Echt super.
Danke für Deine Antwort, der Code funktioniert jetzt gehe ich da mal
langsam durch und versuche es zu verstehen.

Luzian

Loading...