在我的Delphi / C ++ Builder应用程序中,我有一个OnMouseMove处理程序,该处理程序使用户可以通过拖动绘图元素来与绘图进行交互。 (我们已经手动实现了必要的拖放逻辑,而不是使用VCL的OnDragOver等。)
OnMouseMove事件根据绘图的当前状态更新主窗体和几个子窗体。但是,只要我移动鼠标,除非我手动在窗体及其每个子窗体上调用Repaint,否则主窗体和任何子窗体都不会真正重绘其更新状态。这有点脆弱,因为很容易错过需要重新粉刷的子窗体。
我停止移动鼠标的那一刻,窗体按预期方式重新绘制,因此看起来控件已按预期失效,只要传入OnMouseMove事件/ WM_MOUSEMOVE消息,它们就不会重新绘制。(如果我拖慢的话,那么屏幕也会按预期重新绘制。)
甚至在每个窗体上手动调用Repaint也并不总是足够的,因为除非我单独重新绘制单个子窗体的控件,否则它们可能不会重新绘制。 (例如,如果我调用其父TForm的Repaint,则TEdit将显示其新值,但是除非我调用其自己的Repaint,否则我禁用的TRadioButton不会显示为已禁用。)
为什么根本需要致电Repaint?为什么在拖动鼠标时Windows无法自动重绘应用程序的窗口?重试窗口是否比尝试手动枚举需要重绘的窗口更好?
通过玩一个简短的测试应用程序,我想知道问题是否在于我的OnMouseMove事件是否足够慢,以至于由于该应用程序太忙于WM_MOUSEMOVE而不会调度WM_PAINT消息?我不确定是否确实如此,如果不确定,该如何处理。
这是一些(希望不会过于简化)的代码来说明我在做什么。 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;
}
最佳答案
一次,我在使用VCL拖放的应用程序中注意到了相同的行为。通过发布自身或调用WM_PAINT
生成的Invalidate
消息以某种方式不会到达消息队列的顶部。
我建议使用Repaint
代替Update
,它应该更好地处理子级重绘。