简体   繁体   中英

Windows Forms MouseEnter not firing after control moved

I want to color the BackColor property of a PictureBox when the mouse enters it.

I turn the BackColor into Yellow when then MouseEnter event fires, and I reset to transparent in MouseLeave .

Then when I click on a PictureBox , I change its position, so I also have a Move event which resets it in transparent.

The problem is, once I moved it, I need to enter the PictureBox twice with the mouse to fire the MouseEnter event!

It's a very graphical problem, so I uploaded a little video to show you what's happening, it surely will explain my problem better than I do.

I tried another way, changing the color not in MouseEnter but in MouseHover . In this case, it works well, except that I have a 500ms delay before firing the Move event, which is obviously not what I want.

I have no viable solution right now.

For the code, it's very simple, for the moment I have :

private void pictureBoxMouseUp(object sender, MouseEventArgs e)
{
    // I move the PictureBox here
}
 
private void pictureBoxMove(object sender, EventArgs e)
{
    (sender as PictureBox).BackColor = Color.Transparent;
}
 
private void pictureBoxMouseEnter(object sender, MouseEventArgs e)
{
    (sender as PictureBox).BackColor = Color.LightYellow;
}
 
private void pictureBoxMouseLeave(object sender, MouseEventArgs e)
{
    (sender as PictureBox).BackColor = Color.Transparent;
}

In the Designer.cs, my events for each PictureBox are like :

this.pictureBox2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBoxMouseDown);
this.pictureBox2.MouseEnter += new System.EventHandler(this.pictureBoxMouseEnter);
this.pictureBox2.MouseLeave += new System.EventHandler(this.pictureBoxMouseLeave);
this.pictureBox2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBoxMouseUp);
this.pictureBox2.Move += new System.EventHandler(this.pictureBoxMove);

EDIT : To answer my question, this is the code I use now : (comments are in french)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EmoTEDTherapeute;

namespace ControlSceneImage {

    public class SceneImage : PictureBox {

        public static readonly int defaultWidth = 100;
        public static readonly int defaultHeight = 100;

        static readonly int activePbPosY; // Position en Y des scènes actives

        static readonly Dictionary<string, Point> scenesPos = null; // Invariant, stocke la position initiale des PictureBox
        static readonly List<Point>[] activeScenesPos = null; // Invariant, stocke les positions des PictureBox en fonction du nombre de scènes actives

        static List<SceneImage> activeScenes = null;

        const int maxActiveScenes = 5;
        const int ecart = 80;
        const int decalage = 15;
        const int panelScenesWidth = 909;
        const int panelScenesHeight = 154;
        const int panelScenesLocationX = 35;
        const int panelScenesLocationY = 36;

        bool isActive;

        static SceneImage() {
            // Constructeur initialisant tous les membres statiques, n'est appelé qu'une seule fois, avant tout le reste
            activePbPosY = (panelScenesLocationY + panelScenesHeight - (int)(0.6 * defaultHeight)) / 2;
            scenesPos = new Dictionary<string, Point>();
            activeScenesPos = new List<Point>[maxActiveScenes];
            for (int i = 0; i < maxActiveScenes; i++) {
                activeScenesPos[i] = CalcActiveScenesPos(i+1);
            }
            activeScenes = new List<SceneImage>();
        }

        public SceneImage() {
            MouseEnter += new EventHandler(OnMouseEnter);
            MouseDown += new MouseEventHandler(OnMouseDown);
            MouseUp += new MouseEventHandler(OnMouseUp);
            MouseLeave += new EventHandler(OnMouseLeave);
            BorderStyle = BorderStyle.FixedSingle;
            Size = new Size(defaultWidth, defaultHeight);
            SizeMode = PictureBoxSizeMode.Zoom;
            isActive = false;
        }

        private static List<Point> CalcActiveScenesPos(int nbActiveScenes) {
            List<Point> ret = new List<Point>();
            for (int i = 0; i < nbActiveScenes; i++) {
                ret.Add(new Point((panelScenesLocationX + panelScenesWidth + ecart) / 2 + (int)((ecart + defaultWidth) * (i - nbActiveScenes / 2.0)) + decalage, activePbPosY));
            }
            return ret;
        }

        private void UpdateScenesPos() {
            for(int i = 0; i < activeScenes.Count; i++) {
                activeScenes[i].Location = activeScenesPos[activeScenes.Count - 1][i];
            }
        }

        private void OnMouseEnter(object sender, EventArgs e) {
            BackColor = Color.LightYellow;
            Cursor = Cursors.Hand;
        }

        private void OnMouseDown(object sender, MouseEventArgs e) {
            BorderStyle = BorderStyle.Fixed3D;
        }

        private void OnMouseUp(object sender, MouseEventArgs e) {
            if (!scenesPos.ContainsKey(Name)) {
                // Si ce n'est pas déjà fait, on stocke la position initiale de notre PictureBox
                scenesPos.Add(Name, Location);
                // Et on crée un Panel vide sous elle
                Panel panel = new Panel();
                panel.Location = Location;
                panel.Size = Size;
                panel.BorderStyle = BorderStyle.Fixed3D;
                // On ajoute notre panel à notre form
                Form1.AddInSeance(panel);
            }
            if (!isActive) {
                activeScenes.Add(this);
            } else {
                Location = scenesPos[Name];
                activeScenes.Remove(this);
            }
            isActive = !isActive;
            UpdateScenesPos();
        }

        private void OnMouseLeave(object sender, EventArgs e) {
            BorderStyle = BorderStyle.FixedSingle;
            BackColor = Color.Transparent;
        }
    }
}

I use the same method as before, and for an unknown reason, now it works. Thanks to all of you for helping me :)

The problem is that when you relocate the PictureBox , it will not receive the mouse leave event. Maybe you have already noticed that, that's why you set the BackColor in the Move event, too.

After you moved the control, it will not receive a second MouseEnter when you hover it again, only after you moved the mouse off and on again.

Try to send a mouse leave event manually (I haven't tested it):

private const int WM_MOUSELEAVE = 0x02A3;

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

private void pictureBoxMouseUp(object sender, MouseEventArgs e)
{
    // move the PictureBox...

    SendMessage(((PictureBox)sender).Handle, WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
}

I will avoid to move the PictureBox . Clearly your bug come from that.

When you move the component, the mouse is no more in it but it status is not updated.

You can swim deep in the windows form reference code or you can just says you have N small preview (the pictures on the bottom line) and one big preview (the upper one).

Create N+1 picture box and don't change it. Just change their image property .

When a small preview is clicked, switch it's image property with the big preview.

Also, a good MVC pattern is recommended.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM