|
- Jak pozbyć się migotania TImage przy przesuwaniu.
Problem z obiektem TImage polega na tym, że wywodzi się on z klasy TGraphicControl (ta zaś z TControl), co oznacza, że nie posiada on własnego okna. TImage, TLabel i TShape - wszystkie one pochodzą od TGraphicControl. Poruszanie tym typem kontrolek (poprzez zmianę właściwości Top i Left) będzie powodowało wyraźne migotanie. Dzieje się tak, ponieważ wymagają one ciągłego odświeżania przy wyświetlaniu w nowym miejscu (w przeciwieństwie do obiektów wywodzących się od TWinControl). Windows zna pozycję TWinControl, ale nie wie nic o TGraphicControl.
Można tą sytuację porównać do tablicy na notatki: kontrolki TWinControl są przyczepione szpilkami, zaś TGraphicControl są po prostu narysowane na tablicy. Jest o wiele prościej przesunąć kontrolkę "przyszpiloną", aniżeli narysowaną. Widzisz w tym sens? Najłatwiejsze więc rozwiązanie to zmiana rodzica (Parent) kontrolki TGraphicControl na TWinControl i przesunięcie WinControl (np. panel). Kiedy używasz panelu, ustaw właściwość FullRepaint na false. Oto przykład poruszania obiektu TImage (w zasadzie poruszania panelu...)
Strategia: tworzymy TPanel (który jest TWinControl), umieszczamy na nim TImage podczas przeciągania i z powrotem na formie po przeciągnięciu. Idąc dalej, zablokujemy wymazywanie tła poprzez "subclassing" metody WindowProc panelu.
//w pliku nagłówkowym
private:
bool FDragging;
int OldX, OldY;
TPanel *TempPanel;
Controls::TWndMethod OldPanelWP;
void __fastcall NewPanelWP(TMessage &Msg);
//w pliku źródłowym
//-----------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
FDragging = false;
TempPanel = new TPanel(this);
TempPanel->Parent = this;
TempPanel->BorderStyle = bsNone;
TempPanel->BevelInner = bvNone;
TempPanel->BevelOuter = bvNone;
TempPanel->FullRepaint = false;
//poprzez "subclassing" metody WindowProc
//blokujemy komunikat WM_ERASEBKGND
OldPanelWP = TempPanel->WindowProc;
TempPanel->WindowProc = NewPanelWP;
}
void __fastcall TForm1::NewPanelWP(TMessage &Msg)
{
if (Msg.Msg == WM_ERASEBKGND)
{
Msg.Result = 0;
return;
}
OldPanelWP(Msg);
}
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
FDragging = true;
OldX = X;
OldY = Y;
TempPanel->Left = Image1->Left;
TempPanel->Top = Image1->Top;
TempPanel->Height = Image1->Height;
TempPanel->Width = Image1->Width;
TempPanel->Visible = true;
SetCapture(TempPanel->Handle);
Image1->Parent = TempPanel;
Image1->Left = 0;
Image1->Top = 0;
}
void __fastcall TForm1::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
if (FDragging == true)
{
TempPanel->Left = TempPanel->Left + (X - OldX);
TempPanel->Top = TempPanel->Top + (Y - OldY);
}
}
void __fastcall TForm1::Image1MouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y)
{
TempPanel->Visible = false;
Image1->Left = TempPanel->Left;
Image1->Top = TempPanel->Top;
Image1->Parent = this;
FDragging = false;
}
void __fastcall TForm1::FormClose(TObject *Sender,
TCloseAction &Action)
{
TempPanel->WindowProc = OldPanelWP;
delete TempPanel;
}
|