2017-09-28 13 views
0

Als ein Entwickler, der einen Custome Splitter Wnd baut, der benutzerdefinierte Klasse verwendet, die von CWnd geerbt wird. Anfangs hat der Bildschirm ein Fenster (benutzerdefinierte Klasse - CTile), das zwei Schaltflächen hat (vertikal - geteilt, horizontal - geteilt). Wenn der Benutzer auf eine der beiden Schaltflächen klickt, wird der rote Trennbalken angezeigt und zwei untergeordnete Fenster (CTile) werden angezeigt. Wie Sie wissen, während Benutzer die rote Trennleiste ziehen, muss das untergeordnete Fenster geändert werden. Was ich hier sage ist, dass in diesem Moment das Flackern erscheint. Die Eltern-Wnd hat nur drei Elemente (zwei untergeordnete Fenster und eine geteilte Leiste), also denke ich, dass es nie Inhalt der Zeichnung erfordert. Ich meine WM_PAINT Nachrichtenhandler. Hier ist mein Code.C++: RedrawWindow() Flackern

this->cDiv = new CDivider(this->wth_tile/2, 1); 
this->cDiv->CreateDivider(this, this->hgt_tile); 

//cDiv is split bar I used custom class which is inherited from CWnd. 
//CreateDivider() is also my self-defined method. 

this->first_child = new CTile(); 

// As I mentioned above, CTile is divided child window which is also inherited from CWnd. 

POINT pt; 
pt.x = 0; 
pt.y = 0; 
this->first_child->CreateTile(this, this->cDiv->sd_pos, this->hgt_tile, pt); 

this->second_child = new CTile(); 


pt.x = this->cDiv->sd_pos + 5; 
pt.y = 0; 

this->second_child->CreateTile(this, this->cDiv->sd_pos, this->hgt_tile, pt); 

This is make movable split bar wnd creation code. 

And next is about modified child window size while drag the split bar. 

void CDivider::OnMouseMove(UINT nFlags, CPoint point) 
{ 
// TODO: Add your message handler code here and/or call default 

POINT pt; 
HDC hdc; 
RECT rect; 

this->parentWnd->GetWindowRect(&rect); 

//convert the mouse coordinates relative to the top-left of 
//the window 
ClientToScreen(&point); 
pt = point; 
pt.x -= rect.left; 
pt.y -= rect.top; 

if (this->sd_mode == 1) 
{ 
    ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); 
    if (GetCapture() == this && this->dragged) 
    { 
     this->sd_pos = pt.x; 
     if (pt.x != oldPos.x && nFlags & MK_LBUTTON) 
     { 
      this->length = this->parentWnd->hgt_tile; 
      this->MoveWindow(this->sd_pos, 0, 4, this->length); 
      this->parentWnd->ResizeParent(); 
      this->parentWnd->Invalidate(); 
      this->parentWnd->UpdateWindow(); 
      TRACE("Resize Parent\n"); 
      /*this->parentWnd->first_child->Invalidate(); 
      this->parentWnd->second_child->Invalidate();*/ 
     } 
    } 

} 
else if (this->sd_mode == 2) 
{ 
    ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); 

    if (GetCapture() == this && this->dragged) 
    { 
     this->sd_pos = pt.y; 
     if (pt.y != oldPos.y && nFlags & MK_LBUTTON) 
     { 
      this->Invalidate(); 
      this->length = this->parentWnd->wth_tile; 
      this->MoveWindow(0, this->sd_pos, this->length, 4); 

      this->parentWnd->ResizeParent(); 
      this->parentWnd->Invalidate(); 
      this->parentWnd->UpdateWindow(); 
      TRACE("Resize Parent\n"); 
      /*this->parentWnd->first_child->Invalidate(); 
      this->parentWnd->second_child->Invalidate();*/ 
     } 
    } 
} 

CWnd::OnMouseMove(nFlags, point); 

}

Hier ist parentWnd Split übergeordnete Fenster der Bar - nur Eltern erste Fenster. first_child und second_child sind unterteilte Fenster. sd_mode bedeutet, dass Split-Methode - vertikal & horizontal.

Warum funktioniert dieser Code nicht?

+1

Erstellen Sie Elternfenster mit 'WS_CLIPCHILDREN' Windows-Stil? – VTT

+0

WS_CLIPCHILDREN? Ich habe WS_CLIPCHILDREN nie benutzt. Nur WS_VISIBLE und WS_CHILD wurden zum Erstellen eines Fensters verwendet. @VTT –

Antwort

2

Das Flackern geschieht, weil das Malen in den meisten normalen Fenstern ein zweiphasiger Vorgang ist. 1. Der Hintergrund wird gelöscht, 2. Das Fenster wird neu gezeichnet.

Also das Problem ist das untergeordnete Fenster, das neu gezeichnet werden muss. Es gibt viele Artikel über nicht flackerndes Malen.

Sie können auch das Neuzeichnen optimieren, indem Sie nur die betroffenen Teile der Fenster ungültig machen. Sie erzwingen ein Neuzeichnen der vollständigen Fenster. Das ist nicht ideal. In einem solchen Fall könnte ein großer Teil des Fensters flackern.

BTW: RedrawWindow mit den spezifischen Flags sind besser als Aufruf von Invalidate/Update Sequenzen und kann ein Tick schneller sein.

Auch kann es besser sein, eine Methode zu verwenden, um Balken mit einem XOR-Paining während des Ziehens zu zeichnen. Und aktualisieren Sie die Fenstergröße, wenn das LButtonUp-Event passiert. Wie CSplitterWnd es macht ... Sie haben die Quelle. Schau in Es hinein.

+0

Vielen Dank für Ihren Vorschlag, @xMRi –

+0

Ich werde versuchen, Ihre Idee über Kind Fenster Neulackierung folgen. Und über die spezifischen Teile des Fensters denke ich, dass es auch gut ist. Wenn du sagst "Es ist vielleicht auch besser, eine Methode zu verwenden, um Balken während des Ziehens mit einem XOR-Painting zu zeichnen.", Kannst du ein Beispiel dafür nennen? –

+0

Sie haben den Quellcode des MFC CSpiltterWnd. Schaut einfach hinein. Du findest alles was du brauchst. – xMRi