在我的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,它应该更好地处理子级重绘。

10-07 19:48
查看更多