How to change the color scheme of CDateTimeCtrl in MFC? - mfc

I need to change the colors of the background, the text, the color of the dropdown button of
CDateTimeCtrl in MFC. I created new class derived from CDateTimeCtrl and tried overwritten OnCtlColor and CtlColor, but these functions are never called (the message map has been added using the Class Wizard). How should I achieve this without writing a completely new datetimectrl class of my own?

You can try something like this:
// header
CBrush* m_pBkgBrush { nullptr };
COLORREF m_bkgColor { RGB(255, 255, 255) };
COLORREF SetBackgroundColor(BOOL bSysColor, COLORREF cr);
and implementation now:
CYourDateTimeCtrl::CYourDateTimeCtrl()
: CDateTimeCtrl()
, m_bkgColor(::GetSysColor(COLOR_WINDOW))
{
m_pBkgBrush = new CBrush(::GetSysColor(COLOR_WINDOW));
}
CYourDateTimeCtrl::~CYourDateTimeCtrl()
{
if (nullptr != m_pBkgBrush)
delete m_pBkgBrush;
}
COLORREF CYourDateTimeCtrl::SetBackgroundColor(BOOL bSysColor, COLORREF cr)
{
COLORREF color = m_bkgColor;
m_bkgColor = bSysColor ? ::GetSysColor(COLOR_WINDOW) : cr;
if (color != m_bkgColor)
{
delete m_pBkgBrush;
m_pBkgBrush = new CBrush(m_bkgColor);
Invalidate();
}
return color;
}
BOOL CYourDateTimeCtrl::OnEraseBkgnd(CDC* pDC)
{
CBrush* pOldBrush = pDC->SelectObject(m_pBkgBrush);
CRect rect;
pDC->GetClipBox(&rect);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
When you use, you do:
MyMonthCalCtrl.SetBackgroundColor(FALSE, RGB(255, 255, 0));
I hope it helps.

Related

I want to set the background color as the color picked from my CMFCColorButton

I have the color picked from my CMFCColorButton and now I want to set it to the background (if it's not already the current color).
I can't seem to figure out how, so I would really appreciate your help and explanation.
void CMainFrame::OnColor()
{
// m_TextColors is the ID of the color button I created in the resource editor.
CMFCRibbonColorButton* pColorBtn = DYNAMIC_DOWNCAST(CMFCRibbonColorButton, m_wndRibbonBar.FindByID(m_TextColors));
COLORREF color = pColorBtn->GetColor();
CWnd* pwndParent = this->GetParent();
CRect rcClient;
pwndParent->GetClientRect(&rcClient);
if (color != GetSysColor(COLOR_BACKGROUND)) {
CBrush brush;
CClientDC dc(this);
brush.CreateSolidBrush(color);
dc.FillRect(rcClient, &brush);
}
else {
MessageBox(_T("Same Color."), MB_OK);
}
}
I made some changes:
void CMainFrame::OnColor()
{
// m_TextColors is the ID of the color button I created in the resource editor.
CMFCRibbonColorButton* pColorBtn = DYNAMIC_DOWNCAST(CMFCRibbonColorButton, m_wndRibbonBar.FindByID(m_TextColors));
COLORREF color = pColorBtn->GetColor();
CBrush brush;
brush.CreateSolidBrush(color);
CRect rc;
GetClientRect(&rc);
GetWindowRect(&rc);
CClientDC dc(this);
dc.SelectObject(&rc);
if (color != GetSysColor(COLOR_WINDOW)) {
dc.FillRect(rc, &brush);
} else {
MessageBox(_T("Same Color."), MB_OK);
}
}
And this is the result:
It's tracing the document's color but not changing it, it's changing the whole window's color.
Update: I've tried the invalidateRect function, this is the result:
It seems like it's adding color on top of my MDI client area not in it in the background like i intended,
Have you tried:
void CMainFrame::OnButColor()
{
HBRUSH hBrush=CreateSolidBrush(RGB(0,0,255));
SetClassLong(m_hWndMDIClient, BGCL_HBRBACKGROUND,(LONG)hBrush);
::InvalidateRect(m_hWndMDIClient,0,TRUE);
}

C++ MFC overriden OnPaint() not painting on another computer

I added code to OnPaint() and it paints correctly on my Windows 10 laptop, but the painting is not shown on another computer (Windows 8). I'm a novice at painting and I probably did something wrong - maybe with invalidate and updatewindow. Regardless, here is my code:
I am painting on a dialog window; the code for OnPaint() is mostly created by Visual Studios - I simply added DrawValveImage() at the end. Also, here is picture that shows what DrawValveImage() draws. I don't think you need to look at all the code for DrawValveImage() to solve the problem; I think my error is my placement of the calling of DrawValveImage(). Maybe OnPaint() isn't the right event for custom painting.
void CCleaningAndScreeningDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
DrawValveImage();
}
void CCleaningAndScreeningDlg::DrawValveImage()
{
//my own drawing
CClientDC* pDC = new CClientDC(this);
pDC->SelectStockObject(NULL_BRUSH);
COLORREF blueBorder = RGB(67, 99, 155);
COLORREF blueFill = RGB(218, 227, 243);
int x1 = 1050;
int y1 = 50;
int width = 300;
int x2 = x1 + width;
int y2 = y1 + width;
CPen pen;
CBrush brush;
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(blueFill);
// select brush and pen
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
if (valveImageDrawn == FALSE)
pDC->Ellipse(x1, y1, x2, y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
int heightWidth = width;
int smallHeightWidth = heightWidth / 7;
int radiusFromOriginSmallCircle = heightWidth / 2.75;
for (int circleIndex = 0; circleIndex < 10; circleIndex++) {
POINT centerSmallCircle = FindPointOnCircle(POINT{ heightWidth / 2, heightWidth / 2 }, radiusFromOriginSmallCircle, (circleIndex * 360 / 10) - 90);
int smallCircleX = centerSmallCircle.x - smallHeightWidth / 2 + x1;
int smallCircleY = centerSmallCircle.y - smallHeightWidth / 2 + y1;
rectangle smallCircleRect = { smallCircleX, smallCircleY, smallCircleX + smallHeightWidth, smallCircleY + smallHeightWidth };
rectsSmallCircles[circleIndex] = smallCircleRect;
bool greenFilled = false;
if (valvePosition - 1 == circleIndex) {
CPen pen;
CBrush brush;
COLORREF greenFill = RGB(181, 230, 29);
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(greenFill);
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
greenFilled = true; //if mouse clicked and green color is painted on the valve image
}
else {
CPen pen;
CBrush brush;
pen.CreatePen(PS_SOLID, 5, blueBorder);
brush.CreateSolidBrush(blueFill);
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
pDC->Ellipse(smallCircleRect.x1, smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
}
CString circleText;
int CircleNumber = circleIndex + 1;
circleText.Format(_T("%d"), CircleNumber);
CRect testRect = { smallCircleRect.x1,
smallCircleRect.y1, smallCircleRect.x2, smallCircleRect.y2 };
pDC->SetBkMode(TRANSPARENT);
CClientDC dc(this);
CFont font;
VERIFY(font.CreateFont(
30, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_BOLD, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial"))); // lpszFacename
CFont* def_font = pDC->SelectObject(&font);
pDC->DrawText(circleText, testRect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
pDC->SelectObject(def_font);
font.DeleteObject();
}
//redraw the combobox infront of the valve-image
UpdateData(TRUE);
comboPorts.Invalidate();
comboPorts.UpdateWindow();
valveImageDrawn = true;
}
OnPaint() is the right method to do custom painting. When you override OnPaint(), you should not call the OnPaint() method of the base class. You are responsible to draw all of the content of the window on your own (except child windows).
You only need this code:
void CCleaningAndScreeningDlg::OnPaint()
{
CPaintDC dc(this); // constructor of CPaintDC calls ::BeginPaint()
DrawValveImage( dc ); // pass device context to the drawing function
// Destructor of CPaintDC automatically calls ::EndPaint()!
}
You can see that I have added a parameter to DrawValveImage. The declaration would look like this:
void DrawValveImage( CDC& dc );
Make sure that in your drawing function, you only use the dc parameter for drawing.
This is wrong:
CClientDC* pDC = new CClientDC(this);
You should not create any additional device contexts.
Example of another mistake:
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
if (valveImageDrawn == FALSE)
pDC->Ellipse(x1, y1, x2, y2);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(&brush);
DeleteObject(&pen);
First, you don't restore the original state of the device context before you delete objects selected into it. When an object is still selected into a device context, it cannot be deleted correctly. To fix that, store the return value of SelectObject() and SelectStockObject(), which is a pointer to the object previously selected in the device context (if you didn't select one, there is a default object). Before you delete the object, call SelectObject(), passing the stored pointer.
Second, why do you delete objects twice? Either let the object destroy itself automatically when it leaves the current scope or call the DeleteObject() member function (rarely needed).
Corrected code:
auto pOldPen = dc.SelectObject(&pen);
auto pOldBrush = dc.SelectObject(&brush);
if (valveImageDrawn == FALSE)
dc.Ellipse(x1, y1, x2, y2);
if(pOldPen)
dc.SelectObject(pOldPen);
if(pOldBrush)
dc.SelectObject(pOldBrush );
// No need for DeleteObject(), the destructor of each object will delete it at the
// end of the current scope (before the function returns). But if you actually need it
// (say you want to reuse the variable), it would look like this:
// pen.DeleteObject();
// brush.DeleteObject();
This code is unnecessary:
//redraw the combobox infront of the valve-image
UpdateData(TRUE);
comboPorts.Invalidate();
comboPorts.UpdateWindow();
Just set the WS_CLIPCHILDREN style of the dialog window (using the dialog editor) to prevent the painting code from drawing over the combo box.

How to change CTabCtrl tab colors?

Hello and happy new year, (it is acceptable to say it until Thursday)
I am trying to change the color of the tabs in the CTabCtrl class. I am trying to create my own ReskinCTablCtrl so that I can just call it in separate classes and easily use it throughout my program.
Currently I am able to change the background color of the CTabCtrl but I cannot modify the tab's themselves.
I used ON_WM_ERASEBKGND() for painting the background and it worked without a problem:
BOOL ReskinCTabCtrl::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
CBrush myBrush(RGB(51, 51, 51)); // dialog background color
BOOL bRes = pDC->PatBlt(0, 0, rect.Width(), rect.Height(), PATCOPY);
pDC->SetBkColor(RGB(51, 51, 51));
pDC->FillRect(&rect, &myBrush);
return bRes;
}
However, I have been unsuccesfull at changing the tab colors themselves. They are still the default MFC colors. I have tried to implement ON_WM_PAINT() and ON_WM_DRAWITEM() without any success. I think I can get to the specific tab rect with using both OnDraw and DrawItem similar to the second link example that I have posted in the end of this question.
void ReskinCTabCtrl::OnPaint() {
...
// paint the tabs first and then the borders
int nTab = GetItemCount();
int nSel = GetCurSel();
if (!nTab) // no pages added
return;
while (nTab--)
{
if (nTab != nSel)
{
dis.itemID = nTab;
dis.itemState = 0;
VERIFY(GetItemRect(nTab, &dis.rcItem));
dis.rcItem.bottom -= 2;
DrawItem(&dis);
DrawItemBorder(&dis);
}
}
...
}
I would really appreciate at least some direction to go about this problem, perhaps some more examples or what methods I should focus on using. I don't need the tabs to be different colors, maybe there is an easy way of doing this?
I've been trying to follow some examples like the following links but I still couldn't figure out the right way to do it.
https://support.microsoft.com/en-us/help/179909/how-to-change-the-background-color-of-a-tab-control
https://www.codeproject.com/Articles/1786/Ownerdraw-Tab-Controls-Borders-and-All
Enable OwnerDraw for tab control, either in resource editor, or set TCS_OWNERDRAWFIXED in OnInitDialog
CTabCtrl has message reflection for WM_DRAWITEM therefore we don't want to override WM_DRAWITEM/OnDrawItem from parent class. Instead override in CTabCtrl::DrawItem(LPDRAWITEMSTRUCT).
Unfortunately the result is rather ugly. It's sort of like overriding DrawItem in a button.
If Visual Style is available and enabled, then you can override CTabCtrl::OnPaint and draw everything manually. Example:
void CMyTabCtrl::OnPaint()
{
CPaintDC dc(this);
dc.SelectObject(GetFont());
CPen pen, pen_active;
COLORREF color_off = RGB(240, 240, 240);
COLORREF color_active = RGB(200, 240, 240);
CBrush brush_off, brush_active;
brush_off.CreateSolidBrush(color_off);
brush_active.CreateSolidBrush(color_active);
pen.CreatePen(PS_SOLID, 1, RGB(200, 200, 200));
pen_active.CreatePen(PS_SOLID, 1, color_active);
CRect rcitem;
GetItemRect(0, &rcitem);
CRect rc;
GetClientRect(&rc);
rc.bottom = rcitem.bottom;
dc.FillSolidRect(&rc, GetSysColor(COLOR_3DFACE));
GetClientRect(&rc);
rc.top = rcitem.bottom - 1;
dc.SelectObject(&pen);
dc.SelectObject(&brush_active);
dc.Rectangle(&rc);
for(int i = 0; i < GetItemCount(); i++)
{
dc.SelectObject(&pen);
if(i == GetCurSel())
{
dc.SelectObject(&brush_active);
dc.SetBkColor(color_active);
}
else
{
dc.SelectObject(&brush_off);
dc.SetBkColor(color_off);
}
GetItemRect(i, &rcitem);
rcitem.right++;
dc.Rectangle(&rcitem);
if(i == GetCurSel())
{
dc.SelectObject(pen_active);
dc.MoveTo(rcitem.left+1, rcitem.bottom - 1);
dc.LineTo(rcitem.right, rcitem.bottom - 1);
}
TCITEM item = { 0 };
wchar_t buf[32];
item.pszText = buf;
item.cchTextMax = 32;
item.mask = TCIF_TEXT;
GetItem(i, &item);
dc.DrawText(buf, &rcitem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
}
BOOL CMyTabCtrl::OnEraseBkgnd(CDC*)
{
return TRUE;
}

error C2248: 'CObject::CObject' : cannot access private member declared in class 'CObject' afxwin.h

I'm trying to make class responsible for putting some text on grey bg:
Score.h
#pragma once
class Score
{
public:
Score();
~Score();
void UpdateScore(int points);
void UpdateLives(int lives);
int GetScore(){ return m_iScore; }
int GetLives(){ return m_iLives; }
void GetScoreText();//CString
void GetLivesText();
CRect GetArea(){ return m_Area; }
void SetArea(int MaxWidth, int MaxHeight, int Width);
void DrawScore(CDC* pDC);
CPoint GetText1Area(){ return m_ptText1; }
CPoint GetText2Area(){ return m_ptText2; }
COLORREF GetText1Color(){ return COLOR_TXT1; }
COLORREF GetText2Color(){ return COLOR_TXT2; }
COLORREF GetScoreColor(){ return GREY; }
CFont GetFont(){ return m_Font; }
private:
CRect m_Area;
CPoint m_ptText1;
CPoint m_ptText2;
int m_iScore;
int m_iLives;
CString m_sScore;
CString m_sLives;
CFont m_Font;
const COLORREF COLOR_TXT1 = RGB(0, 255, 127);//lives txt color
const COLORREF COLOR_TXT2 = RGB(50, 205, 50);//score txt color
const COLORREF GREY = RGB(128, 128, 128);// bg color
};
Score.cpp
#include"stdafx.h"
Score::Score()
{
m_iScore = 0;
m_iLives = 1;
m_Font.CreateFont(
12, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial")); // lpszFacename
}
Score::~Score()
{
m_Font.DeleteObject();
}
void Score::GetScoreText()
{
char c[20];
sprintf_s(c, "Score: %d", m_iScore);
m_sScore.Format(_T("%S"), c);
//return m_sScore;
}
void Score::GetLivesText()
{
char c[20];
sprintf_s(c, "Lives: %d", m_iLives);
m_sLives.Format(_T("%S"), c);
//return m_sLives;
}
void Score::SetArea(int MaxWidth, int MaxHeight, int Width)
{
m_Area = CRect(Width, 0, MaxWidth, MaxHeight);
m_ptText1 = CPoint(static_cast<int>(Width * 1.1), static_cast<int>(MaxHeight * 0.1));
m_ptText2 = CPoint(static_cast<int>(Width * 1.1), static_cast<int>(MaxHeight * 0.2));
}
void Score::DrawScore(CDC* pDC)
{
GetLivesText();
GetScoreText();
CPen pen2(PS_SOLID, 0, GREY);
CBrush brush2(GREY);
CPen* pOldPen = pDC->SelectObject(&pen2);
CBrush* pOldBrush = pDC->SelectObject(&brush2);
pDC->Rectangle(m_Area);
pDC->SelectObject(pOldPen); //resetting default Pen
pDC->SelectObject(pOldBrush); //resetting default Brush
CFont *pPrevFont = pDC->SelectObject(&m_Font);
pDC->SetTextColor(COLOR_TXT1);
pDC->TextOut(m_ptText1.x, m_ptText1.y, m_sLives);
pDC->SetTextColor(COLOR_TXT2);
pDC->TextOut(m_ptText2.x, m_ptText2.y, m_sScore);
pDC->SelectObject(pPrevFont);
}
All I can tell about this error is that it should be in this class(error points to afhwin.h). From what I saw from other questions it's usually connected to private constructor or strings. Here strings belong to class so it shouldn't be problem and I can't tell where may be called private constructor(for now this class have no obiects in other classes). Please tell me what's wrong here.
The CFont Class ultimately derives from the CObject Class. Looking at CObject's definition (see afx.h) you will find the following comment:
// Disable the copy constructor and assignment by default so you will get
// compiler errors instead of unexpected behaviour if you pass objects
// by value or assign objects.
In other words: You cannot pass CObject-derived objects by value. Your Score::GetFont() method is doing just that. You will have to change to return either a reference or pointer:
const CFont& GetFont() { return m_Font; }
// or
const CFont* GetFont() { return &m_Font; }
Your GetFont function returns a CFont by value, pass it by refernce of pointer instead.

How do I prevent flickering on CListCtrl?

I'm using a CListCtrl/CListView report view (LVS_REPORT) in virtual mode (LVS_OWNERDATA) with LVS_EX_DOUBLEBUFFER enabled and I encounter ugly flickering. Double buffer have a real effect but it doesn't stop all flickering (without it very slow).
I'm not looking for switching to other controls that would require a high amount of rework (like ObjectListView)
How does the flickering behaves:
on column resize - the background is first clean using lightgray and after this is displayed the text (background is white)
on mouse scroll (animated) - for a very short time there is lightgray-bar displayed in the area where new lines are to be displayed.
It looks like it does clean the background using the default window background color (lightgray) for the area where it has to redraw.
How do I solve the flickering problem?
Try to do the following:
- Set Clip Children and Clip Sibling for paremt dialog of List Control.
- Make dirived from CListCtrl class. In this class overwrite OnEraseBkgnd. In the OnEraseBkgnd fill with background color area around of visible items of the list.
The OnEraseBkgnd can look like:
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
CBrush br;
CRect rcCli;
CRect rcItemsRect(0, 0, 0, 0);
int nHeadHeight = 0;
int nItems = GetItemCount();
GetClientRect(&rcCli);
CHeaderCtrl* pHeadCtrl = GetHeaderCtrl();
if (pHeadCtrl)
{
CRect rcHead;
pHeadCtrl->GetWindowRect(&rcHead);
nHeadHeight = rcHead.Height();
}
rcCli.top += nHeadHeight;
if (nItems > 0)
{
CPoint ptItem;
CRect rcItem;
GetItemRect(nItems - 1, &rcItem, LVIR_BOUNDS);
GetItemPosition(nItems - 1, &ptItem);
rcItemsRect.top = rcCli.top;
rcItemsRect.left = ptItem.x;
rcItemsRect.right = rcItem.right;
rcItemsRect.bottom = rcItem.bottom;
if (GetExtendedStyle() & LVS_EX_CHECKBOXES)
rcItemsRect.left -= GetSystemMetrics(SM_CXEDGE) + 16;
}
br.CreateSolidBrush(GetBkColor());
if (rcItemsRect.IsRectEmpty())
pDC->FillRect(rcCli, &br);
else
{
if (rcItemsRect.left > rcCli.left) // fill left rectangle
pDC->FillRect(
CRect(0, rcCli.top, rcItemsRect.left, rcCli.bottom), &br);
if (rcItemsRect.bottom < rcCli.bottom) // fill bottom rectangle
pDC->FillRect(
CRect(0, rcItemsRect.bottom, rcCli.right, rcCli.bottom), &br);
if (rcItemsRect.right < rcCli.right) // fill right rectangle
pDC->FillRect(
CRect(rcItemsRect.right, rcCli.top, rcCli.right, rcCli.bottom), &br);
}
return TRUE;
}
I know only way to have flicker free is using double buffering or MemDC.
have found this article: Flicker-free-drawing-of-any-control
This article explains it well how to quickly perform Non Flickering drawing on your CListCtrl.
And it works excellent.
PS: VS 2005 doesn't have CMemDC class you will need to implement it your self, or use the following code:
//
// CMemDC.h header file
//
#pragma once
class CMemDC
{
public:
CMemDC(CDC& dc, CWnd* pWnd);
CMemDC(CDC& dc, const CRect& rect);
virtual ~CMemDC();
CDC& GetDC() { return m_bMemDC ? m_dcMem : m_dc; }
BOOL IsMemDC() const { return m_bMemDC; }
BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }
void EraseBkClip();
protected:
CDC& m_dc;
BOOL m_bMemDC;
HANDLE m_hBufferedPaint;
CDC m_dcMem;
CBitmap m_bmp;
CBitmap* m_pOldBmp;
CRect m_rect;
};
//
// CMemDC.cpp source file
//
#include "CMemDC.h"
CMemDC::CMemDC(CDC& dc, CWnd* pWnd) :
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL)
{
ASSERT_VALID(pWnd);
pWnd->GetClientRect(m_rect);
m_rect.right += pWnd->GetScrollPos(SB_HORZ);
m_rect.bottom += pWnd->GetScrollPos(SB_VERT);
if (m_dcMem.CreateCompatibleDC(&m_dc) &&
m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
{
m_bMemDC = TRUE;
m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
}
}
CMemDC::CMemDC(CDC& dc, const CRect& rect) :
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_pOldBmp(NULL), m_rect(rect)
{
ASSERT(!m_rect.IsRectEmpty());
if (m_dcMem.CreateCompatibleDC(&m_dc) &&
m_bmp.CreateCompatibleBitmap(&m_dc, m_rect.Width(), m_rect.Height()))
{
m_bMemDC = TRUE;
m_pOldBmp = m_dcMem.SelectObject(&m_bmp);
}
}
CMemDC::~CMemDC()
{
if (m_bMemDC)
{
CRect rectClip;
int nClipType = m_dc.GetClipBox(rectClip);
if (nClipType != NULLREGION)
{
if (nClipType != SIMPLEREGION)
{
rectClip = m_rect;
}
m_dc.BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), &m_dcMem, rectClip.left, rectClip.top, SRCCOPY);
}
m_dcMem.SelectObject(m_pOldBmp);
}
}
void CMemDC::EraseBkClip()
{
CRect clip;
m_dcMem.GetClipBox(&clip);
m_dcMem.FillSolidRect(clip, GetSysColor(COLOR_WINDOW));
}
There is an ultra simple way I found that worked for me:
Turn off redraw with m_List1.SetRedraw(false)
Reset contents with m_List1.ResetContents()
Add new strings in loop with m_List1.AddString()
Then finalize by turning back on redraw and a m_List1.UpdateWindow().