OnPaint spinnt



  • Hallo,
    ich habe ein eigenes Steuerelement geschrieben, dass von der Optik her an eine CListCtrl erinnert. Eigentlich läuft das Ding aber wenn ich das Programm mehrere Stunden laufen lasse, dann wird plötzlich die standard Schrift genommen und nicht meine eigene und außerdem wird keine der definieren Farben mehr benutzt um den Hintergrund zu zeichnen. Es ist also alles weiss, Schrift schwarz und Schrift standard Schrift.

    Hier mein Code:

    void myListCtrl::OnPaint() 
    {
    	// Variablen
    	CPaintDC	paint_dc(this);
    	CMemDC		dc(&paint_dc);
    
    	// Farben
    	COLORREF	m_backgroundColor	= RGB(255, 255, 255);
    	COLORREF	m_systemGREY		= RGB(236, 233, 216);
    	COLORREF	m_darkGREY			= RGB(173, 170, 153);
    	COLORREF	m_lightGREEN		= RGB(149, 255, 144);
    	COLORREF	m_darkGREEN			= RGB(  9, 198,   0);
    
    	// Textart
    	HFONT		m_Font = CreateFont(14,0, 0,0, FW_THIN, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "Arial");
    
    	// Bereiche
    	CRect		client_rect;
    	CRect		content_rect;
    
    	// Bestimmen, wo gezeichnet werden soll
    	GetClientRect(client_rect);
    
    	content_rect = client_rect;
    	content_rect.top+=1;
    	content_rect.right-=2;
    	content_rect.left+=1;
    
    	dc.SetBkMode(TRANSPARENT);							// Alle nicht bemalten Flächen sind durchsichtig
    	dc.SelectObject(m_Font);							// Schriftart laden
    
    	dc.FillSolidRect( client_rect, m_backgroundColor );	// Hintergrund malen
    
    	// Titelleiste zeichnen
    	//
    		// Hintergrund zeichnen
    		HPEN	border_pen	= CreatePen( PS_SOLID,0,m_darkGREY );	SelectObject( dc, border_pen );
    		HBRUSH	backg_fill	= CreateSolidBrush( m_systemGREY );		SelectObject( dc, backg_fill);
    
    		Rectangle(	dc, 
    					content_rect.left, 
    					content_rect.top, 
    					content_rect.right, 
    					content_rect.top+row_height);
    
    		// Spalten und Spaltenbeschriftung
    		int x = content_rect.left;
    
    		for( int i=0; i<myCols.size(); i++ )
    		{
    			// Beschriftung
    			dc.TextOut(x+5,content_rect.top+1,myCols[i].title);
    
    			// Trennlinie
    			x	+=	myCols[i].width;
    
    			dc.MoveTo( x, content_rect.top);
    			dc.LineTo( x, content_rect.top+row_height	);
    		}
    
    	// Content
    	//
    		// Hintergrundfarbe wählen
    		backg_fill	= CreateSolidBrush( m_backgroundColor );	SelectObject( dc, backg_fill);
    
    		int y = content_rect.top+row_height+2;
    
    		// Rahmen für die Zeilen
    		for( i=0; i<m_iVisibleLines; i++)
    		{
    			Rectangle(	dc, 
    						content_rect.left, 
    						y, 
    						content_rect.right, 
    						y+row_height);
    
    			y+=row_height-1;
    		}
    
    		// Rahmen für die Spalten
    		border_pen	= CreatePen( PS_SOLID,0,m_darkGREY );		SelectObject( dc, border_pen);
    		x = content_rect.left;
    
    		for( i=0; i<myCols.size()-1; i++ )
    		{
    			x	+=	myCols[i].width;
    
    			dc.MoveTo( x, content_rect.top+row_height+4);
    			dc.LineTo( x, y	);
    		}
    
    		// Content eintragen
    		CString data;
    		y = content_rect.top+row_height+2;
    
    		for( i=m_iFirstLine; i<row_data_set.size(); i++)
    		{
    			x = content_rect.left;
    
    			for( int j=0; j<3; j++ )
    			{
    				if(j==0) data = row_data_set[i].data1;
    				if(j==1) data = row_data_set[i].data2;
    				if(j==2) data.Format("%.3f",row_data_set[i].data3); 
    
    				dc.TextOut(x+6,y+1,data);
    				x	+=	myCols[j].width;
    			}
    
    			y+=row_height-1;
    		}
    

  • Mod

    Das wundert mich nicht. Du erzeugst einen Font, selektierst diesen in den DC und dann wird dieser Font nicht wieder aus dem DC entfernt. Dadurch kann der Font auch nicht zerstört werden.

    Also immer bei einem SelectObject, den Rückgabewert merken und später (vor dem Ende der OnPaint Routine) wieder den alten Wert selektieren.

    Außerdem sehe ich nicht, dass der Font wieder zerstört wird.
    Erzeuge den Font doch nur einmal.

    CFont *pOldFont = dc.SelectObject(&m_Font);                          
    ...
    dc.SelectObject(pOldFont);
    


  • Hallo Martin,
    vielen Dank für deinen Beitrag.
    Ich konnte das Problem gestern lösen und dein Beitrag ist Teil der Lösung.

    Was ich jetzt anders mache:

    CPen *pen1 = new CPen;			
    		pen1->CreatePen( PS_SOLID,0,RGB(0,0,0) );
    		dc->SelectObject(pen1);
    
    [...]
    
    pen1->DeleteObject();			
    delete pen1;
    

    Das für alle CBrush, CPen & CFont.

    Grüße,
    Michael


  • Mod

    1. Hast Du nicht gelesen wie es richtig geht. Denn auch in diesem Fall bleibt der CPen in dem DC selektiert.
    2. Du brauchst die CPen Objekte nicht mit new erzeugen. Das kostet nur Zeit. Erzeuge sie wie bisher auf dem Stack...
    3. Das explizite Aufrufen von DeleteObject ist nicht noitwendig, das besorgt der Destruktor.

    CPen pen1;
    pen1.CreatePen( PS_SOLID,0,RGB(0,0,0) );
    CPen *pPenOld = dc->SelectObject(&pen1);
    
    [...]
    
    dc->SelectObject(pPenOld);
    

Anmelden zum Antworten