Re: Paint issues

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



Joseph M. Newcomer a écrit :
On Tue, 09 Oct 2007 13:21:29 +0200, mosfet <john.doe@xxxxxxxxxxxxx> wrote:

Hi,

I am using a control inheriting from CStatic(code provided at then end) but I have one problem when I use it on pocket pc.
I use this CStatic as m_ctlText to display a text VERTICALLY CENTERED and my CStatic is used in a CFormView called CMessageView.

void CMessageView::OnSize(UINT nType, int cx, int cy)
{
TRACE(_T("[0x%x]CMessageView::OnSize(%d, %d, %d)\n"), this, nType, cx, cy);

// call ancestor
CBaseView::OnSize(nType, cx, cy);
//
if ( ::IsWindow(m_ctlText.GetSafeHwnd()) && ::IsWindow(m_hWnd) && (cx > 0) )
{

// Background Image
if (m_ePrevDisplayMode != DRA::GetDisplayMode())
{
// assign bitmap
HBITMAP hBmp = UIManager::GetInstance()->GetBitmap( UIManager::BACKGROUND );
if ( hBmp != NULL ) {
m_ctlText.SetBitmap( hBmp, CxStatic::OriginalSize );
}

// remember now
m_ePrevDisplayMode = DRA::GetDisplayMode();
}

//
m_ctlText.MoveWindow( 0, 0 , cx, cy );
// Scroll bar info
SetScrollSizes( MM_TEXT, CSize(cx, cy) );
}
}

The problem is when I get the virtual keyboard(called SIP - see here http://www.dotnetheaven.com/Uploadfile/jodonnell/SIPOnPocketPC01312006011457AM/Images/PocketPCSIPView1.jpg) to be displayed, because my text is displayed two times one below the other.
One text is displayed centered just before to display the virtual keyboard and the other is the message displayed centered when taking in account the keyboard.

I don't understand why I have the two text displayed because when I look at windows messages I get :

WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_WINDOPOSCHANGED
WM_PAINT
WM_ERASEBKGND
WM_GETTEXTLENGTH
WM_GETTEXT
WM_PAINT
WM_GETTEXTLENGTH
WM_GETTEXT

So when I am in the WM_PAINT I have the right rect values, here is what I get when I my control is displayed for the first time
BEFORE DrawText : 0,0,268,240
BEFORE DrawText : 0,0,268,240

And then when I display the virtual keyboard:
BEFORE DrawText : 0,0,188,240
BEFORE DrawText : 0,0,188,240

So as you can see values seems OK.


I am a bit lost so If you have any suggestion ...

UPDATE : I have found that if if comment the following lines
if (m_ePrevDisplayMode != DRA::GetDisplayMode())
{} used to detect when passing from a landscape to portrait mode
it seems to fix my problem but in this case my image is reloaded several times







********************************************

#include "stdafx.h"
#include "CxStatic.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


#ifndef WM_MOUSELEAVE
#define WM_MOUSELEAVE 0x02A3
#endif

#ifndef DestroyCursor
#define DestroyCursor DestroyIcon
#endif



///////////////////////////////////////////////////////////////////////////////
// ctor
CxStatic::CxStatic()
{
hinst_msimg32 = NULL;
//m_strText = _T("");
m_bTransparentBk = FALSE;
m_bAutoWrapping = TRUE;
m_bAutoAdjustFont = FALSE;
m_bNotifyParent = FALSE;
m_bRounded = TRUE;
m_rgbText = ::GetSysColor(COLOR_WINDOWTEXT);
m_rgbBkgnd = ::GetSysColor(COLOR_CAPTIONTEXT);
****
Just an observation: if the user changes color schemes after the window class is created,
you will not follow the change. Do not get these colors until the actual paint event!
****
m_cr3DHiliteColor = RGB(0,0,255);
m_rgbTransparent = 0xFF000000;
m_EDispMode = 0;
m_pBrush = new CBrush(m_rgbBkgnd);
m_fillmode = Normal;
m_crHiColor = m_rgbBkgnd;
m_crLoColor = m_rgbBkgnd;
****
See previous comment. Do not obtain colors until the time of painting
****
m_nFontSize = m_nFontSizeVar = 8;
m_csFontFamilly = _T("");
m_bFont3d = FALSE;

m_hBitmap = NULL;
m_bBitmap = FALSE;
m_nResourceID = -1;
m_bHover = FALSE;
m_bTracking = FALSE;
m_bAllowMove = FALSE;
m_dwTxtFlags = 0;

m_blendfunc.BlendOp = AC_SRC_OVER;
m_blendfunc.BlendFlags = 0;
m_blendfunc.AlphaFormat = 0;
m_blendfunc.SourceConstantAlpha = 128;
m_bAutoSizing = FALSE;

m_strResourceName.Empty();


}

CxStatic::~CxStatic()
{
//TRACE(_T("in CxStatic::~CxStatic\n"));

// Clean up
if (m_pBrush){
delete m_pBrush;
m_pBrush = NULL;
}
if ( m_hBitmap )
::DeleteObject(m_hBitmap);

if ( hinst_msimg32 )
::FreeLibrary( hinst_msimg32 );
}


// CxStatic
BEGIN_MESSAGE_MAP(CxStatic, CStatic)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_MESSAGE(WM_SETTEXT, OnSetText)
ON_MESSAGE(WM_SETFONT, OnSetFont)
ON_WM_SIZE()
END_MESSAGE_MAP()



/////////////////////////////////////////////////////////////////////////////////
//// PreSubclassWindow
void CxStatic::PreSubclassWindow()
{
//TRACE(_T("in CxStatic::PreSubclassWindow\n"));

m_dwTxtFlags = GetStyle();

// get current font
CFont* pFont = GetFont();
if (pFont == NULL){
pFont = CFont::FromHandle( (HFONT) ::GetStockObject(SYSTEM_FONT) );
}

// create the font for this control
LOGFONT lf;
pFont->GetLogFont(&lf);
m_font.CreateFontIndirect(&lf);
****
OK, why are you doing a GetFont and then creating a font absolutely identical to the font
you already have?
****
//this->GetWindowText(m_strText);


Invalidate();
****
Given you have done nothing to affect the drawing, why are you invalidating?
****
//ReconstructFont();
}

void CxStatic::SetMoveable(BOOL moveAble)
{
ModifyStyle(0, SS_NOTIFY);
m_bAllowMove = moveAble;
}

///////////////////////////////////////////////////////////////////////////////
// SetBackgroundColor
void CxStatic::SetBkColor(COLORREF rgbBkgnd, COLORREF rgbBkgndHigh, BackFillMode mode)
{
m_crLoColor = rgbBkgnd;
m_crHiColor = rgbBkgndHigh;
m_fillmode = mode;

m_rgbBkgnd = rgbBkgnd;
if (m_pBrush){
delete m_pBrush;
m_pBrush = new CBrush(m_rgbBkgnd);
}
else
m_pBrush = new CBrush(m_rgbBkgnd);

RedrawWindow();
}

/////////////////////////////////////////////////////////////////////////////////
//// SetTransparent
void CxStatic::SetTransparent(BOOL bTranspMode)
{
m_bTransparentBk = bTranspMode;
RedrawWindow();
}

void CxStatic::SetTextColor(COLORREF col)
{
m_rgbText = col;
RedrawWindow();
}

void CxStatic::SetAutoSizing(BOOL bAutoSizing)
{
m_bAutoSizing = bAutoSizing;
}

void CxStatic::SetAutoAdjustFont(BOOL bAutoAdjustFont)
{
m_bAutoAdjustFont = bAutoAdjustFont;
}

void CxStatic::SetRounded(BOOL bRounded){
m_bRounded = bRounded;
}

/////////////////////////////////////////////////////////////////////////////////
//// FONT

void CxStatic::SetFont(const CString& strFont,int nPointSize, int nWeight,
BOOL bRedraw /*= TRUE*/)
{
LOGFONT lf;
CFont* pFont = NULL;
memset(&lf, 0, sizeof(LOGFONT)); // Zero out the structure.
****
It would be better to write ::ZeroMemory because that is more readable. Or better still,
if you feel a need to zero it, write
LOGFONT lf = {0};
however, there is no need to zero it because the GetLogFont is going to completely
overwrite all the contents, so the zeroing is pointless
****
pFont = GetFont();
if (pFont == NULL){
pFont = CFont::FromHandle( (HFONT) ::GetStockObject(SYSTEM_FONT) );
}
pFont->GetLogFont( &lf );

if (strFont.IsEmpty() == FALSE)
_tcscpy(lf.lfFaceName,strFont); // Set Font Familly
****
Dangerous. You did not check to see if strFont.GetLength() is < sizeof(lf.lfFaceName)
****
if (nPointSize > 0)
lf.lfHeight = nPointSize; // Set Height

lf.lfWeight = nWeight; // Set Weight

SetFont(&lf, bRedraw);
}

void CxStatic::SetFont(LOGFONT *pLogFont, BOOL bRedraw /*= TRUE*/)
{
****
Why not a LOGFONT &? Note this removes the need for the ASSERT and test...
****
ASSERT(pLogFont);
if (!pLogFont)
return;

if (m_font.GetSafeHandle())
m_font.DeleteObject();

LOGFONT lf = *pLogFont;

m_font.CreateFontIndirect(&lf);
****
Why make a copy? Why not CreateFontIndirect(pLogFont)? For a LOGFONT&, you would do
CreateFontIndirect(&logfont)
****
if (bRedraw)
RedrawWindow();
}

void CxStatic::SetFont(CFont *pFont, BOOL bRedraw /*= TRUE*/)
{
ASSERT(pFont);
if (!pFont)
return;

LOGFONT lf;
memset(&lf, 0, sizeof(lf));
****
As already pointed out, since GetLogFont will completely replace the contents of the
LOGFONT structure, zeroing it out seems pointless
****
pFont->GetLogFont(&lf);

SetFont(&lf, bRedraw);
}

LRESULT CxStatic::OnSetFont(WPARAM wParam, LPARAM lParam)
{
LRESULT lrReturn(Default());

SetFont(CFont::FromHandle((HFONT)wParam) );

RedrawWindow();

return lrReturn;
}


void CxStatic::SetFont3D(BOOL bFont3D, Type3D type)
{
m_bFont3d = bFont3D;
m_3dType = type;

RedrawWindow();
}




LRESULT CxStatic::OnSetText(WPARAM wParam, LPARAM lParam)
{
LRESULT lRet = Default();



Invalidate();

return lRet;
}

BOOL CxStatic::SetBitmap(HBITMAP hBitmap, ImageSize Emode, COLORREF rgbTransparent)
{
m_bBitmap = TRUE;

if ( m_hBitmap ) {
::DeleteObject(m_hBitmap);
}
m_hBitmap = hBitmap;

//if (Emode == OriginalSize){
// CRect Rect;
// GetWindowRect(&Rect); // x,y -> screen
// ScreenToClient(&Rect); // screen -> to client ( view ou dialog)
// Rect.InflateRect(Rect.Width(),Rect.Height());
// SetWindowPos( NULL,0,0,Rect.Width(),Rect.Height(),SWP_NOMOVE | SWP_NOZORDER); //
//}

Invalidate();

return ::GetObject(m_hBitmap, sizeof(BITMAP), &m_bmInfo);
}

BOOL CxStatic::SetBitmap(UINT nIDResource, ImageSize Emode, COLORREF rgbTransparent)
{
m_nResourceID = nIDResource;
m_strResourceName.Empty();
m_bTransparentBk = FALSE;

HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(nIDResource),
IMAGE_BITMAP,
0,0,
LR_DEFAULTCOLOR);

if (!hBmp) return FALSE;
return CxStatic::SetBitmap(hBmp, Emode, rgbTransparent);
}

BOOL CxStatic::SetBitmap(LPCTSTR lpszResourceName, ImageSize Emode, COLORREF rgbTransparent)
{
m_nResourceID = -1;
m_strResourceName = lpszResourceName;

#ifndef UNDER_CE
HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
lpszResourceName,
IMAGE_BITMAP,
0,0,
LR_DEFAULTCOLOR);
#else
HBITMAP hBmp = ::SHLoadImageFile( lpszResourceName );
if (!hBmp) return FALSE;
#endif

return CxStatic::SetBitmap(hBmp, Emode, rgbTransparent);
}



void CxStatic::Format(LPCTSTR szFmt, ...)
{
ULONG bytesWriten;
TCHAR szBuffer[2048];
****
You should not need a temporary buffer of any size. Use

CString Buffer;
Buffer.FormatV(szFmt, args);
****
va_list args;

va_start(args, szFmt);
bytesWriten = _vstprintf(szBuffer, szFmt, args);

SetWindowText( szBuffer );

va_end(args);

RedrawWindow();
}

void CxStatic::AppendText(LPCTSTR szFmt, ...)
{
ULONG bytesWriten;
TCHAR szBuffer[2048];
va_list args;
CString strTmp;

GetWindowText(strTmp);

va_start(args, szFmt);
bytesWriten = _vstprintf(szBuffer, szFmt, args);
va_end(args);

strTmp += szBuffer;
SetWindowText( strTmp );

RedrawWindow();
}


BOOL CxStatic::RedrawWindow()
{
Invalidate();
return TRUE;
}

void CxStatic::OnPaint()
{
CPaintDC dc(this); // device context for painting
CBitmap bmp;
CBitmap* pOldBitmap = NULL;
CString strText;


// GET Client area
CRect rect;GetClientRect(rect);
m_rc = rect;

//Double Buffering - Modify MemDC for transparent background but doesn't work
// because I have to invalidate parent when SetWindowText - Need to find a fix!!!
//pDC->SetBkColor(m_rgbBkgnd);
CMemDC MemDC(&dc, &rect, m_bTransparentBk);


// PAINT SOLID BACKGROUND IF NO BITMAP
if ( !m_bBitmap){
if ( !m_bTransparentBk ){
if (m_fillmode == Normal)
MemDC.FillRect(&rect, m_pBrush);
else
DrawGradientFill(&MemDC, &rect, m_fillmode);
}
}
else{// DISPLAY BACKGROUND BITMAP
//GetWindowText( strText);
DrawBitmap(&MemDC, &rect);
}

// TEXT RENDERING
GetWindowText( strText);
CFont* pOldFont = MemDC.SelectObject( &m_font );
COLORREF rgbText = MemDC.SetTextColor(m_rgbText);

TRACE(_T("BEFORE DrawText : %d,%d,%d,%d\n"),rect.top, rect.left, rect.bottom, rect.right );
MemDC.DrawText( strText, &rect, DT_LEFT|DT_VCENTER|DT_CENTER);

//CxStatic::DrawText( &MemDC, &rect, strText );
****
But having drawn the text to the MemDC, where do you BitBlt it to the actual window? ****
// Restore DC's State
MemDC.SelectObject(pOldFont);
MemDC.SetTextColor(rgbText);
****
Instead of all these 'old' values, just use SaveDC() and RestoreDC() to save everything.
See my essay on SaveDC/RestoreDC on my MVP Tips site.
****
}







void CxStatic::DrawBitmap(CDC* pDCMem, CRect* pRect)
{
CRect rect;
GetClientRect( rect );
BOOL bRet = FALSE;

if (!m_hBitmap)
return;

CDC dcMem;
VERIFY( dcMem.CreateCompatibleDC(pDCMem) );
m_bTransparentBk = FALSE;

// Select bitmap
HBITMAP* pBmpOld = (HBITMAP*) ::SelectObject(pDCMem->m_hDC, m_hBitmap);



pDCMem->StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(),
&dcMem, 0, 0, m_bmInfo.bmWidth, m_bmInfo.bmHeight,
SRCCOPY);

}




///////////////////////////////////////////////////////////////////////////////
// OnEraseBkgnd
BOOL CxStatic::OnEraseBkgnd(CDC* pDC)
{
Invalidate(FALSE);
****
Invalidate is pointless; this only forces unnecessary drawing. And this is why you are
getting two copies; you are not erasing the old one. I don't follow all the conditions in
your OnPaint, but it looks like there might be a path that does not fully redraw the
background.
****
return FALSE;
}



void CxStatic::OnSize(UINT nType, int cx, int cy)
{
TRACE( _T("CxStatic::OnSize(%d,%d,%d)\n"), nType, cx,cy );


CStatic::OnSize(nType, cx, cy);
Invalidate();
}
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Thanks for the lesson.
.



Relevant Pages

  • [PATCH 2.6.17.13] display: Driver ks0108 and cfag12864b
    ... Adds support for additional "display" devices, like small LCD screens. ... +void cfag12864b_E(unsigned char _State) ... +void cfag12864b_CS1 ...
    (Linux-Kernel)
  • Re: Paint issues
    ... I use this CStatic as m_ctlText to display a text VERTICALLY CENTERED ... void CxStatic::PreSubclassWindow ... LOGFONT lf; ... void CxStatic::Format(LPCTSTR szFmt, ...) ...
    (microsoft.public.vc.mfc)
  • Paint issues
    ... One text is displayed centered just before to display the virtual keyboard and the other is the message displayed centered when taking in account the keyboard. ... void CxStatic::PreSubclassWindow ... BOOL CxStatic::SetBitmap(UINT nIDResource, ImageSize Emode, COLORREF rgbTransparent) ... void CxStatic::Format(LPCTSTR szFmt, ...) ...
    (microsoft.public.vc.mfc)
  • [PATCH 2/2] display: Driver ks0108 and cfag12864b
    ... Adds support for additional "display" devices, ... +static const unsigned int FirstMinor = 0; ... +void cfag12864b_E(unsigned char _State) ... +void cfag12864b_CS1 ...
    (Linux-Kernel)
  • Re: ? Copying Fonts and Changing Font Attributes
    ... Well it worked like a charm, ... void blah::SetItalics{ ... LOGFONT lf; ... Alec S. ...
    (microsoft.public.vc.mfc)