在我的Delphi/C++ Builder應用程序中,我有一個OnMouseMove處理程序,它允許用戶通過拖動陰謀元素與陰謀交互。 (我們手動實現了必要的拖放邏輯,而不是使用VCL的OnDragOver等)爲什麼在OnMouseMove中必須調用Repaint?
OnMouseMove事件根據圖的當前狀態更新主窗體和幾個子窗體。但是,只要我移動鼠標,主窗體和任何子窗體實際上都不會重繪它們的更新狀態,除非手動在窗體及其每個子窗體上調用Repaint。這有點脆弱,因爲很容易錯過需要重新繪製的兒童表格。
即時我停止移動鼠標,表單重新繪製按預期的方式,所以它看起來控件正在作爲預期失效,只要OnMouseMove事件/ WM_MOUSEMOVE消息進來,它們就不會重新繪製。(If我很慢地拖動非常,然後屏幕也會按預期重新繪製。) (例如,如果我調用其父母TForm的重畫,則TEdit會顯示其新值,但我禁用的TRadioButton不會顯示爲禁用,除非我將其稱爲它自己的重繪。)
爲什麼有必要根本打電話給Repaint ?爲什麼當我拖動鼠標時,Windows不會自動重新繪製應用程序的窗口?有沒有更好的方法來重繪窗口比嘗試手動枚舉哪些窗口需要重繪調用?
從一個簡短的測試應用程序,我想知道是否問題是我的OnMouseMove事件足夠慢,WM_PAINT消息不會得到調度,因爲應用程序是忙於WM_MOUSEMOVE?我不確定這是否確實如此,或者如果是這樣的話,該怎麼辦。
下面是一些(希望不是過於簡化)代碼來說明我在做什麼。 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;
}
我想這是因爲拖動操作在一個特殊的消息循環內運行,而不是類似於模態消息循環。 – 2012-07-31 21:46:10
@DavidHeffernan - 即使我是從OnMouseMove處理程序手動實現自己的拖放操作,而不是調用任何VCL拖動操作? – 2012-07-31 21:47:39
如果你不瞭解你的手動拖放操作,那真的很難說。通常情況下,您不必調用Repaint(並且不應該放在首位 - 父控件上的「Invalidate」通常足以更新它並且它是子控件)。 – 2012-07-31 21:48:12