在我的 Delphi / C++Builder 应用程序中,我有一个 OnMouseMove 处理程序,它允许用户通过拖动绘图元素与绘图进行交互。(我们手动实现了必要的拖放逻辑,而不是使用 VCL 的 OnDragOver 等。)
OnMouseMove 事件根据绘图的当前状态更新主窗体和几个子窗体。但是,只要我移动鼠标,主窗体和任何子窗体都不会真正重绘它们的更新状态,除非我在窗体及其每个子窗体上手动调用 Repaint。这有点脆弱,因为很容易错过需要重新绘制的子窗体。
在我停止移动鼠标的那一刻,表单按预期重新绘制,因此控件似乎按预期失效,只要 OnMouseMove 事件/WM_MOUSEMOVE 消息进入,它们就不会重新绘制。(如果我拖动非常缓慢,然后屏幕也将按预期重新绘制。)
即使在每个窗体上手动调用 Repaint 也总是不够的,因为除非我单独重绘它们,否则单个子窗体的控件可能不会重绘。(例如,如果我调用其父 TForm 的 Repaint,TEdit 会显示其新值,但我禁用的 TRAdioButton 不会显示为禁用,除非我调用它自己的 Repaint。)
为什么有必要调用 Repaint?为什么当我拖动鼠标时 Windows 不会自动重新绘制我的应用程序的窗口?有没有比尝试手动枚举需要调用 Repaint 的窗口更好的重绘窗口的方法?
通过玩一个简短的测试应用程序,我想知道问题是否是我的 OnMouseMove 事件足够慢以至于 WM_PAINT 消息没有被调度,因为应用程序忙于 WM_MOUSEMOVE?我不确定这是否确实如此,或者如果是这样,该怎么办。
这是一些(希望不会过于简化)代码来说明我在做什么。GraphArea 是一个 TImage,其 Canvas 包含绘图。
void __fastcall TMachineForm::GraphAreaMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
if (IsNearAdjustableObject(X, Y)) {
is_adjusting = true;
}
}
void TMachineForm::GraphAreaMouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if (is_adjusting) {
AdjustObject(X, Y);
/* Draws to the GraphArea TImage by calling GraphArea->Canvas methods */
RedrawGraphArea();
/* Updates several standard VCL controls on ChildForm1 and ChildForm2;
* e.g., ChildForm1->Edit1->Text = CalculatedValue(); */
NotifyChildForm1OfAdjustment();
NotifyChildForm2OfAdjustment();
/* This is where I have to manually call Repaint. I don't know why. */
GraphArea->Repaint();
ChildForm1->Repaint();
ChildForm2->Repaint();
}
}
void TMachineForm::GraphAreaMouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
is_adjusting = false;
}