私の Delphi / C++Builder アプリには、ユーザーがプロット要素をドラッグしてプロットを操作できるようにする OnMouseMove ハンドラがあります。(VCL の OnDragOver などを使用する代わりに、必要なドラッグ アンド ドロップ ロジックを手動で実装しました。)
OnMouseMove イベントは、プロットの現在の状態に基づいて、メイン フォームといくつかの子フォームの両方を更新します。ただし、マウスを動かしている限り、フォームとその各子フォームで Repaint を手動で呼び出さない限り、メイン フォームも子フォームも更新された状態を実際に再描画しません。再描画が必要な子フォームを見落としやすいため、これはやや脆弱です。
マウスの動きを止めるとすぐに、フォームが期待どおりに再描画されるため、コントロールが期待どおりに無効化されているように見えます.OnMouseMoveイベント/ WM_MOUSEMOVEメッセージが着信している限り、コントロールは再描画されません.(非常にゆっくりとドラッグすると、その後、画面も期待どおりに再描画されます。)
個々の子フォームのコントロールは、個別に再描画しない限り再描画されない可能性があるため、各フォームで手動で Repaint を呼び出すだけでは必ずしも十分ではありません。(たとえば、TEdit は、親の TForm の Repaint を呼び出すと新しい値を表示しますが、無効にした TRadioButton は、それ自体の Repaint を呼び出さない限り、無効に見えません。)
Repaint を呼び出す必要があるのはなぜですか? マウスをドラッグしている間、Windows がアプリのウィンドウを自動的に再描画しないのはなぜですか? Repaint を呼び出す必要があるウィンドウを手動で列挙するよりも、ウィンドウを再描画するより良い方法はありますか?
簡単なテスト アプリケーションをいじってみると、OnMouseMove イベントが遅すぎて、アプリケーションが WM_MOUSEMOVE で忙しすぎて WM_PAINT メッセージがディスパッチされないことが問題なのだろうか? これが実際に当てはまるかどうか、またはそうである場合、これについて何をすべきかはわかりません。
ここに、私が何をしているかを説明するための (過度に単純化されていないことを願っています) コードを示します。GraphArea は、Canvas にプロットが含まれる TImage です。
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;
}