Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. How do I write red text to a CDialogBar?

How do I write red text to a CDialogBar?

Scheduled Pinned Locked Moved C / C++ / MFC
questiongraphicstutorial
6 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    IlanTal
    wrote on last edited by
    #1

    I have a dialog bar (similar to a dialog box) where I have a number of different objects. Now I have a request to write the patient name in a large font in red. I don't have a clue how to do this. Usually one uses OnDraw(CDC *pDC) where the pDC allows you to draw what you want. For a dialog bar or a dialog box there is no OnDraw and the system does the work for you. The only way I can think of is to make a bitmap file, where I draw into the bitmap what I want and then I display the bitmap as a picture. This is awkward especially as the program will generally be run from a CD which has no write possibilities. There must be a better way, the question is can anyone suggest what it is? Thanks, Ilan

    O 1 Reply Last reply
    0
    • I IlanTal

      I have a dialog bar (similar to a dialog box) where I have a number of different objects. Now I have a request to write the patient name in a large font in red. I don't have a clue how to do this. Usually one uses OnDraw(CDC *pDC) where the pDC allows you to draw what you want. For a dialog bar or a dialog box there is no OnDraw and the system does the work for you. The only way I can think of is to make a bitmap file, where I draw into the bitmap what I want and then I display the bitmap as a picture. This is awkward especially as the program will generally be run from a CD which has no write possibilities. There must be a better way, the question is can anyone suggest what it is? Thanks, Ilan

      O Offline
      O Offline
      ovidiucucu
      wrote on last edited by
      #2

      First of all, few aside notes:

      • A dialog bar is not quite similar to a dialog box, although both can be based on a dialog template. That because CDialogBar is not derived from CDialog but from CControlBar.
      • OnDraw is a virtual member function of CView which is called from within WM_PAINT message handler (OnPaint). Neither CDialog, nor CDialogBar have OnDraw method.
      • If you need a text in a dialog box or a dialog bar is easier to put it in a static or edit control rather than drawing it in WM_PAINT message handler.

      Given these said, I would like to suggest to derive from CDialogBar, make some "cosmetics", i.e. adding WM_INITDIALOG message handler (CDialogBar has not OnInitDialog virtual function like CDialog), change the edit's font in that handler, and finally set the edit's text color in WM_CTLCOLOR message handler. Here is a sample code:

      // MyDialogBar.h
      class CMyDialogBar : public CDialogBar
      {
      // Construction
      public:
         CMyDialogBar();
         
      // ...
      // Implementation
      protected:
         
         // Generated message map functions
         //{{AFX_MSG(CMyDialogBar)
         afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
         //}}AFX_MSG
         afx_msg LRESULT OnInitDialog (WPARAM wParam, LPARAM lParam); // <-- added by hand
         DECLARE_MESSAGE_MAP()
      };
      
      
      // MyDialogBar.cpp
      // ...
      MyDialogBar::CMyDialogBar()
      {
      // ...
      }
      void CMyDialogBar::DoDataExchange(CDataExchange* pDX)
      {
         CDialogBar::DoDataExchange(pDX);
         //{{AFX_DATA_MAP(CMyDialogBar)
         // NOTE: the ClassWizard will add DDX and DDV calls here
         //}}AFX_DATA_MAP
      }
      BEGIN_MESSAGE_MAP(CMyDialogBar, CDialogBar)
         //{{AFX_MSG_MAP(CMyDialogBar)
         ON_WM_CTLCOLOR()
         //}}AFX_MSG_MAP
         ON_MESSAGE(WM_INITDIALOG, OnInitDialog) // <-- added by hand
      END_MESSAGE_MAP()
      
      LRESULT CMyDialogBar::OnInitDialog (WPARAM wParam, LPARAM lParam)
      {
         if (!HandleInitDialog(wParam, lParam) || !UpdateData(FALSE))
         {
            TRACE0("Warning: UpdateData failed during dialog init.\n");
            return (LRESULT)0;
         }
         CFont font;
         font.CreatePointFont(140, _T("Times New Roman"));
         CWnd* pEdit = GetDlgItem(IDC_EDIT_PATIENT);
         _ASSERTE(NULL != pEdit); // something stinks in here!
         pEdit->SetFont(&font); // set the "larger" font
         font.Detach();
      
         return (LRESULT)1;
      }
      HBRUSH CMyDialogBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
      {
         HBRUSH hbr = CDialogBar::OnCtlColor(pDC, pWnd, nCtlColor);
         if(pWnd->m_hWnd == GetDlgItem(IDC_EDIT_PATIENT)->GetSafeHwn
      
      I 1 Reply Last reply
      0
      • O ovidiucucu

        First of all, few aside notes:

        • A dialog bar is not quite similar to a dialog box, although both can be based on a dialog template. That because CDialogBar is not derived from CDialog but from CControlBar.
        • OnDraw is a virtual member function of CView which is called from within WM_PAINT message handler (OnPaint). Neither CDialog, nor CDialogBar have OnDraw method.
        • If you need a text in a dialog box or a dialog bar is easier to put it in a static or edit control rather than drawing it in WM_PAINT message handler.

        Given these said, I would like to suggest to derive from CDialogBar, make some "cosmetics", i.e. adding WM_INITDIALOG message handler (CDialogBar has not OnInitDialog virtual function like CDialog), change the edit's font in that handler, and finally set the edit's text color in WM_CTLCOLOR message handler. Here is a sample code:

        // MyDialogBar.h
        class CMyDialogBar : public CDialogBar
        {
        // Construction
        public:
           CMyDialogBar();
           
        // ...
        // Implementation
        protected:
           
           // Generated message map functions
           //{{AFX_MSG(CMyDialogBar)
           afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
           //}}AFX_MSG
           afx_msg LRESULT OnInitDialog (WPARAM wParam, LPARAM lParam); // <-- added by hand
           DECLARE_MESSAGE_MAP()
        };
        
        
        // MyDialogBar.cpp
        // ...
        MyDialogBar::CMyDialogBar()
        {
        // ...
        }
        void CMyDialogBar::DoDataExchange(CDataExchange* pDX)
        {
           CDialogBar::DoDataExchange(pDX);
           //{{AFX_DATA_MAP(CMyDialogBar)
           // NOTE: the ClassWizard will add DDX and DDV calls here
           //}}AFX_DATA_MAP
        }
        BEGIN_MESSAGE_MAP(CMyDialogBar, CDialogBar)
           //{{AFX_MSG_MAP(CMyDialogBar)
           ON_WM_CTLCOLOR()
           //}}AFX_MSG_MAP
           ON_MESSAGE(WM_INITDIALOG, OnInitDialog) // <-- added by hand
        END_MESSAGE_MAP()
        
        LRESULT CMyDialogBar::OnInitDialog (WPARAM wParam, LPARAM lParam)
        {
           if (!HandleInitDialog(wParam, lParam) || !UpdateData(FALSE))
           {
              TRACE0("Warning: UpdateData failed during dialog init.\n");
              return (LRESULT)0;
           }
           CFont font;
           font.CreatePointFont(140, _T("Times New Roman"));
           CWnd* pEdit = GetDlgItem(IDC_EDIT_PATIENT);
           _ASSERTE(NULL != pEdit); // something stinks in here!
           pEdit->SetFont(&font); // set the "larger" font
           font.Detach();
        
           return (LRESULT)1;
        }
        HBRUSH CMyDialogBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
        {
           HBRUSH hbr = CDialogBar::OnCtlColor(pDC, pWnd, nCtlColor);
           if(pWnd->m_hWnd == GetDlgItem(IDC_EDIT_PATIENT)->GetSafeHwn
        
        I Offline
        I Offline
        IlanTal
        wrote on last edited by
        #3

        Thank you for your reply which I didn't see until this morning. Usually it sends me mail when someone replies and since I received no mail I didn't know that you had replied. I came up with another solution, where basically I make a static text box to receive the information and I invalidate it whenever I need to update the information. Unfortunately I can't use the WM_INITDIALOG because the user can change the study. So, I invalidate the static box when I need a change, then validate inside WM_PAINT (which it nicely gives me as a message). Once it is valid, I write on top of the static box with the color and text size which I need. So far, it seems to be doing the job. Here is the code: void CMyToolbar::SetPatInfo(void) { int oldColor, bkgColor, oldMode, fontSize = 160; int i, j; CFont hFont, *hOldFont; CBrush br1; CWnd *wnd1; CSize sz1, sz2; CRect rc1; CString textOut[4]; CDC *pDC; CCardiacDoc *pDoc; CCardiacView *vw = CCardiacView::GetView(); pDoc = vw->GetDocument(); textOut[0] = pDoc->m_patName; if( textOut[0].IsEmpty()) return; textOut[1] = pDoc->m_patID; textOut[2] = pDoc->m_imageData[0].m_acqDateTime.Format("%d-%b-%Y"); textOut[3] = pDoc->m_styName; if( vw->m_masterFlg <= CCardiacView::VW_CARDIAC_DISP2) textOut[3] = "Myocardial Perfusion"; wnd1 = GetDlgItem(IDC_PATINFO); pDC = wnd1->GetDC(); bkgColor = pDC->GetBkColor(); sz1 = 0; for( i=j=0; i< 4; i++) { sz2 = pDC->GetTextExtent(textOut[i]); if( sz2.cx > sz1.cx) { sz1 = sz2; j = i; // j will be the maximum string } } oldColor = pDC->SetTextColor( RGB(255,0,0)); oldMode = pDC->SetBkMode( TRANSPARENT); wnd1->GetClientRect(&rc1); wnd1->ValidateRect(rc1); sz1.cx = rc1.right; sz1.cy = rc1.bottom; br1.CreateSolidBrush(bkgColor); pDC->FillRect(rc1, &br1); while( fontSize > 80) { hFont.CreatePointFont( fontSize, "Ariel", pDC); hOldFont = pDC->SelectObject( &hFont); sz2 = pDC->GetTextExtent(textOut[j]); // the longest one if( sz2.cx <= sz1.cx) break; // found a size pDC->SelectObject( hOldFont); DeleteObject( hFont); hFont.Detach(); fontSize -= 20; // reduce font size by 2 } for( i=j=0; i<4; i++) { if( j+sz2.cy > sz1.cy) break; // no more room pDC->TextOut(0,j,textOut[i]); j += sz2.cy; } pDC->SelectObject( hOldFont); DeleteObject( hFont); pDC->SetTextColor( oldColor); pDC->SetBkMode( oldMode); ReleaseDC(pDC); } void CMyToolbar::OnPaint() { CPaintDC dc(this); // device context for painting SetPatInf

        O 1 Reply Last reply
        0
        • I IlanTal

          Thank you for your reply which I didn't see until this morning. Usually it sends me mail when someone replies and since I received no mail I didn't know that you had replied. I came up with another solution, where basically I make a static text box to receive the information and I invalidate it whenever I need to update the information. Unfortunately I can't use the WM_INITDIALOG because the user can change the study. So, I invalidate the static box when I need a change, then validate inside WM_PAINT (which it nicely gives me as a message). Once it is valid, I write on top of the static box with the color and text size which I need. So far, it seems to be doing the job. Here is the code: void CMyToolbar::SetPatInfo(void) { int oldColor, bkgColor, oldMode, fontSize = 160; int i, j; CFont hFont, *hOldFont; CBrush br1; CWnd *wnd1; CSize sz1, sz2; CRect rc1; CString textOut[4]; CDC *pDC; CCardiacDoc *pDoc; CCardiacView *vw = CCardiacView::GetView(); pDoc = vw->GetDocument(); textOut[0] = pDoc->m_patName; if( textOut[0].IsEmpty()) return; textOut[1] = pDoc->m_patID; textOut[2] = pDoc->m_imageData[0].m_acqDateTime.Format("%d-%b-%Y"); textOut[3] = pDoc->m_styName; if( vw->m_masterFlg <= CCardiacView::VW_CARDIAC_DISP2) textOut[3] = "Myocardial Perfusion"; wnd1 = GetDlgItem(IDC_PATINFO); pDC = wnd1->GetDC(); bkgColor = pDC->GetBkColor(); sz1 = 0; for( i=j=0; i< 4; i++) { sz2 = pDC->GetTextExtent(textOut[i]); if( sz2.cx > sz1.cx) { sz1 = sz2; j = i; // j will be the maximum string } } oldColor = pDC->SetTextColor( RGB(255,0,0)); oldMode = pDC->SetBkMode( TRANSPARENT); wnd1->GetClientRect(&rc1); wnd1->ValidateRect(rc1); sz1.cx = rc1.right; sz1.cy = rc1.bottom; br1.CreateSolidBrush(bkgColor); pDC->FillRect(rc1, &br1); while( fontSize > 80) { hFont.CreatePointFont( fontSize, "Ariel", pDC); hOldFont = pDC->SelectObject( &hFont); sz2 = pDC->GetTextExtent(textOut[j]); // the longest one if( sz2.cx <= sz1.cx) break; // found a size pDC->SelectObject( hOldFont); DeleteObject( hFont); hFont.Detach(); fontSize -= 20; // reduce font size by 2 } for( i=j=0; i<4; i++) { if( j+sz2.cy > sz1.cy) break; // no more room pDC->TextOut(0,j,textOut[i]); j += sz2.cy; } pDC->SelectObject( hOldFont); DeleteObject( hFont); pDC->SetTextColor( oldColor); pDC->SetBkMode( oldMode); ReleaseDC(pDC); } void CMyToolbar::OnPaint() { CPaintDC dc(this); // device context for painting SetPatInf

          O Offline
          O Offline
          ovidiucucu
          wrote on last edited by
          #4

          You have chosen the harder way, but that's it... your choice. However, here are some "first look" remarks:* I put SetFont in WM_INITDIALOG message handler only as an example; you can put it also in any oter place, then call Invalidate() as well.

          • No need to write your own CMyToolbar::Invalidate function, as long as you can directly call Invalidate for the desired control.

            GetDlgItem(IDC_PATINFO)->Invalidate();
            
          • As long as you have not handled WM_PAINT in the static control, but you draw text in it from another place, for sure you'll have troubles after another window will overlap; just test it and see if I'm right.

            Ovidiu

          I 2 Replies Last reply
          0
          • O ovidiucucu

            You have chosen the harder way, but that's it... your choice. However, here are some "first look" remarks:* I put SetFont in WM_INITDIALOG message handler only as an example; you can put it also in any oter place, then call Invalidate() as well.

            • No need to write your own CMyToolbar::Invalidate function, as long as you can directly call Invalidate for the desired control.

              GetDlgItem(IDC_PATINFO)->Invalidate();
              
            • As long as you have not handled WM_PAINT in the static control, but you draw text in it from another place, for sure you'll have troubles after another window will overlap; just test it and see if I'm right.

              Ovidiu

            I Offline
            I Offline
            IlanTal
            wrote on last edited by
            #5

            Again I didn't receive any email to know that you had replied. In fact when I wrote my reply to you, I was convinced that you would never see it since it was so old. I just wrote the reply for the sake of completeness. Not only were you right, you are ABSOLUTELY right in your analysis that I will have troubles since I don't handle WM_PAINT for the static control. Since I thought there was zero chance of anybody seeing this message, I opened a new message. I described exactly what you said would happen. If I continue on with what I started then I need to figure out how to handle the WM_PAINT for the static control. So far, I can't find any way to do this. The static control has no messages which I can override. Since you told me that I need to handle this message (very correctly so!!!), could you please tell me how I get my hands onto it? In parallel I will look into your original solution. Again, I didn't do it by your suggestion because I didn't know you answered so I had to figure out something for myself - and I chose the hard way. I wasn't really serious about the WM_INITDIALOG, just my reply was "dead" in any case. All I needed was something which I could call more than once and where I could set the font size according to the length of the patient name (or the new patient name for the new study). Thanks for all your comments. They are VERY helpfull. Ilan

            1 Reply Last reply
            0
            • O ovidiucucu

              You have chosen the harder way, but that's it... your choice. However, here are some "first look" remarks:* I put SetFont in WM_INITDIALOG message handler only as an example; you can put it also in any oter place, then call Invalidate() as well.

              • No need to write your own CMyToolbar::Invalidate function, as long as you can directly call Invalidate for the desired control.

                GetDlgItem(IDC_PATINFO)->Invalidate();
                
              • As long as you have not handled WM_PAINT in the static control, but you draw text in it from another place, for sure you'll have troubles after another window will overlap; just test it and see if I'm right.

                Ovidiu

              I Offline
              I Offline
              IlanTal
              wrote on last edited by
              #6

              I decided that your method was SO much nicer that I would throw out what I did and use your method. Just for general education if you happen to know how I would capture the WM_PAINT for the static control, it would be nice to know. In any case, I will no longer pursue it so it is of minor importance. I threw out the WM_PAINT message, threw out the invalidateRect and I just call it once. It turns out that I need an initialization routine for setting up the radio buttons depending upon the study type. It was most natural to just call my routine from there (like your WM_INITDIALOG suggestion). My code is simpler now: void CMyToolbar::SetPatInfo(void) { // font size can start at 16 if 3 lines are permitted. // start with font size = 12 for 4 lines. int fontSize = 120; int i, j; CFont hFont, *hOldFont; CWnd *wnd1; CSize sz1, sz2; CRect rc1; CString textOut[4]; CDC *pDC; CCardiacDoc *pDoc; CCardiacView *vw = CCardiacView::GetView(); pDoc = vw->GetDocument(); textOut[0] = pDoc->m_patName; if( textOut[0].IsEmpty()) return; textOut[1] = pDoc->m_patID; textOut[2] = pDoc->m_imageData[0].m_acqDateTime.Format("%d-%b-%Y"); textOut[3] = pDoc->m_styName; if( vw->m_masterFlg <= CCardiacView::VW_CARDIAC_DISP2) textOut[3] = "Myocardial Perfusion"; wnd1 = GetDlgItem(IDC_PATINFO); pDC = wnd1->GetDC(); sz1 = 0; for( i=j=0; i< 4; i++) { sz2 = pDC->GetTextExtent(textOut[i]); if( sz2.cx > sz1.cx) { sz1 = sz2; j = i; // j will be the maximum string } } wnd1->GetClientRect(&rc1); wnd1->SetWindowText(textOut[0] + "\r\n" + textOut[1] + "\r\n" + textOut[2] + "\r\n" + textOut[3]); sz1.cx = rc1.right; sz1.cy = rc1.bottom; while( fontSize > 80) { hFont.CreatePointFont( fontSize, "Ariel", pDC); hOldFont = pDC->SelectObject( &hFont); sz2 = pDC->GetTextExtent(textOut[j]); // the longest one if( sz2.cx <= sz1.cx) break; // found a size pDC->SelectObject( hOldFont); DeleteObject( hFont); hFont.Detach(); fontSize -= 20; // reduce font size by 2 } wnd1->SetFont(&hFont); hFont.Detach(); ReleaseDC(pDC); } I have a question about DeleteObject(hFont). Do I need it in my loop if I use hFont.Detach()? I noticed you didn't use it in your example, so I also didn't use it when I found the font I wanted. Will I add garbage if I change the patient to a new patient? Thanks again, Ilan

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups