Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS General Discussion » Transparent background on custom control Collapse All
Subject Author Date
Bart Kampers Jan 23, 2009 - 2:41 AM

Hello,


 


I derived a custom control from CWnd. I override OnEraseBkgnd and OnPaint to do my own drawings. When I use this control in an ordinary MFC application it has a transparent background. But when I use it in a Prof-UIS application the background is white.


 


How can I have a transparent background in Prof-UIS also?


 


Kind regards,


 


Bart.

Carsten Pedersen Feb 20, 2012 - 6:50 AM

Hi - I have implemented this functionality into my custom control, and it works great. Since my dialog application is non-resizable I don’t have a problem with the custom control not being derived from CExtResizableDialog.
However, if I choose to make a resizable dialog, then I reckon I must derive all controls from the CExtResizableDialog ? And then we have the ::OnPaint problem again, with the CPaintDC I assume?

Best regards,

Carsten Pedersen

Technical Support Feb 21, 2012 - 2:23 AM

The resizable dialog behavior is not a problem. The CExtPaintManager::PaintDockerBkgnd() method provides a themed background to any control at any nested level. The background content is drawn using the dialog coordinate system. The dialog size is not important.

Carsten Pedersen Feb 22, 2012 - 2:12 AM

Hi,


I think you misunderstood; If I derive a control from CExtResizableDialog, then the ::OnPaint method will not work with the CPaintDC, and thus flickering will occur. If I derive from CWnd, then it will work as described below. But then it won’t be resizable using ProfUIS methods, will it?

Technical Support Feb 23, 2012 - 2:16 AM

The CExtResizableDialoig class handles the WM_PAINT message in the WindowProc() virtual method. Please override the WindowProc() method in your dialog class and implement painting code here.

#if (!defined __EXT_MEMORY_DC_H)
    #include <../Src/ExtMemoryDC.h>
#endif


. . .

    virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam ) 
    {
        if( message == WM_PAINT )
        {
                CPaintDC dcPaint( this );
                CRect rcClient;
                GetClientRect( &rcClient );
                CExtMemoryDC dc( &dcPaint, &rcClient );
                COLORREF clrBackground = GetBkColor();
                bool bTransparent = false;
                if( PmBridge_GetPM()->GetCb2DbTransparentMode(this) && ( clrBackground == COLORREF(-1L) ) )
                {
                    CExtPaintManager::stat_ExcludeChildAreas( dc, GetSafeHwnd(), CExtPaintManager::stat_DefExcludeChildAreaCallback );
                    if( PmBridge_GetPM()->PaintDockerBkgnd( true, dc, this ) )
                        bTransparent = true;
                if( ( ! bTransparent) && clrBackground != COLORREF(-1L) )
                    dc.FillSolidRect( &rcClient, clrBackground );    
                }

                //
                //
                // draw custom things into dc here (not into dcPaint)
                //
                //

                PmBridge_GetPM()->OnPaintSessionComplete( this );
        return __super::WindowProc( message, wParam, lParam );
    }

Technical Support Jan 26, 2009 - 11:40 AM

The code snippet in your message looks incorrectly formatted or as a result of incorrect copy or paste. We can’t understand which of lines in it are those relevant last 3 lines.

Technical Support Jan 23, 2009 - 12:44 PM

All the Prof-UIS controls are written with care to flicker free painting. All the container windows in Prof-UIS are created with the WS_CLIPSIBLINGS | WS_CLIPCHILDREN window styles and we strongly recommend to set these styles in all your dialog template resources. So, your window should simply return TRUE from the WM_ERASEBKGND message handler. The WM_PAINT message handler should look like this:

#if (!defined __EXT_MEMORY_DC_H)
      #include <../Src/ExtMemoryDC.h>
#endif

void CYourWnd::OnPaint() 
{
      ASSERT_VALID( this );
CPaintDC dcPaint( this );
CRect rcClient;
      GetClientRect( &rcClient );
      if( rcClient.IsRectEmpty() )
            return;
CExtMemoryDC dc( &dcPaint, &rcClient );
      DrawEntireYourWnd( dcPaint, rcClient );
}

Where the DrawEntireYourWnd() method looks like:
void CYourWnd::DrawEntireYourWnd( CDC & dc, CRect rcClient )
{
      ASSERT_VALID( this );
      DrawBackgroundOfYourWnd( dcPaint, rcClient );
      DrawContentOfYourWnd( dcPaint, rcClient );
}

Where the DrawBackgroundOfYourWnd() and DrawContentOfYourWnd() methods look like:
void CYourWnd::DrawBackgroundOfYourWnd( CDC & dc, CRect rcClient )
{
      ASSERT_VALID( this );
bool bThemedBackgroundPainted = false;
      if(         g_PaintManager->GetCb2DbTransparentMode(this)
            &&    g_PaintManager->PaintDockerBkgnd( true, dc, this )
            )
            bThemedBackgroundPainted = true;
      if( ! bThemedBackgroundPainted )
            dc.FillSolidRect( &rcClient, g_PaintManager->GetColor( CExtPaintManager::CLR_3DFACE_OUT, this )  );
}

void CYourWnd::DrawContentOfYourWnd( CDC & dc, CRect rcClient )
{
      ASSERT_VALID( this );
      //
      // TO-DO: draw content of your window here
      //
}

But the good implementation of custom control should also handle surface printing.
LRESULT CYourWnd::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
{
      if( message == WM_PRINT || message == WM_PRINTCLIENT )
      {
            CDC * pDC = CDC::FromHandle( (HDC)wParam );
            CRect rcClient;
            GetClientRect( &rcClient );
            DrawEntireYourWnd( pDC, rcClient );
            HWND hWndChild = ::GetWindow( m_hWnd, GW_CHILD );
            for( ; hWndChild != NULL; hWndChild = ::GetWindow( hWndChild, GW_HWNDNEXT ) )
            {
                  __EXT_MFC_LONG_PTR dwChildStyle = ::__EXT_MFC_GetWindowLong( hWndChild, GWL_STYLE );
                  if( ( dwChildStyle & WS_VISIBLE ) == 0 )
                        continue;
                  CRect rcChildWnd, rcChildClient, rcStartClient;
                  ::GetClientRect( m_hWnd, &rcStartClient );
                  ::ClientToScreen( hWndChild, ((LPPOINT)(&rcStartClient)) );
                  ::ClientToScreen( hWndChild, ((LPPOINT)(&rcStartClient))+1 );
                  ::GetWindowRect( hWndChild, &rcChildWnd );
                  ::GetClientRect( hWndChild, &rcChildClient );
                  ::ClientToScreen( hWndChild, ((LPPOINT)(&rcChildClient)) );
                  ::ClientToScreen( hWndChild, ((LPPOINT)(&rcChildClient))+1 );
                  CPoint ptChildRenderOffset( 0, 0 );
                  if( ( lParam & PRF_NONCLIENT ) != 0 )
                  {
                        ptChildRenderOffset.x = rcStartClient.left - rcChildWnd.left;
                        ptChildRenderOffset.y = rcStartClient.top - rcChildWnd.top;
                  }
                  else
                  {
                        ptChildRenderOffset.x = rcStartClient.left - rcChildClient.left;
                        ptChildRenderOffset.y = rcStartClient.top - rcChildClient.top;
                  }
                  if( ptChildRenderOffset.x != 0 || ptChildRenderOffset.y != 0 )
                        ::OffsetViewportOrgEx( pDC->m_hDC, -ptChildRenderOffset.x, -ptChildRenderOffset.y, NULL );
                  ::SendMessage( hWndChild, message, (WPARAM)pDC->m_hDC, lParam );
                  if( ptChildRenderOffset.x != 0 || ptChildRenderOffset.y != 0 )
                        ::OffsetViewportOrgEx( pDC->m_hDC, ptChildRenderOffset.x, ptChildRenderOffset.y, NULL );
            }
            return (!0);
      }
      return C_BASE_OF_YourWnd::WindowProc( message, wParam, lParam );
}

You may also need to re-paint your window when the WM_ACTIVATE, WM_NCACTIVATE, WM_ACTIVATEAPP, WM_ENABLE and/or WM_SETTEXT messages received.

Bart Kampers Jan 26, 2009 - 1:49 AM

Thanks for reply. I implemented my control almos as you described except for the DrawBackgroundOfYourWnd part. So I added this piece and my OnPaint now looks like the code below.


 


I noticed that when I leave the last three statements out the background is transparents. When I  then add the "CExtMemoryDC memDC(&paintDC);" statement again the background turns white.


 



void



CClock::OnPaint()this);this); // device context for painting

  CRect rcClient;


  GetClientRect(&rcClient);


 


  {


 


 


    {


      bThemedBackgroundPainted =


    }


 


    {


      paintDC.FillSolidRect(&rcClient, g_PaintManager->GetColor(CExtPaintManager::CLR_3DFACE_OUT,


    }


    CExtMemoryDC memDC(&paintDC);


    Graphics graphics(memDC);


    Paint(graphics);


  }


}


  if (! rcClient.IsRectEmpty())    bool bThemedBackgroundPainted = false;    if (g_PaintManager->GetCb2DbTransparentMode(this) && g_PaintManager->PaintDockerBkgnd(true, paintDC, this))true;    if(! bThemedBackgroundPainted)this));


{


  ASSERT_VALID(


  CPaintDC paintDC(

Bart Kampers Jan 27, 2009 - 1:37 AM

I’m sorry for the unreadable snippet. Here it is again:


 


 


void CClock::OnPaint()

{

  ASSERT_VALID(this);

  CPaintDC paintDC(this); // device context for painting

  CRect rcClient;

  GetClientRect(&rcClient);

  if (! rcClient.IsRectEmpty())

  {

    bool bThemedBackgroundPainted = false;

    if (g_PaintManager->GetCb2DbTransparentMode(this) && g_PaintManager->PaintDockerBkgnd(true, paintDC, this))

    {

      bThemedBackgroundPainted = true;

    }

    if(! bThemedBackgroundPainted)

    {

      paintDC.FillSolidRect(&rcClient, g_PaintManager->GetColor(CExtPaintManager::CLR_3DFACE_OUT, this));

    }


    CExtMemoryDC memDC(&paintDC);

    Graphics graphics(memDC);

    Paint(graphics);

  }

}

Technical Support Jan 27, 2009 - 11:36 AM

The CExtMemoryDC object should be initialized immediately after the CPaintDC object because the themed background should be painted into CExtMemoryDC. We recommend you invoke the GdiFlush() API before initializing the Graphics object.