Grafische Elemente zeichnen auf unendliche Zeichenfläche

  • VB.NET

Es gibt 49 Antworten in diesem Thema. Der letzte Beitrag () ist von FlyingEagle.

    FlyingEagle schrieb:

    dann deaktiviert bitte
    Das ist nicht erforderlich, da man dieses Feature sehr gut dezent einsetzen kann.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Rofl!

    FlyingEagle schrieb:

    eigentlich will ich ja gar nicht so viel...
    und dann kommen 16 Punkte - you made my day :D
    /offtopic
    so, und nu guck ich mal rein

    Edit: Und bitte keine Executables in angehängten zips
    Vorm zippen den bin - Ordner rauswerfen.

    Auch scheinst du VB2012 zu nutzen? Ich bin neulich auf 2013Community-Edition umgestiegen, die ist auch umsonst, aber deutlich besser, auch was das Debuggen angeht.

    guck - sowas ist stuss:

    VB.NET-Quellcode

    1. Private m_colObjects As ObservableCollection(Of clsDrawingObject)
    2. Public Sub New()
    3. If m_colObjects Is Nothing Then
    4. m_colObjects = New ObservableCollection(Of clsDrawingObject)
    5. End If
    6. '...
    In Sub new brauchst du nicht auf Nothing zu testen - es ist ganz sicher, dasses da Nothing ist.

    Aber vb hat nette Initialisierungs-Möglichkeiten, da brauchste die Collection im Konstruktor gar nicht erneut aufzugreifen:

    VB.NET-Quellcode

    1. Private m_colObjects As New ObservableCollection(Of clsDrawingObject)
    2. Public Sub New()
    3. '... (alles bereits erledigt)

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    und dann kommen 16 Punkte - you made my day


    stets gern zu diensten

    ErfinderDesRades schrieb:

    Auch scheinst du VB2012 zu nutzen?


    VB2010 Ultimate ... keine knöppe für 2013 :)

    ErfinderDesRades schrieb:

    '... (alles bereits erledigt)


    ja, so kann man das auch machen, aber das alleine ist kein grund für die performance, oder?
    ich habe es irgendwie immer gern wenn alles brav initialisiert ist etc. mag sein, dass man das bei der deklaration mit angeben kann, aber so falsch ist mein weg auch nicht - oder?

    viel blöder finde ich so geschichten wie

    VB.NET-Quellcode

    1. if klasseoderobjekt is nothing then
    2. if klasseoderobjekt.subobjektodersowas is nothing then
    3. ...

    warum kann man nicht so fragen

    VB.NET-Quellcode

    1. if klasseoderobjekt.subobjektodersowas is nothing then
    2. ...

    letzteres wirft ne exception.

    aber danke das du mir hilfst!

    FlyingEagle schrieb:

    VB.NET-Quellcode

    1. if klasseoderobjekt.subobjektodersowas is nothing then
    Instanz in der Instanz.
    Das geht der Reihe nach:

    VB.NET-Quellcode

    1. if klasseoderobjekt IsNot Nothing AndAlso klasseoderobjekt.subobjektodersowas isNot nothing then
    2. ' auf klasseoderobjekt.subobjektodersowas zugreifen
    3. End If
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    hab 2 schwere Bugs gefunden
    1. mit Properties musste bei eigenen Controls aufpassen - da will der Designer immer was persistieren, und das hat bei eigenen DrawObjekten keinen Sinn und führt sogar in korrupte Resourcen, und dann ist das ganze Form im Eimer.
      Um den Designer dran zu hindern, musste alle DrawPanel-Properties wie folgt attributieren:

      VB.NET-Quellcode

      1. Private m_DragObjects As New ObservableCollection(Of clsDrawingObject)
      2. <Browsable(False), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
      3. Public ReadOnly Property DragObjects() As ObservableCollection(Of clsDrawingObject)
      4. Get
      5. Return m_DragObjects
      6. End Get
      7. End Property

    2. Sowas geht nicht:

      VB.NET-Quellcode

      1. Private Sub clsDrawingPanel_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
      2. Using g = e.Graphics
      3. If Not bufferImage Is Nothing Then
      4. g.DrawImage(bufferImage, 0, 0)
      5. Else
      6. RealPaint()
      7. End If
      8. End Using
      9. End Sub
      Disposen darfst du nur Objekte, die danach nicht mehr benötigt werden. Also nur Objekte, die du dir selbst erstellt oder generiert hast.
      Hier aber bekommst du von irgendwoher ein Graphics - ja das kannst du doch nachdem du es benutzt hast nicht unbrauchbar machen!
    3. Nachdem diese Hürde genommen, kannst du auch machen, wie du eh vorhattest:

      VB.NET-Quellcode

      1. Public Sub New()
      2. Me.DoubleBuffered = True
      und das Geflacker ist weg :D
      Naja, nun ists ein bischen zäh, aber glaub v.a. wegen der vielen Debug-Ausgaben während des Zeichnens
    anbei mal mein Stand
    Dateien
    • PaintTest01.zip

      (24,19 kB, 88 mal heruntergeladen, zuletzt: )
    1. ah ok, werde ich mir merken
    2. ups :) jetzt wird mir auch so einiges klar
    3. sehr gut.

    schön, das es nun nicht mehr so flackert, aber die performance für - eigentlich - so wenig zeugs ist schon hammer mies.
    werde mal die debugs rauswerfen, die ich auch nur drin habe um zu sehen was er wie oft aufruft - und dann mal release ohne vs testen ...

    dafür das ich nen i7 mit 4gb ram habe ist die leistung echt fies ;)

    danke Erfinder bis hierher!!

    Rod:

    ich werde es mal so zukünftig verwenden.
    verstehen bzw nachvollziehen kann ich das so aber nicht. immer müsste ja klasseoderobjekt.subobjektodersowas von haus aus nothing sein wenn klasseoderobjekt bereits nothing ist ...
    naja, deine Architektur besteht zwar prinzipiell, aber du machst da noch haufenweise komisches Zeugs.
    etwa dieses Gemurkel mittm bufferedImage - was soll das?
    Image ist übrigens echt 'ne fette Resource.

    Und für die Kringel haste zwar DrawObjects angelegt, aber die rechnen ihre Bounds erst im Painting aus, das ist glaub nicht Sinn der Sache.
    Ein DrawObject muss seine Abmasse jederzeit angeben können, und wenn es sich drawt, dann innerhalb dieser Abmasse.
    Nur dann kann man gezielt invalidieren, also das Neuzeichnen so veranlassen, dass nur die Stelle auffm DrawPanel geneuzeichnet wird, wo auch eine Veränderung stattgefunden hat.
    Du invalidierst ja immer das ganz Panel - das ist natürlich was anneres als flott.
    Und für die Linien brauchst du auch DrawObjekte (die sich halt ganz anners zeichnen) - also du solltest die Architektur konsequent anwenden, und nicht son Mischmasch.
    ja ich gebe zu, da is ne menge im argen, aber vieles davon ist vom ausprobieren ...
    ja das mit dem bufferedimage ist so ein überbleibsel aus der ära "ich versuche das mal damit" ;)
    erkläre hiermit die ära als beendet :-)
    und es funktioniert immer noch wie vorher, nen super performancesprung kann ich aber nicht feststellen ... klar, am ende wirds die summe machen.

    würde es sinn machen die "kringel" und die linien in nen graphicspath zu schieben und den dann zum gezielten invalidieren zu nehmen?

    was genau meinst du genau mit "architektur konsequent anwenden?

    das mit den linien hab ich mir auch schon überlegt, fand aber zum zeitpunkt der überlegung, dass es evtl mehr ressourcen - im sinne von performance - benötigt die via klasse/for etc erst rauszufischen vorm zeichnen.

    danke & grüße

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „FlyingEagle“ ()

    FlyingEagle schrieb:

    würde es sinn machen die "kringel" und die linien in nen graphicspath zu schieben und den dann zum gezielten invalidieren zu nehmen?
    Jo, das ist bei mir auch architektur-Prinzip: Figuren werden in GraphicsPathes niedergelegt, und das Painten ist letztendlich immer nur eine (performante) Zeile: e.Graphics.DrawPath(blalba).

    FlyingEagle schrieb:

    was genau meinst du genau mit "architektur konsequent anwenden?
    Guck nochmal die StoryCards-Architektur:
    Es gibt ein MustInherit DrawObject, was grundlegende Funktionalität bereitstellt: Zeichenbereich festlegen, ob selectiert ist, und drawen halt.
    Das alles erbt die StoryCard, die dem nur noch einen Text zufügen muss, und eben wie sie sich selber zeichnet.
    Weitere Klassen könnten ebenfalls von DrawObject erben, anderes hinzufügen, und sich anders zeichnen.
    Im DrawPanel ist das Paint dann mit einer einzigen Schleife abgehandelt:

    VB.NET-Quellcode

    1. For Each DrgO As DrawObject In _DragObjects
    2. DrgO.Draw(e)
    3. Next
    Prinzipiell ist damit jede Art von OwnerDrawing abgedeckt - egal was kommt: von DrawObject erben, zusätzliche Eigenschaften zufügen, und die Draw-Methode überschreiben, damit das Ding weiss, wie es sich zeichnen soll.
    Das mit linien "rausfischen vorm Zeichnen" ist vor diesem Hintergrund unverständlich: Die Linien musste nicht rausfischen und zeichnen - die zeichnen sich doch selber. Das sind doch DrawObjects wie alle anneren auch, eben von DrawObject geerbt!

    Wobei die StoryCards - Architektur zwar ganz i.O. ist, aber die DrawObject-Klasse kann man auch anners konzipieren, ich hab auch mal mit DrawObjects gearbeitet, die gleich von vornherein einen GraphicsPath bereitstellten, wo ein Erbe nur noch sein "Figur" einspeisen musste.

    Aber es bleibt immer so, dasses auch auf die konkreten Anforderungen ankommt: Auch hatte ich DrawObjekte, die mehrere Farben enthielten, die kamen dann mit einem GraphicsPath nicht mehr aus, und bekamen halt eine Liste davon.
    Und so kann mans immer weiter treiben in dem Versuch die eierlegende Wollmilchsau-Architektur zu erfinden.

    Aber das Grundprinzip: DrawPanel - DrawObject - DrawObject-Erben
    Das würde ich als Architektur-Pattern unbedingt beibehalten.

    ErfinderDesRades schrieb:

    Aber das Grundprinzip: DrawPanel - DrawObject - DrawObject-Erben
    Das würde ich als Architektur-Pattern unbedingt beibehalten.


    jouh, das habe und hatte ich ja ... mache das schon länger auch bei vielen anderen dingen so, zumal schon aus rein pragmatischen gründen, weil man so lecker ne list-of erstellen kann ...

    na ich meinte mit den linien eher, da wären ja auch wieder sprünge in die klasse, zu den properties etc innerhalb der linien-drawobjekt-child-klasse notwendig, so ist bisher nur ein sprung in ne routine. und die for-schleife in paint wäre länger.

    zuerst will ich aber mal sehen das ich dieses komische gespringe des kreises beim klicken und ziehen wegkriege. irgendwie muss ich mir da noch nen offset zum mauszeiger ausknobeln. genau wie nur-klicken, da muss ne schwelle rein, dass er erst dragged wenn bestimmte pixel-anzahl gezogen wurde.
    wo ich auch noch ein bischen hänge ist bei der vorberechnung der größen etc. mal gucken wie ich das hinkriege, weil allen gemein ist nunmal paint, so muss man immer bei jeder property-ändernug, die auswirkungen auf die größen hat diese neu berechnen ... und das geht ja bei location los und hört bei größe oder textänderungen auf ...
    in meinen DrawObjects hab ich oft auch eine Methode ApplyChanges, wo derlei Berechnungen zusammengefasst sind.

    Also angenommen eine verschieb - und drehbare Bildbeschriftung, die muss bei allen möglichen Veränderungen neu ausgerechnet werden: beim Selectieren, Unselectieren, Verschieben, Drehen, Größer-Ziehen, Ändern des Textes, Schriftfarbe, etc..

    Da mach ich kein groß Heckmeck mit Berücksichtigung aller Auswirkungen einer Änderung auf andere, und auf wieder andere nicht, sondern
    1. Die aktuellen Bounds invalidieren
    2. Eigenschaften ändern, evtl. auch mehrere auf ein Rutsch
    3. ApplyChanges rechnet das neue Aussehen komplett neu aus - inklusive Bounds
    4. diese neuen Bounds auch invalidieren
    5. jo, fertig - ein Paint-Event wird auf dem Fuße folgen, aber dafür simmerja nun genau gerüstet :D
    ja so in der art dachte ich mir das.

    bin halt bei sowas immer am grübeln bzw abwägen, auch wenn die klassen für einen selbst sind, so möchte man später nicht 1001 propertie oder methode aufrufen um zum ziel zu gelangen, sondern nur 1 oder 2 oder so je nach zweck.
    ich versuche daher immer möglichst viel zu automatisieren, daher kommt es häufiger zum maus beißt schwanz problem :P

    so wie ich das grad sehe, werde ich wohl noch ne zwischenklassen einbauen (müssen), die z.b. die grundformen für "echte" zeichenobjekte (rechteckig gedacht ;-)) bereitstellt, während die linien ja mehr punkte als alles andere haben. muss da noch mal in mich gehen. blöd wirds nur wenn dort keiner ist gerade.
    graphicspath ist immer gut. Nur Region würd ich nicht einsetzen, weil das verkomplizierts, wenn die beschrifteten Kringel ihre Bounds als Rechteck angeben, die Linien aber als Region.
    Mach die Linien in einen GP, von dem kannste die Bounds direkt abrufen.

    Theoretisch ist eine Region zu invalidieren ja effizienter, weil da ja eine viel kleinere Fläche einzugrenzen ist.
    Praktisch bringt das glaub nix, weil das Paint-Event Clipt nunmal keine Regions, sondern es clipt Rectangles.

    Ich find übrigens, du kommst ungewöhnlich gut klar mit dem Kram - hast du schon die Matrix-Klasse gefunden?
    Dann kannste ja auch mal probieren, dir dieses Werk von mir zuzumuten: activevb.de/cgi-bin/tippupload…beweglicher_Figur_darstel
    (und bei Bedarf kann ich dich auch noch mit noch weitergehenden Übungen versorgen, allerdings c#)
    Wie genau läuft es denn von der Architektur her bei dir ab? Vielleicht könnte man da ansetzen und versuchen, diese zu "optimieren".
    Hab den Download übersehen - werde es mir mal genauer ansehen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nafets“ ()

    Ok, das sieht üppig aus. Ich versuche mal schnell, das Teil neu zu schreiben, um ein Gefühl dafür zu bekommen, wo das Problem ist. Bei deiner aktuellen Architektur blicke ich nämlich leider nicht wirklich durch.
    im wesentlichen sollen es zwei spalten geben, drag&drop von re nach li oder li nach re, hover und gedöns is luxus.
    beide punkte per geschmeidiger linie verbinden.
    das is im wesentlichen alles :D

    später will ich den einzelnen elementen noch daten aus ner db mitgeben.
    will nen grafischen editor um verbindungen zu visualisieren.

    da fällt mir was ein, falls einer noch ne gute idee hat, wie man es vermeiden kann, beim zeichnen der linien, das sich diese in einem gemeinsamen mittelpunkt treffen. dazu einfach mal li oben nach re unten und so weiter verbinden. hat aber mit dem ursprünglichen nix zu tun ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „FlyingEagle“ ()