Link to home
Start Free TrialLog in
Avatar of Thomas Stockbruegger
Thomas StockbrueggerFlag for Germany

asked on

Need some help with SetBkMode(TRANSPARENT) and OnTimer

In OnCreate(LPCREATESTRUCT lpCreateStruct) of my View Class I put the timer and create the Static Text
     

  CStatic *pStatic=new CStatic;
        pStatic->Create(_T(""),WS_CHILD|WS_VISIBLE|SS_CENTER,CRect(10,1,150,50),this,IDC_STATIC_TEXT);

      //---------------- für Datum / KW / Zeit ---------------
      SetTimer(1,1000,NULL);  // siehe OnTimer
      //------------------------------------------------------




In OnTimer(UINT nIDEvent) I wrote the following :


     CTime time=CTime::GetCurrentTime();
     m_str_Zeit  = time.Format("%H:%M:%S  ");
     m_str_Datum = time.Format("%d.%m.%Y  KW:");
     m_str_KW    = time.Format("%U");

   
        GetDlgItem(IDC_STATIC_TEXT)->SetWindowText(m_str_Zeit+m_str_Datum+m_str_KW);
       CRect rect;
       GetDlgItem(IDC_STATIC_TEXT)->GetWindowRect(&rect);
       ScreenToClient(&rect);
       InvalidateRect(&rect);
       UpdateWindow();



      

In OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) I did the following:
{
      HBRUSH hbr = CView::OnCtlColor(pDC, pWnd, nCtlColor);

      if(pWnd->GetDlgCtrlID()==IDC_STATIC_TEXT)
      {
            pDC->SetBkMode(TRANSPARENT);
            return reinterpret_cast<HBRUSH>(::GetStockObject(NULL_PEN));
            
      }
      else
      {
            return hbr;
      }


}

The problem:  I would like to show the user the date and time (time running) . I have the transparent text but you see a rectangle in white blinking. How can I fix this?
Avatar of sarabande
sarabande
Flag of Luxembourg image

what kind of view are you using? if it is a formview you better add the static control into the dialog resource.

if it is not a formview you may move the creation of the static control into the OnInitialUpdate function. you also should use a member (pointer or object) such that the control could be freed or deleted when you close the view.

the call of UpdateWindow would send a WM_PAINT message to the view window what probably is responsible for the wrong display. you may try instead:

CWnd * pStatic = GetDlgItem(IDC_STATIC_TEXT);
pStatic->SetWindowText(strCurrentTime);
pStatic->UpdateWindow();

Open in new window


if that doesn't work either, you might try to not using a CStatic but use the OnDraw function of your view to write the new time with DrawText directly to the view's surface. use a member of your view class to decide whether you should draw the whole view or only update the timer.

Sara
Avatar of Thomas Stockbruegger

ASKER

Hello Sara,
thank you for your answer.
This looks better.... no blinking rectangle but the same problem that I had before with dc.textout:
take a look at my bitmap. The time is writing all over .User generated image

CWnd * pStatic = GetDlgItem(IDC_STATIC_TEXT);
pStatic->SetWindowText(strCurrentTime);
pStatic->UpdateWindow();

if that doesn't work either, you might try to not using a CStatic but use the OnDraw function of your view to write the new time with DrawText directly to the view's surface. use a member of your view class to decide whether you should draw the whole view or only update the timer.

Also I do not know why I don´t even stop at OnDraw with a breakpoint. So I can not draw anything there.

use a member of your view class to decide whether you should draw the whole view or only update the timer.
I do not know how to do this.



void CStockbrueggerView::OnDraw(CDC* pDC)
{
      CStockbrueggerDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);

           Int x=0;  //try to stop here with breakpoint
I only can draw something in OnPaint to the viewscreen
This problem is only with the TRANSPARENT.
When I remove  the TRANSPARENT for the Static Text in OnCtlColor(pDC, pWnd, nCtlColor);
I will get a running clock. Take a look at my picture. But this looks not nice. I would like see my background of the View screen.
User generated image
I only can draw something in OnPaint to the viewscreen
but in your picture you are drawing the date/time to the view screen. an mfc view has a virtual OnDraw function which was called as a handler to the WM_PAINT message.

if you first draw the picture and second draw the text of the time info, you should have no issues with the transparent background.

to get only the time info updated (to not get flicker issues) you could evaluate the invalid rectangle in the OnDraw. that way you only would draw the part of the picture which is covered by the time info text (in order to clear the old time info) and then draw the text of the new info.

i think, the OnCtlColor didn't work correctly because the picture and the static control were not drawn in the correct order. is the picture also a control? if so, you might have better luck as two child controls of a view would be drawn in tab order what simply is the order the controls were subclassed.  subclassing of controls was done in a dialog or formview in the OnInitDialog respectively the OnInitialUpdate function. if you create controls on the fly you would need to assign the controls yourself and/or add an own WindowsProc function that evaluates the windows messages. that is why you should consider to using a CFormView as a base even if you were drawing only pictures. if the picture was drawn to a (huge) owner-draw button or to a frame control instead of painting it directly to the client area of the view, the clock control could be placed directly above the picture control and and subclassing + drawing should work as expected as the OnCtlColor would be called for the static control.

Sara
but in your picture you are drawing the date/time to the view screen. an mfc view has a virtual OnDraw function which was called as a handler to the WM_PAINT message.

I draw the background and text only in OnPaint. Any code in OnDraw will not execude, if I put there a breakpoint I got not stop!
So I do not know how to change that.
Any code in OnDraw will not execute
if you were overwriting the OnPaint the default view handling was not executed since the OnDraw function would be called from the CView::OnPaint (or CScrollView::OnPaint or CFormView::OnPaint).

so, you should comment your own implementation of OnPaint (and comment the entry in the MESSAGE_MAP if any) and if OnDraw was called then, move the drawing code from OnPaint to OnDraw.

is the view part of an SDI or MDI solution? such that you were using a doctemplate to creating a triple of document, frame and view?

did you derive an own view class from CView and are you using CMainFrame and or a CMDIChildWnd derived frame class which is parent of your view?

generally, also the YourView::OnPaint should be able to draw a time info text above a picture. the difficulty is to save the picture in the rectangle where the time info would be drawn and restore only this part if the time was updated. MFC can't help you with this if picture and time info is not in child controls.

Sara
I think I have a SDI, with CMainFrame, CDocument, and CView.

did you derive an own view class from CView
NO


This is a short version of my OnPaint()
void CStockbrueggerView::OnPaint()
{
	CPaintDC dc(this); // device context for painting
  
	
	CBitmap x_bitmap; 
		    CDC MemDCBild;

 

		 
			if(m_Hintergrundbild==0) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_FIRMA_CLASSIC);
			if(m_Hintergrundbild==1) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_FIRMA_CLASSIC);
			if(m_Hintergrundbild==2) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_BOAT);
		        if(m_Hintergrundbild==3) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_MONUMENT_VALLEY);
			if(m_Hintergrundbild==4) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_MALEDIVEN);
	    	        if(m_Hintergrundbild==5) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_NEUSCHWANSTEIN);
			if(m_Hintergrundbild==6) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_NEW_YORK);
	                if(m_Hintergrundbild==7) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_VOGEL);
		        if(m_Hintergrundbild==8) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_WING);
			if(m_Hintergrundbild==9) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_WEIHNACHTEN1);
                        if(m_Hintergrundbild==10) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_WINTER_BARN);
			if(m_Hintergrundbild==11) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_KERMIT);
			if(m_Hintergrundbild==12) x_bitmap.LoadBitmap(IDB_BITMAP_HINTERGRUNDBILD_PYRENEES);
			 
			 
			 
			 
			 
			 
 
			MemDCBild.CreateCompatibleDC(&dc);
    
                        CBitmap *BmpPrevious = MemDCBild.SelectObject(&x_bitmap);
                       dc.BitBlt(0,0,2500,1000,&MemDCBild,0,0,SRCCOPY);
                      MemDCBild.SelectObject( BmpPrevious );
                      x_bitmap.DeleteObject();

                  .
                  .
                  .
                  .
                  .
}

Open in new window

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   .
   .
   .
      if (!m_wndDlgBar.Create(this, IDR_MAINFRAME,
            CBRS_ALIGN_TOP, AFX_IDW_DIALOGBAR))
      {
            TRACE0("Dialogfeldleiste konnte nicht erstellt werden\n");
            return -1;            // Fehler bei Erstellung
      }


If the time will not work with the Cview Class, is it possible to set the time to IDR_MAINFRAME, because of the background there is no problem with the transparent mode. But how can I draw or textout the time there ?
User generated image

User generated image
sara,
I found a way, that was easy.
I have enclosed OnPaint() at my CMainFrame and also the timer.
I have used the m_wndDlgBar for that.

//###########################################################
void CMainFrame::OnPaint()
{
      CPaintDC dc(this); // device context for painting
      m_wndDlgBar.GetDlgItem(IDC_STATIC_TEXT)->SetWindowText(m_str_Zeit+m_str_Datum+m_str_KW);
}
//###########################################################
void CMainFrame::OnTimer(UINT nIDEvent)
{
      
 

      

       CTime time=CTime::GetCurrentTime();
       m_str_Zeit  = time.Format("%H:%M:%S  ");
       m_str_Datum = time.Format("%d.%m.%Y  KW:");
       m_str_KW    = time.Format("%U");

       m_wndDlgBar.GetDlgItem(IDC_STATIC_TEXT)->SetWindowText(m_str_Zeit+m_str_Datum+m_str_KW);


      


      



      CFrameWnd::OnTimer(nIDEvent);
}
//###########################################################
User generated image
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you for your help.
Best regards.
Thomas