【问题标题】:Windows Forms MouseEnter not firing after control moved控件移动后 Windows 窗体 MouseEnter 未触发
【发布时间】:2015-09-14 08:02:07
【问题描述】:

我想在鼠标进入时为PictureBoxBackColor 属性着色。

MouseEnter 事件触发时,我将BackColor 变为黄色,并在MouseLeave 中重置为透明。

然后当我点击PictureBox 时,我改变了它的位置,所以我还有一个Move 事件,它可以透明地重置它。

问题是,一旦我移动它,我需要用鼠标输入两次PictureBox 来触发 MouseEnter 事件!

这是一个非常图形化的问题,所以我上传了一点video 来告诉你发生了什么,它肯定会比我更好地解释我的问题。

我尝试了另一种方法,不是在MouseEnter 中更改颜色,而是在MouseHover 中更改颜色。在这种情况下,它运行良好,只是我在触发 Move 事件之前有 500 毫秒的延迟,这显然不是我想要的。

我目前没有可行的解决方案。

代码很简单,目前我有:

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;
}

在 Designer.cs 中,我对每个 PictureBox 的事件如下:

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);

编辑:回答我的问题,这是我现在使用的代码:(cmets 是法语)

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;
        }
    }
}

我使用与以前相同的方法,但由于未知原因,现在它可以工作了。 感谢大家帮助我:)

【问题讨论】:

  • 我在我的信息顶部写了一个“大家好”,但由于某些奇怪的原因,它似乎被剪掉了,即使我编辑了它,所以不要粗鲁:)跨度>
  • 您能否提供更多代码来显示您分配给处理程序的事件?
  • 可能跟一些重点部分有关。
  • @Falco Alexander 我编辑了我的第一篇文章,但我不知道我是否理解正确!
  • @user3623965 “你好”等是frowned upon,因为它们把事情搞得一团糟;许多称呼是automatically removed。别担心,没有人认为你不礼貌:-)

标签: c# windows forms winforms mouseenter


【解决方案1】:

问题是当你重新定位PictureBox时,它不会收到鼠标离开事件。可能你已经注意到了,这也是你在Move事件中设置BackColor的原因。

在您移动控件后,当您再次将其悬停时,它将不会收到第二个MouseEnter,只有在您关闭并再次打开鼠标之后。

尝试手动发送鼠标离开事件(我没有测试过):

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);
}

【讨论】:

  • 你说得对,我注意到 MouseLeave 没有引发,这就是我使用 Move 事件的原因;)谢谢你,我试过了,但它没有改变任何东西......但我们可能已经接近了解决方案!
  • 也许您应该将它与TrackMouseEvent 一起使用:msdn.microsoft.com/en-us/library/ms646265%28VS.85%29.aspx 这是一个一次性事件,因此需要在处理完事件后再次调用它以接收未来的事件。有关 C# 用法,请参阅链接页面的底部。
  • 我正在搜索和搜索,但无法使其正常工作...页面底部给出的代码给了我不明白的错误,解决方案似乎超重像我这样的小问题
【解决方案2】:

我会避免移动PictureBox。很明显你的 bug 就是从那里来的。

当你移动组件时,鼠标不在其中,但它的状态没有更新。

您可以在the windows form reference code 中畅游,或者您可以只说您有 N 个小预览(底部的图片)和一个大预览(上方的)。

创建N+1个图片框,不要更改。只需更改他们的image property

点击小预览时,将其图片属性切换为大预览。

另外,推荐一个好的MVC pattern

【讨论】:

  • 是的,我会尝试,当我成功后我会回来,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多