MouseWheel-Aktion auf passiven Controls

    • C#

      MouseWheel-Aktion auf passiven Controls

      Moin Leute.

      Problem war die Auswertung des MouseWheel-Events auf einer PictureBox, um in einem Stapel von Bildern zu wechseln, nicht aber die Bildposition oder den Zoomfaktor zu ändern.
      Einen freundlichen Dank an Stackoverflow, wo einige Grundlagen diskutiert wurden: stackoverflow.com/questions/33…eel-event-with-picturebox
      PictureBox, Label und Co. reagieren nicht auf das MouseWheel-Event, sie sind passiv.

      Wie sich herausstellte, gibt es unter Win7 und Win8.1 einerseits und Win10 andererseits große Unterschiede.
      Außerdem gibt (unter W7 und W8.1) es bezüglich des MouseWheel-Events "gutartige" und "bösartige" Controls.
      "Gutartige" Controls sind Controls, die auf das MouseWheel-Event reagieren, wenn die Maus über ihnen ist, z.B. die RichTextBox.
      "Bösartige" Controls sind Controls, die das MouseWheel-Event claimen, wenn sie den Eingabefokus haben, z.B. das NumericUpDown oder die TrackBar.

      Zu den Code-Beispielen.
      In einer RichTextBox, einem Label und einem Nicht-Autoscroll-Panel werden Zahlen ausgegeben, die mit der Scroll-Richtung incrementiert oder decrementiert werden.
      NumericUpDown und TrackBar verändern ihr Value.
      Das MouseWheel-Event der RichTextBoxen ist eigentlich nicht erforderlich, der vorhandene Text, so er länger als die Anzeige ist, wird gescrollt.
      Um denselben visuellen Eindruck wie bei den passiven Controls zu erzeugen, bekommt die RichTextBox ebenfalls einen zählenden Wert im eigenen Eventhandler.

      Zum Prinzip:
      Unter Win10 ist es ganz einfach.
      Die Form aboniert das globale MouseWheel-Event und verteilt es, je nach von der Maus überstrichenem passiven Control, auf dieses.
      Aktive Controls bekommen keinen separaten Eventhandler.
      Ausnahme ist die RichTextBox, wie oben erläutert.

      Unter Win7 und Win8.1 ist das etwas komplizierter.
      Alle aktiven Controls bekommen denselben Eventhandler.
      Die "bösartigen" Controls müssen abgeleitet werden, um freiwillig das MouseWheel-Event abzugeben, wenn das Control nicht mehr von der Maus überstrichen wird.
      "Bösartige" Conrols werden aktiviert, wenn die Maus auf ihnen ist, ansonsten werden sie deaktiviert.
      exemplarisch für ein "bösartiges" Control

      C#-Quellcode

      1. using System.Windows.Forms;
      2. namespace PictureBoxMouseWheel
      3. {
      4. /// <summary>
      5. /// Klasse zum freundlichen Behandeln des
      6. /// MouseWheel-Events unter Windows 7 und 8.1
      7. /// </summary>
      8. public class MyNumericUpDown
      9. : NumericUpDown
      10. {
      11. /// <summary>
      12. /// Flag zum Deaktivieren "bösartigen" Controls
      13. /// </summary>
      14. public bool IsActive = false;
      15. /// <summary>
      16. /// Event für das MainWindow zum re-aquirieren
      17. /// des MouseWheel-Events
      18. /// </summary>
      19. public event MouseEventHandler MyMouseWheel = delegate { };
      20. /// <summary>
      21. /// das eigentliche MouseWheel-Event
      22. /// </summary>
      23. protected override void OnMouseWheel(MouseEventArgs e)
      24. {
      25. // globales MouseWheel-Event
      26. this.MyMouseWheel(this, e);
      27. if (this.IsActive)
      28. {
      29. // nur aktive Controls dürfen ihr MouseWheel-Event abarbeiten
      30. base.OnMouseWheel(e);
      31. }
      32. }
      33. }
      34. }
      Test, ob sich die Maus auf einem Control befindet

      C#-Quellcode

      1. /// <summary>
      2. /// Testen, ob die Maus auf dem gegebenen Control ist
      3. /// </summary>
      4. private bool CheckMousePos(Control ctrl)
      5. {
      6. // Do not use MouseEventArgs.X, Y because they are relative!
      7. Point mousePos = Control.MousePosition;
      8. do
      9. {
      10. Rectangle rect = ctrl.RectangleToScreen(ctrl.ClientRectangle);
      11. if (!rect.Contains(mousePos))
      12. {
      13. return false; // mouse position is outside the picturebox or it's parents
      14. }
      15. ctrl = ctrl.Parent;
      16. }
      17. while (ctrl != null && ctrl != this);
      18. // here you have the mouse position relative to the pictureBox if you need it
      19. return true;
      20. }
      Der Rest ist dann wieder einfach, jedes Control reagiert auf sein eigenes Event im globalen Event-Handler.

      Viel Spaß

      PictureBoxMouseWheel.W7.zip
      PictureBoxMouseWheel.W10.zip
      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!