Snapshot before repaint phase 2

This commit is contained in:
Codex
2026-04-07 21:37:49 +08:00
parent b07a4ec370
commit 77a8fe568a
10 changed files with 395 additions and 131 deletions
+22 -7
View File
@@ -1,5 +1,6 @@
#include "Button.h"
#include "SxLog.h"
#include "Window.h"
Button::Button(int x, int y, int width, int height, const std::string text, StellarX::ButtonMode mode, StellarX::ControlShape shape)
: Control(x, y, width, height)
@@ -269,6 +270,9 @@ void Button::draw()
restoreStyle();//恢复默认字体样式和颜色
dirty = false; //标记按钮不需要重绘
if (tipEnabled && tipVisible)
tipLabel.draw();
}
// 处理鼠标事件,检测点击和悬停状态
// 根据按钮模式和形状进行不同的处理
@@ -422,20 +426,28 @@ bool Button::handleEvent(const ExMessage& msg)
if (stateChanged)
dirty = true;
const bool tipVisibilityChanged = (tipVisible != oldTipVisible);
if (tipVisibilityChanged)
dirty = true;
// 鼠标命中按钮区域,或按钮自身状态因此发生变化时,吞掉该事件。
// 这样可以避免被遮挡/重叠的下层控件继续收到同一事件并把自己重绘到上层。
if (isMouseMessage && (hover || oldHover || click != oldClick))
// 事件吞噬规则:
// - 鼠标移动:只有“当前命中按钮”时才吞掉,避免前一个按钮在清 hover 时截断消息,
// 导致后一个真正命中的按钮收不到 WM_MOUSEMOVE。
// - 鼠标按下/抬起:命中按钮区域时吞掉,避免点击穿透到底层控件。
if (msg.message == WM_MOUSEMOVE)
{
if (hover)
consume = true;
}
else if ((msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONUP) && hover)
{
consume = true;
}
markEventVisualChanged(stateChanged || tipVisibilityChanged);
// 如果需要重绘,立即执行
if (dirty)
requestRepaint(parent);
if (tipEnabled && tipVisible)
tipLabel.draw();
return consume;
}
@@ -671,7 +683,10 @@ void Button::hideTooltip()
if (tipVisible)
{
tipVisible = false;
tipLabel.hide(); // 还原快照+作废,防止残影
if (auto* host = getHostWindow(); host && host->isManagedDispatchActive())
tipLabel.invalidateBackgroundSnapshot();
else
tipLabel.hide(); // 还原快照+作废,防止残影
tipHoverTick = GetTickCount64(); // 重置计时基线
}
}