Je ne parviens pas à obtenir l'événement Mouse Wheel dans le formulaire principal.
En tant que démo, j'ai trouvé un exemple simple:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.panel1.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
this.panel1.MouseMove += new MouseEventHandler(panel1_MouseWheel);
Form2 f2 = new Form2();
f2.Show(this);
}
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
if(e.Delta != 0)
Console.Out.WriteLine(e.Delta);
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(Form2_MouseMove);
this.MouseWheel += new MouseEventHandler(Form2_MouseMove);
}
private void Form2_MouseMove(object sender, MouseEventArgs e)
{
if(e.Delta != 0)
Console.Out.WriteLine(e.Delta);
}
}
Je reçois l'événement de la molette de la souris dans Form2 mais pas Form1, des idées?
À votre santé,
James
Je soupçonne que l'OP souhaite obtenir des événements de défilement lorsque seule la souris survole le panneau, même si le panneau n'a pas le focus.
Un moyen d'accomplir ce comportement est expliqué ici:
http://social.msdn.Microsoft.com/forums/en-US/winforms/thread/eb922ed2-1036-41ca-bd15-49daed7b637c/
et ici:
http://social.msdn.Microsoft.com/forums/en-US/winforms/thread/6bfb9287-986d-4c60-bbcc-23486e239384/
L'un des extraits de code extraits du forum lié:
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1 {
public partial class Form1 : Form, IMessageFilter {
public Form1() {
InitializeComponent();
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m) {
if (m.Msg == 0x20a) {
// WM_MOUSEWHEEL, find the control at screen position m.LParam
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
IntPtr hWnd = WindowFromPoint(pos);
if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) {
SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
return true;
}
}
return false;
}
// P/Invoke declarations
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pt);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
}
Ce code interceptera essentiellement tous les événements wm_mousewheel et les redirigera vers le contrôle sur lequel la souris survole actuellement. Le panneau n'a plus besoin de se concentrer pour recevoir les événements de la roue.
Votre problème vient du fait que form1 a le focus, pas panel1. ... ce qui signifie bien sûr que ce sont les événements de form1 qui seront déclenchés, pas les événements de panel1.
J'ai recréé votre scénario avec les modifications suivantes apportées au constructeur dans Form1 et vérifié qu'il déclenche l'événement de la molette de défilement.
public Form1()
{
InitializeComponent();
/* --- Old code that don't work ---
this.panel1.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
this.panel1.MouseMove += new MouseEventHandler(panel1_MouseWheel);
*/
this.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
this.MouseMove += new MouseEventHandler(panel1_MouseWheel);
Form2 f2 = new Form2();
f2.Show(this);
}
}
Ajoutez un autre événement du panneau MouseEnter
et dans sa fonction de rappel obtenez le focus d'entrée:
void MouseEnterEvent()
{
this.Panel.Focus();
}
Grâce à la réponse de @nitrogenycs, j'ai écrit une classe générique simple pour résoudre facilement le problème:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
namespace MyNamespace
{
public class MouseWheelManagedForm : Form, IMessageFilter
{
private bool managed;
public MouseWheelManagedForm () : this (true) {
}
public MouseWheelManagedForm (bool start) {
managed = false;
if (start)
ManagedMouseWheelStart();
}
protected override void Dispose (bool disposing) {
if (disposing)
ManagedMouseWheelStop();
base.Dispose(disposing);
}
/************************************
* IMessageFilter implementation
* *********************************/
private const int WM_MOUSEWHEEL = 0x20a;
// P/Invoke declarations
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint (Point pt);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage (IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
private bool IsChild (Control ctrl) {
Control loopCtrl = ctrl;
while (loopCtrl != null && loopCtrl != this)
loopCtrl = loopCtrl.Parent;
return (loopCtrl == this);
}
public bool PreFilterMessage (ref Message m) {
if (m.Msg == WM_MOUSEWHEEL) {
//Ensure the message was sent to a child of the current form
if (IsChild(Control.FromHandle(m.HWnd))) {
// Find the control at screen position m.LParam
Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
//Ensure control under the mouse is valid and is not the target control
//otherwise we'd be trap in a loop.
IntPtr hWnd = WindowFromPoint(pos);
if (hWnd != IntPtr.Zero && hWnd != m.HWnd && Control.FromHandle(hWnd) != null) {
SendMessage(hWnd, m.Msg, m.WParam, m.LParam);
return true;
}
}
}
return false;
}
/****************************************
* MouseWheelManagedForm specific methods
* **************************************/
public void ManagedMouseWheelStart () {
if (!managed) {
managed = true;
Application.AddMessageFilter(this);
}
}
public void ManagedMouseWheelStop () {
if (managed) {
managed = false;
Application.RemoveMessageFilter(this);
}
}
}
}
À partir de là, il vous suffit d'hériter votre formulaire de cette classe au lieu du formulaire pour chaque formulaire dont vous avez besoin que la molette de la souris soit "gérée":
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
namespace MyApp
{
public partial class MyForm : MyNamespace.MouseWheelManagedForm
{
public MyForm ()
{
InitializeComponent();
}
}
}
J'espère que cela aidera quelqu'un d'autre (que moi).
Peut-être que cela fonctionnera pour vous?
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
Form2 f2 = new Form2();
f2.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
f2.MouseMove += new MouseEventHandler(panel1_MouseWheel);
f2.Show(this);
}
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
if(e.Delta != 0) Console.Out.WriteLine(e.Delta);
}
}
Je pense que vous avez un peu mal compris mon problème. Sur mon formulaire principal avec le code ci-dessous, je ne reçois pas l'événement MouseWheel:
public Form1()
{
InitializeComponent();
this.panel1.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
this.panel1.MouseMove += new MouseEventHandler(panel1_MouseWheel);
}
Mais je reçois l'événement avec:
public Form1()
{
InitializeComponent();
this.MouseWheel += new MouseEventHandler(panel1_MouseWheel);
}
J'espère que c'est plus clair sans la confusion Form2. J'essaie simplement d'obtenir les événements MouseWheel sur un panneau dans ma forme principale.
À votre santé,
James
Le panneau ne peut pas avoir le focus lui-même, seul un élément placé à l'intérieur du panneau peut avoir le focus. Le panneau ne recevra l'événement MouseWheel qu'une fois que quelque chose est placé à l'intérieur et que cette chose a le focus. Le simple fait de passer au-dessus du panneau et de déplacer la molette de la souris enverra l'événement au formulaire, pas au panneau.
C'est la différence entre vos deux exemples.