Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Newbie, using CDC & CStatic control

1 view
Skip to first unread message

Reyes

unread,
May 7, 2000, 3:00:00 AM5/7/00
to
Hi, sorry if this question seems stupid, I've created a color selector
CComboBoxEX (u can add images to the dropdown list), the idea is to select a
color from it and the color selected will be shown in the Rect area of a
CStatic control, thaks for any (urgent) help.

HBRUSH CBorderDialog::SetBkColor(COLORREF crBkgnd)
{
if (m_hBackBrush)
::DeleteObject(m_hBackBrush);

m_hBackBrush = ::CreateSolidBrush(crBkgnd);

return m_hBackBrush;
}

void CBorderDialog::OnSelchangeFillComboboxex()
{
// TODO: Add your control notification handler code here
int x = m_fillCombo.GetCurSel();
if(x != CB_ERR)


switch (x)


case 0: SetBkColor(NULL); break;
case 1: SetBkColor(RGB(0,0,0)); break;
case 2: SetBkColor(RGB(128,0,0)); break;
case 3: SetBkColor(RGB(0,128,0)); break;
case 4: SetBkColor(RGB(128,128,0)); break;
case 5: SetBkColor(RGB(0,0,128)); break;
case 6: SetBkColor(RGB(128,0,128)); break;
case 7: SetBkColor(RGB(0,128,128)); break;
case 8: SetBkColor(RGB(128,128,128)); break;
case 9: SetBkColor(RGB(192,192,192)); break;
case 10: SetBkColor(RGB(255,0,0)); break;
case 11: SetBkColor(RGB(0,255,0)); break;
case 12: SetBkColor(RGB(255,255,0)); break;
case 13: SetBkColor(RGB(0,0,255)); break;
case 14: SetBkColor(RGB(255,0,255)); break;
case 15: SetBkColor(RGB(0,255,255)); break;
case 16: SetBkColor(RGB(255,255,255)); break;
}
}
}

void CBorderDialog::OnPaint()
{
CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here
CBorderDialog *pWnd = (CBorderDialog*)GetParent();

CRect rc;
CBrush br;
CDC* pDCMem;

This is the member variable CStatic of the Ctrl in which I'm trying to
diplay the color (m_exmpl):

m_exmpl.GetWindowRect(&rc);

if(pWnd)


pDCMem = new CDC;
pDCMem->CreateCompatibleDC(&dc);
CBitmap bmp;
bmp.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
pDCMem->SelectObject(&bmp);

if (m_hBackBrush != NULL)
{ br.Attach(m_hBackBrush);
}
pDCMem->FillRect(pWnd->rc,&br);
br.Detach();
}
// Do not call CDialog::OnPaint() for painting messages
}


Johan Rosengren

unread,
May 7, 2000, 3:00:00 AM5/7/00
to
Reyes <vcv...@hotmail.com> a écrit dans le message :
OYU6Ju#t$GA.328@cppssbbsa04...

> Hi, sorry if this question seems stupid, I've created a color selector
> CComboBoxEX (u can add images to the dropdown list), the idea is to select
a
> color from it and the color selected will be shown in the Rect area of a
> CStatic control, thaks for any (urgent) help.
>

I have asked myself far more stupid questions during my time programming...

Here comes the problems. The first and major one is that each and every
window receives a WM_PAINT message. Below, you are actually trying to redraw
a window in response to another window's WM_PAINT message. This leads to
unprofessional results, and should be avoided. After the commented function,
I will outline how to do it properly :)))

> void CBorderDialog::OnPaint()
> {
> CPaintDC dc(this); // device context for painting
>
> // TODO: Add your message handler code here
> CBorderDialog *pWnd = (CBorderDialog*)GetParent();
>

The above gets the parent of the *dialog box*. As the parent of the dialog
box is not the dialog box itself, you are making a faulty test below. If the
dialog is the main app window, you code will not even be called.

> CRect rc;
> CBrush br;
> CDC* pDCMem;
>
> This is the member variable CStatic of the Ctrl in which I'm trying to
> diplay the color (m_exmpl):
>
> m_exmpl.GetWindowRect(&rc);

Note that GetWindowRect will get the rect in *screen coordinates*. As the
painting calls origin from 0,0, you painting will probably be outside the
window.


>
> if(pWnd)
>
>
> pDCMem = new CDC;
> pDCMem->CreateCompatibleDC(&dc);

You are creating a DC compatible with the parent window, not the window you
draw in. This is inappropriate.

> CBitmap bmp;
> bmp.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
> pDCMem->SelectObject(&bmp);
>
> if (m_hBackBrush != NULL)
> { br.Attach(m_hBackBrush);
> }
> pDCMem->FillRect(pWnd->rc,&br);

What is pWnd->rc supposed to be? As pWnd is a pointer to the parent of the
dialog, but cast to this class, you hav probably a member rc. You also draw
to a memory DC. Nowhere is this memory DC actually transfered to screen. You
have to BitBlt the contents from a memory DC to screen, otherwise it will
never be displayed.

> br.Detach();
> }
> // Do not call CDialog::OnPaint() for painting messages
> }
>

But the above is not a good solution. The complicated version is to create a
CStatic-derived class, and handle WM_PAINT in the derived class instead. In
this case, however, it is far easier to handle the WM_CTLCOLOR message of
the dialog. First, add code to force a redraw of your static when you handle
the combobox change:

void CBorderDialog::SetBkColor(COLORREF crBkgnd)
{
if (m_hBackBrush)
::DeleteObject(m_hBackBrush);

m_hBackBrush = ::CreateSolidBrush(crBkgnd);

// Force a redraw
// I have put the call here, to make sure that the control is redrawn as
// soon as the brush is modified. This way, it will updated even if you
// call the function from a place different than the selchange handler.

// I would prefer a more general approach, such as redrawing the
// main window, but as it will introduce flicker, this must do.

m_exmpl.RedrawWindow();
}

The map WM_CTLCOLOR, an put in the following code:

HBRUSH CBorderDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

if(pWnd->GetDlgCtrlID()==m_exmpl.GetCtrlID && m_hb)
return m_hBackBrush;
return hbr;
}

Johan Rosengren
Responsable Informatique
PACTA S.A.


Tenebrax

unread,
May 7, 2000, 3:00:00 AM5/7/00
to
The best way to avoid painting problem with static control is to derive your
own class from CStatic and make your own paint function... this way
evrything will be fine... (with in your case a SetColor(...) function that
will set a member data telling which color to use... to update the display a
call to Invalidate (that post WM_PAINT) is the good way)

Tenebrax


You wanna see what a bug is?: visit http://graff.ctw.net and download Graff
beta 1.02 (in french, if you want an english version mail me)

Joseph M. Newcomer

unread,
May 7, 2000, 3:00:00 AM5/7/00
to
You are going about this in an unnecessarily complex fashion. Take a
look at sotring the color in the ItemData part. This completely
eliminates the switch statement, which is a fundamentally bad idea for
this purpose. The key to this is to eliminate entirely the
initialization of the combo box in the resource editor (read my essays
on dialog boxes on my MVP Tips site), where I think it is completely
useless for reasons I explain in the essay on combo box
initialization; instead, have a table of pairs, e.g.,

static struct {
UINT id;
COLORREF color; } colors[] = {
{ IDS_BLACK, RGB(0, 0, 0) },
{ IDS_RED, RGB(255, 0, 0)},
... lots of other colors in here...
(0, 0} // end of table
};

You can see some instances of this in the source files from my
download site; or send me email and I'll send you a suite of C++
classes that do this. I have one that selects colors (CColorCombo)
which is a subclass of a mapped-value ComobBox (CIDCombo) which is a
subclass of the combo box which always tries to be big enough to hold
everything (CSmartDropdown) which is a subclass of CComboBox. It puts
the color names and a little drawing of the color in each entry.

The IDs, IDS_RED, etc. are string IDs in the String Table. For details
of why this is a Fundamentally Good Idea, read my essay on "Who Owns
the GUI" on my MVP Tips site. Recognize that your implementation fails
completely when someone internationalizes your application if you had
a sorted combo box. And it isn't too healthy under the best of
conditions, because it is not robust under maintenance.

Then you are doing the painting in the dialog's OnPaint handler; this
would be find for painting the dialog, but you're not; you want to
paint the static control. So you need to subclass the static control
and put the painting logic in this control, where it belongs. What
the dialog does is set a member variable (preferrably a protected
member variable) of the derived CStatic.

BOOL CBorderDialog::OnInitDialog()
{
for(int i = 0; colors[i].id != 0; i++)
{
CString s;
s.LoadString(colors[i].id);
int n = c_Colors.AddString(s);
c_Colors.SetItemData(n, colors[i].color);
}
... whatever else you do here
}

COLORREF CMyStatic::SetBkColor(COLORREF newcolor)
{
COLORREF oldcolor = bkcolor;
bkcolor = newcolor;
InvalidateRect(NULL);
return oldcolor;
}

void CMyStatic::OnPaint()
{
CPaintDC dc(this);
CBrush br(bkcolor);
CRect r;
GetClientRect(&r);
dc.FillRect(&r, &br);
}

I'm not sure what the role of the bitmap is; this seems to be
gratuitous complexity. Particularly because it is created, filled, and
nothing else is done with it, and it is never deleted, so every paint
operation leaks a bitmap that seems to have no connection with the GUI
at all.

The above code will fill the static control with the desired color.
The attach/detach of the brush serves no useful purpose, because you
don't need to do this at all; just create the brush as needed as shown
above.

void CBorderDialog::OnSelchangeFillComboboxex()
{
COLORREF color = c_Colors.GetItemData(c_Colors.GetCurSel());
c_StaticControl.SetBkColor(color);
}

Note how much simpler the code is! You don't need to save the brush,
you don't have a switch statement, the total number of lines of code
is massively smaller, the code is simpler, and it is easier to
maintain and understand. It can be readily internationalized. Note
that if you needed the brush saved as a member, saving the handle of a
brush does not optimize anything; it just adds lines of code that
servce no useful purpose. Declare it as a CBrush, and when you need to
create the brush, just call

br.DeleteObject(); // delete previous brush
br.CreateSolidBrush(bkcolor); // create new brush

but saving the brush doesn't really give you anything important.
Complexity without value adds nothing to a program. If you think this
is "optimizing" your program, be aware that the optimization is so
minute as to be essentially indetectable by all but the most
sophisticated high-resolution measurement tools, and the overall
impact on program performance is probably a factor of a few
thousandths of a percent, if that much (I'm being generous here; it
might be an optimization of one part in several million). Note that a
single page fault (about 2ms of processing, the last time I saw any
numbers) is several orders of magnitude greater than any possible
saving you think you have achieved (read my essay on "Optimization:
Your Worst Enemy" on my MVP Tips site if you don't believe this).
joe

On Sun, 7 May 2000 11:16:01 -0700, "Reyes" <vcv...@hotmail.com> wrote:

>Hi, sorry if this question seems stupid, I've created a color selector
>CComboBoxEX (u can add images to the dropdown list), the idea is to select a
>color from it and the color selected will be shown in the Rect area of a
>CStatic control, thaks for any (urgent) help.
>

>void CBorderDialog::OnPaint()
>{
> CPaintDC dc(this); // device context for painting
>
> // TODO: Add your message handler code here
> CBorderDialog *pWnd = (CBorderDialog*)GetParent();
>

> CRect rc;
> CBrush br;
> CDC* pDCMem;
>
>This is the member variable CStatic of the Ctrl in which I'm trying to
>diplay the color (m_exmpl):
>
>m_exmpl.GetWindowRect(&rc);
>

> if(pWnd)
>
>
> pDCMem = new CDC;
> pDCMem->CreateCompatibleDC(&dc);

> CBitmap bmp;
> bmp.CreateCompatibleBitmap(&dc,rc.Width(),rc.Height());
> pDCMem->SelectObject(&bmp);
>
> if (m_hBackBrush != NULL)
> { br.Attach(m_hBackBrush);
> }
> pDCMem->FillRect(pWnd->rc,&br);

> br.Detach();
>}
> // Do not call CDialog::OnPaint() for painting messages
>}
>
>

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www3.pgh.net/~newcomer
MVP Tips: http://www3.pgh.net/~newcomer/mvp_tips.htm

Reyes

unread,
May 8, 2000, 3:00:00 AM5/8/00
to
Hey thanks guys, your analysis and optimization of the code has help me
tremendously, being a newbie it great to know we can find expert advise
cool....


Tenebrax

unread,
May 8, 2000, 3:00:00 AM5/8/00
to
As I already said the easier way to draw all you need in a static (color,
text, everything... quite...) is to derive your own class from CStatic and
implement WM_PAINT (OnPaint)... this way all will work, you'll be able to
reuse your control (in other wnd... or other app).

The last thing that may you cause problem is flickering to solve it, draw in
a mem DC...

Joseph M. Newcomer

unread,
May 8, 2000, 3:00:00 AM5/8/00
to
Be aware that most people won't open a .doc file except from trusted
sites. I don't even open them from trusted sites (post text or .rtf
files if you want them read at all). Who knows what macro virus is
lurking within that our virus scanners haven't found out about yet...
So attaching .doc files to messages won't do much good.
joe

On Mon, 8 May 2000 04:47:04 -0700, "Reyes" <vcv...@hotmail.com> wrote:

>Hi, here's attached (interface.doc) the interface that I'm trying to imitate
>it's from Crystal Reports 7, the line styles will be limited to double or
>single and will be controlled via check boxes instead of a combobox, my
>problems are as you Know is how to assign the background colors and draw
>lines inside the CStatic ctrl , to achieve an interface like the one attach,
>as u can see the line drawing must be inside the Static control, but being a
>newbie I'm not advancing very fast and I'm getting very frustrated, my
>project is due on Tuesday, would appreciate every ounce of help

0 new messages