Mouse / bMaus - Events

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von -Franky-.

    Mouse / bMaus - Events

    Für die Maus als das wichtigste Gerät für die User-Interaktion finde ich hier nur wenige Infos.

    Da die Maus in interschiedlichsten Situationen verwendet wird, trenne ich diese durch einen "Maus-Status", der dann bei den Event-Behandungen per Select Case getrennt behandelt wird. Insbesondere habe ich Probleme mit dem Mouse_Move-Event. Hier verwende ich lieber einen Timer, der die Verarbeitung (per Flag) übernimmt.
    Gibt es hier andere / bessere Vorschläge?

    Thema verschoben; Das Thema wird automatisch dort erstellt, wo man sich befindet, wenn man auf [* Neues Thema] klickt. ~VaporiZed

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

    Kannst Du bitte für Spätaufsteher wie mich mit einfacheren Formulierungen sagen, was Dein Problem/momentaner Weg/Ziel ist? Ich blick's nicht.
    Was genau legst Du mit Flags und nem Timer fest? Nenn mal bitte ein konkretes Beispiel.

    btw:

    koning3 schrieb:

    die Maus als das wichtigste Gerät für die User-Interaktion
    Da würd ich ja als Gesundseher eher den Monitor als wichtigstes Gerät bewerten, aber das ist nebensächlich …
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @koning3 Was passiert denn so in Deinem Timer-Tick-Event, was bei Dir nicht im Mouse-Move-Event steht?
    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!
    Ich habe eigentlich kein Problem, eher eine Lösung, von der ich nicht sicher bin, ob man das professionell nicht besser machen kann.

    Beispiel (grob skizziert): Um eine gezeichnete Struktur, die aus relativ vielen Einzelelementen besteht (Linien, Polygone, Ellipsen, etc) innerhalb einer Picturebox zu verschieben, könnte ich den MouseMove-Event zum Neuzeichnen nutzen. Da das Neuzeichnen auf einem unveränderten strukturierten Hintergrund recht zeitaufwändig ist und das Event beim Verschieben viel zu oft ausgelöst wird, ist die Anwendung schnell "ausgelastet". Nichts geht mehr.
    Um das zu vermeiden, verwende ich eine globale Variable(point), die vom MouseMove-Event ständig mit der Position der Maus versorgt wird. Mehr macht MouseMove nicht.
    Ein Timer-Tick (ca 50-100 msec) zeichnet nun unter Verwendung dieser globalen Variable die Struktur neu, solange das Flag "MouseDown" gesetzt ist.

    Kann man das "eleganter" machen? Wie ginge das ohne die globale Variable?
    Sowas ginge aber auch mit MouseMove. Leider erstmal auch mit klassenweiten Variablen. (Static lassen wir mal raus ;) )
    Im Timer_Tick-EventHandler das Zeichnen-Flag auf True setzen, im MouseMove-EventHandler dann:

    VB.NET-Quellcode

    1. Private Sub PicBox_MouseMove(sender As Object, e As MouseEventArgs) Handles PicBox.MouseMove
    2. If Not Zeichnen OrElse Not e.Button.HasFlag(MouseButtons.Left) Then Return
    3. Zeichnen = False
    4. PicBox.Invalidate()
    5. End Sub

    sollte reichen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Na klar, habe ich ja - in etwa - auch so gemacht.

    Aber der Event wird ja bei der geringsten Maus-Bewegung ausgelöst. Es wird da sicher eine interne Queue für die Abarbeitung der Events geben. Die ist - offensichtlich - schnell verstopft, daher die Timer-Lösung. Die Zwischenstände sind ja auch völlig unwichtig. Ob man nun die anstehende Verarbeitung im "geflaggten" MouseMove-Eventhandling oder im auslösenden Timer-Tick selbst macht, ist letztlich egal

    Es gibt eine ähnliche Problematik (Off-Topic, ich weiß) bei den Scroll-Events. Auch hier muss eine "angemessene" Zeitspanne für die User-Interaktion eingeplant werden, damit die Event-Verarbeitung nicht sofort beginnt, sondern erst den (mutmaßlichen) Endwert verwendet.

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

    koning3 schrieb:

    Aber der Event wird ja bei der geringsten Maus-Bewegung ausgelöst.
    Das Event wird immer gefeuert, wenn die Maus über das Control geht. Da musss noch nicht mal Code in Deinem Projekt drinstehen. Aber das ist vollkommen leistungswurscht. Selbst das Eventfeuerhören durch einen EventHandler ist leistungswurscht. Das Neuzeichnen der PicBox-Inhalte ist nicht leistungswurscht. Aber das geschieht ja nur so oft, wie es im Timer eingestellt ist. Danach wird einmal neu gezeichnet und dann wird das Neuzeichnen durch meinen Codeschnipsel verhindert, bis der Timer wieder tickt.
    Wenn Du Dir die MessageQueue anschauen würdest, würdest Du Herzflattern kriegen. Selbst bei einem leeren Form werden hunderte Events innerhalb weniger Sekunden abgefeuert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Da hast Du sicher recht.

    Aber umsomehr möchte ich da keine große Verarbeitung dranhängen.
    Daher das Timer-Konstrukt, das nur zu vernünftigen Zeiten arbeitet.

    Für Deine Lösung würde sprechen, dass keine Verarbeitung stattfindet wenn die Maus unbewegt ist - während der Timer weiterläuft.
    Allerdings wird der Timer bei MouseUp sowieso wieder gestoppt.

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

    koning3 schrieb:

    die aus relativ vielen Einzelelementen besteht (Linien, Polygone, Ellipsen, etc)
    Sieh Dir mal die Klasse GraphicsPath an:
    docs.microsoft.com/de-de/dotne…?view=dotnet-plat-ext-6.0
    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!
    Die Timer Lösung hier ist absoluter Käse… MouseMove Event in Kombination mit MouseDown oder ähnlichem ist hier der saubere Weg.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    @RodFromGermany:
    Die Grafikklasse sieht interessant aus und man kann sie sicher gut zum Zeichnen komplexer Strukturen benutzen.
    Meine Grafiken sind temporäre Projektionen eines 3D-Raummodells, d.h. die Struktur ändert sich beim Verschieben durch die Änderung der Perspektive. Wobei ich aus der Mausposition mittels weiterer Informationen die Position eines Raumpunkts ermittele, den ich im Raum mit dem gesamten Modell verschiebe. Funktioniert einwandfrei und mit erstaunlich guter Performance.

    Trotzdem danke für den Tipp. Es ist immer gut mehr Lösungen als Probleme zu haben.

    Ich hänge mal einen Screenshot von dem betreffenden Projekt an.
    Bilder
    • Screen_Grafik06.jpg

      488,56 kB, 2.736×1.824, 64 mal angesehen

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

    @koning3 Um Dir effektiv helfen zu können, müsstest Du schon mal etwas Code zeigen.
    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!
    @RodFromGermany
    Ich könnte natürlich meinen Code zeigen, aber dann reiben wir uns nur wieder daran, dass ich nicht NET/OOP-konform programmiere.

    Ich habe mir völlig eigenständig und autodidaktisch eine Lösung konstruiert - wobei mir die inzwischen 5 Bücher zu VB wenig helfen konnten - die funktioniert. Da der Umgang mit Mouse-Events aber eigentlich Standard-Aufgaben sind, dachte ich hier im Forum noch etwas besseres und effizienteres zu finden. Allein schon für das MouseDown gibt es in größeren Programmen eine Vielzahl von Funktionen, die sauber voneinander getrennt werden müssen.

    Wie geht ihr denn mit den Mouse-Events um?

    koning3 schrieb:

    aber dann reiben wir uns nur wieder daran, dass ich nicht NET/OOP-konform programmiere.

    koning3 schrieb:

    Wie geht ihr denn mit den Mouse-Events um?
    NET/OOP-konform.
    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!
    Ok, bei dem Screenshot bin ich hilfstechnisch raus. Um da Flüssigkeit reinzukriegen, ist wohl z.B. DirectX gefragt. Aber das übersteigt meinen Kenntnissstand im Zusammenhang mit VB.NET. Da hatte @-Franky- schon mal was angefangen zu erklären/Tutorials zu machen.
    Großen Respekt, dass Du Dir, @koning3, dieses Ergebnis selber zusammenbasteln konntest. Dass das die Framerate in den Keller geht, wenn bei jeden MouseMoveEventfeuern alles gezeichnet wird, kann ich nachvollziehen. Und ja, ich sehe Deinen Einsatz eines Timers als gute Lösungsmöglichkeit.
    Da wär ich allerdings schon auch interessiert, mit welchen Code Du solche Strukturen zeichnest. Das dürfte ggf. etwas exzessiv sein.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hi

    Wow, Hut ab @koning3. Im Prinzip hast Du Dir da eine eigene 3D-Engine geschrieben. Wenn was per DirectX geht, dann evtl. per Direct3D. Damit hab ich mich aber bisher noch nicht Beschäftigt. Mit Direct2D könnte man experimentieren ob da was machbar ist. Denke aber das dann Dein Code zum zeichnen komplett neu geschrieben werden müsste. Bei dem Fortschritt den Du da schon hast, würde ich das so lassen wie es ist.

    Die Timer-Idee ist gar nicht so verkehrt. Sobald ein MouseMove (und MouseDown) registriert wird, den Timer starten (kleinster Interval) und in die Prozedur zum zeichnen springen. Hier den Timer gleich wieder stoppen und per Variable das erneute starten des Timer im MouseMove unterbinden bis die Prozedur verlassen wird. Ist dann immer noch ein MouseMove-Event vorhanden, kann der Timer ja wieder gestartet werden. Man könnte sich auch überlegen ein vereinfachtes Linien (Drahtgitter)-Modell, anstatt eines kompletten 3D-Modells mit Beleuchtung und Schatten, während des Timer-Events zu zeichnen und erst mit dem MouseUp das komplette 3D-Modell oder man arbeitet nur mit dem Drahtgitter-Modell und schaltet erst zur Ansicht auf ein 3D-Modell mit Licht und Schatten um.
    Mfg -Franky-
    @VaporiZed
    @-Franky-
    Danke für eure anerkennenden Beiträge. Als "One-man-show" kann man seine eigene Leistung schwer einschätzen.

    Ich verwende für meine 3D-Darstellungen nur Basis-2DGrafik-Befehle wie DrawLine, FillEllipse, DrawPolygon etc.
    Das im Screenshot gezeigte Objekt hat 42 Punkte (als Kugeln dargestellt) und 76 Linien, die als räumliche Darstellung ringförmig mit je 60 Polygonflächen (=4560 Stück) umgeben sind. Hierfür werden die weiteren 9120 Koordinaten benötigt. Alle 41394 Grafikelelmente müssen bei jeder Verschiebung (MouseMove) neu gezeichnet werden und zwar (nach Sortierung) beginnend mit dem vom Beobachtungspunkt weitest entfernten Element (wg der Überdeckung). Für jede der Polygonflächen wird je nach Orientierung zur fiktiven Lichtquelle ein anderer Farb-/Helligkeitswert errechnet(Vektorrechnung). Für den Schatten berechne ich die Projektion des Objekts auf eine Untergrundebene und behandle dieses wie ein eigenes Objekt, das wg der Überdeckung zuerst gezeichnet wird, also nochmal 41394 Grafikelemente.
    Trotzdem lässt sich das Objekt - mittels Timermethode - mit der Maus recht flüssig bewegen und drehen. Alles soweit OK.
    Da ich mir das alles selbst ausgedacht habe, war ich mir nicht sicher, ob man das nicht noch einfacher und effizienter hätte machen können.

    Nachtrag. Das mit dem Drahtgittermodell habe ich optional schon implementiert. Man muss die Option bei sehr großen Objekten es nur vorher aktivieren. Ansonsten habe ich den gesamten Vorgang des Zeichnens als Backgroundworker-Prozess ermöglicht, was eine Performance-Steigerung um Faktor Zwei brachte, das Bild aber sehr unruhig werden lässt.

    Anbei noch ein weiterer Screenshot des Objekts in anderer Umgebung
    Bilder
    • Screen2_Grafik06.jpg

      497 kB, 2.736×1.824, 54 mal angesehen

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

    @koning3
    Alles ganz normal mit Standard GDI+ Funktionen? Nicht schlecht. Dann wäre ja Direct2D ja vllt doch eine Alternative. Ich hatte hier mal gezeigt wie man einfache Sachen per Direct2D zeichnen kann: einfache 2D Objekte per Direct2D, ohne Verweis oder NuGet-Pakete, zeichnen Das Beispiel ist natürlich mit weiteren D2D Funktionen zum zeichnen ausbaubar. Evtl. wäre auch ein SwapChain denkbar um das ganze zu beschleunigen.
    Mfg -Franky-