C# WinForms数独开发:如何触发被覆盖主按钮的OnMouseHover事件?
解决WinForms数独游戏悬停小按钮时主按钮Hover失效的问题
这里提供三个实用的解决方案,你可以根据开发习惯选择:
方案一:让小按钮透传鼠标事件给主按钮
小按钮覆盖主按钮会拦截鼠标事件,我们可以让小按钮把鼠标消息转发给主按钮,确保主按钮的OnMouseHover能正常触发。
简单实现:直接调用主按钮的Hover方法
给每个小按钮绑定MouseEnter和MouseMove事件,主动触发主按钮的悬停逻辑:
// 假设当前主按钮实例为mainBtn,小按钮的MouseEnter事件处理 private void SmallButton_MouseEnter(object sender, EventArgs e) { mainBtn.OnMouseHover(e); } // 若需要持续保持悬停状态,可在MouseMove里也调用 private void SmallButton_MouseMove(object sender, MouseEventArgs e) { mainBtn.OnMouseHover(e); }
自定义控件方式(一劳永逸)
写一个自定义按钮类,自动把鼠标消息转发给指定的主按钮:
public class PassThroughButton : Button { // 要转发事件的目标控件(主按钮) public Control TargetControl { get; set; } protected override void WndProc(ref Message m) { base.WndProc(ref m); if (TargetControl == null) return; // 转发核心鼠标消息 switch (m.Msg) { case 0x200: // WM_MOUSEMOVE case 0x20A: // WM_MOUSEHOVER Message forwardMsg = Message.Create(TargetControl.Handle, m.Msg, m.WParam, m.LParam); TargetControl.WndProc(ref forwardMsg); break; } } }
使用时把小按钮替换成这个自定义控件,设置TargetControl为对应主按钮即可。
方案二:放弃小按钮,自定义绘制数字选项
直接在主按钮上绘制1-9的数字区域,完全避免子控件覆盖问题:
- 给主按钮添加状态标记和基础事件:
private bool _showNumOptions = false; // 鼠标悬停时显示数字选项 private void MainButton_MouseHover(object sender, EventArgs e) { _showNumOptions = true; this.Invalidate(); // 触发重绘 } // 鼠标离开时隐藏 private void MainButton_MouseLeave(object sender, EventArgs e) { _showNumOptions = false; this.Invalidate(); }
- 重写主按钮的
OnPaint方法,绘制3x3数字网格:
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (!_showNumOptions) return; int cellSize = Math.Min(this.Width, this.Height) / 3; var g = e.Graphics; // 绘制9个数字单元格 for (int i = 0; i < 9; i++) { int x = (i % 3) * cellSize; int y = (i / 3) * cellSize; // 绘制单元格背景和边框 g.FillRectangle(Brushes.LightBlue, x, y, cellSize, cellSize); g.DrawRectangle(Pens.DarkBlue, x, y, cellSize, cellSize); // 居中绘制数字 var numText = (i + 1).ToString(); var textSize = g.MeasureString(numText, this.Font); g.DrawString(numText, this.Font, Brushes.Black, x + (cellSize - textSize.Width) / 2, y + (cellSize - textSize.Height) / 2); } }
- 在主按钮的
MouseClick事件里判断选中的数字:
private void MainButton_MouseClick(object sender, MouseEventArgs e) { if (!_showNumOptions) return; int cellSize = Math.Min(this.Width, this.Height) / 3; int col = e.X / cellSize; int row = e.Y / cellSize; int selectedNum = row * 3 + col + 1; // 处理选中数字的逻辑,比如设置主按钮文本 this.Text = selectedNum.ToString(); _showNumOptions = false; this.Invalidate(); }
方案三:跟踪鼠标是否在主按钮/小按钮范围内
通过判断鼠标位置控制小按钮显示状态,避免误触发隐藏:
- 定义小按钮集合和状态标记:
private List<Button> _smallButtons = new List<Button>(); private bool _isHoveringGrid = false;
- 给主按钮和所有小按钮绑定
MouseEnter事件:
private void GridControl_MouseEnter(object sender, EventArgs e) { _isHoveringGrid = true; foreach (var btn in _smallButtons) { btn.Visible = true; } }
- 给主按钮和所有小按钮绑定
MouseLeave事件,检查鼠标位置:
private void GridControl_MouseLeave(object sender, EventArgs e) { Point globalMousePos = Cursor.Position; // 检查鼠标是否在主按钮范围内 bool inMainBtn = this.ClientRectangle.Contains(this.PointToClient(globalMousePos)); // 检查鼠标是否在任何小按钮范围内 bool inSmallBtn = _smallButtons.Any(btn => btn.ClientRectangle.Contains(btn.PointToClient(globalMousePos))); if (!inMainBtn && !inSmallBtn) { _isHoveringGrid = false; foreach (var btn in _smallButtons) { btn.Visible = false; } } }
内容的提问来源于stack exchange,提问作者Fox_Nyssame
相关产品推荐
相关产品推荐

