Re: grid



On Thu, 19 Apr 2007 06:57:43 +0900, "William" <port@xxxxxxxxxxxxxxxxxx> wrote:

Env: WindowsXP, VC++6.0

In my application, I need to draw grid on scaled(x8) bitmap in
CMyScrollView::OnDraw(CDC* pDC).

In the method No.1(below), I draw directly grid on the current hDC. But it
has a problem. When we move the scrollbar button, the view of grid is
changed(gray to white on some places).

In the method No.2(below), I firstly draw grid on another hdcScale. Then
copy it to the current hDC. There is no such problem. But I have to consume
memory.

So, I am wondering how to work it around by method No.1.

TIA
William

***********************************************************************************
Method No.1
CMyScrollView::OnDraw(CDC* pDC)
{
CRect rcClient;
GetClientRect(&rcClient);

int iWindowWid, iWindowHei;
*****
Generally, it is good practice to avoid using commas in declaration lists. One variable,
one line. It would be a lot better use of the names if you eliminated the 'i' (which
conveys nothing useful) or the "Window" (which conveys nothing useful) and simply called
them "Width" and "Height", which would mean the meaningless abbreviations of the most
important part of the name would be eliminated.
*****
iWindowWid = rcClient.right / iZoom; //iZoom=8
iWindowHei = rcClient.bottom / iZoom;
*****
You would be much better off using mapping modes here. Note that the result of doing
these computations is that you are drawing on only 1/8 of your window. These should be
handled in your OnPrepareDC handler where you include the zoom factor, so that you are
always working in terms of your logical coordinate system.
*****

//add one point
iWindowWid++;
iWindowHei++;

//when original bitmap is small than view window
iWindowWid = min(iWindowWid, cxImage);
iWindowHei = min(iWindowHei, cyImage);
*****
THis is confusing. Why not work in terms of logical coordinates, set the zoom factor in
your OnPrepareDC handler, and then never again care about it?
****

::StretchBlt( pDC->m_hDC, 0, 0, iWindowWid * iZoom , iWindowHei * iZoom,
hdcImage, 0, 0, iWindowWid, iWindowHei, SRCCOPY);
****
Why do you keep unwrapping the CDC to an HDC, when there is a perfectly find method of the
CDC called StretchBlt? Why do you keep going for the raw GDI when it is nicely wrapped by
the CDC class?
****

//
// Draw grid
//
DrawGrid(pDC->m_hDC);
****
Why send the raw DC? Why not pass the CDC to your draw handler?
****
}

void CMyScrollView::DrawGrid(HDC hdcTemp)
****
Why an HDC instead of a CDC *? Makes no sense. Why called it hdcTemp when it is not some
temporary HDC, but the actual HDC of your window? Name makes no sense. This should be
written as

void CMyScrollView::DrawGrid(CDC * dc)

and avoid the confusion of using a raw HDC or the construction of a misleading name
****
{
const int brush_width = 8, brush_height = 8;
****
Avoid commas in declaration lists
****
COLORREF colors[] = {RGB(128,128,128), RGB(192,192,192)};
****
static const COLORREF would be better here
****

HDC hDCPattern = ::CreateCompatibleDC(hdcTemp);
HBITMAP hBMP = ::CreateCompatibleBitmap(hdcTemp, brush_width,
brush_height);
****
CDC:::CreateCompatibleBitmap works and doesn't need the raw HDC
****
HBITMAP hBMPOld = (HBITMAP)SelectObject(hDCPattern, hBMP);
*****
Look at the use of SaveDC and RestoreDC
*****

for (int i=0; i<brush_width; i++)
for (int j=0; j<brush_height; j++)
SetPixelV(hDCPattern, i, j, colors[(i+1)*(j+1)&1]);
*****
This is about the worst possible way to draw a grid. It is unbelievably slow. In any
case, you could do this using a compile-time const table, or you could simply store a
little bitmap in your resource segment. Given it is exactly the same bitmap every time,
these would be preferred approaches
*****

HBRUSH hBrPattern = ::CreatePatternBrush(hBMP);
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdcTemp, hBrPattern );

for (int x = iScale; x < gi.cxScale; x += iScale)
PatBlt(hdcTemp, x, 0, 1, gi.cyScale, PATCOPY);
****
What is iScale? Where is it set? What relationship does it have to the coordinates of
the DC? What is gi.cxScale? How is it set?

You are using a CScrollView; how do these logical coordinates relate to the scrolling
values?
*****

for (int y = iScale; y < gi.cyScale; y += iScale)
PatBlt(hdcTemp, 0, y, gi.cxScale, 1, PATCOPY);
*****

SelectObject(hDCPattern, hBMPOld);
SelectObject(hdcTemp, hOldBrush);
DeleteObject(hBrPattern);
}

***********************************************************************************
Method No.2

CMyScrollView::OnDraw(CDC* pDC)
{
CRect rcClient;
GetClientRect(&rcClient);

int iWindowWid, iWindowHei;
iWindowWid = rcClient.right / iZoom; // //iZoom=8
iWindowHei = rcClient.bottom / iZoom;
****
All the same issues as above, including stylistic issues, naming conventions, bizarre uses
of raw DCs when completely inappropriate, and the use of mapping modes so that the zoom
factor completely disappears from all computations here
*****

//add one point
iWindowWid++;
iWindowHei++;

//when original bitmap is small than view window
iWindowWid = min(iWindowWid, cxImage);
iWindowHei = min(iWindowHei, cyImage);
****
Would not be needed if you use mapping modes and handle this in OnPrepareDC
****

HDC hdcScale;
****
Raw HDC usage inappropriate. Use CDC, CClientDC as appropriate
****
HBITMAP hbmScale;
hdcScale = CreateCompatibleDC(hdcImage);
*****
Pretend you never heard of HDCs. Your code will be cleaner and easier to write and
understand. Note that when you call raw APIs, it is considered good style to put :: in
front of them.
****
hbmScale = CreateCompatibleBitmap(hdcImage, iWindowWid * iZoom, iWindowHei
* iZoom);
SelectObject(hdcScale, hbmScale);

::StretchBlt( hdcScale, 0, 0, iWindowWid * iZoom , iWindowHei * iZoom,
hdcImage, 0, 0, iWindowWid, iWindowHei, SRCCOPY);

//
// Draw grid on hdcShow.
//
DrawGrid(hdcScale);

//
// Copy to the screen.
//
::BitBlt(pDC->m_hDC, 0, 0, iWindowWid * iZoom, iWindowHei * iZoom,
hdcScale, 0, 0, SRCCOPY);

DeleteDC(hdcScale);
DeleteObject(hbmScale);
}

*********************************************************************
NOTE:
hdcImage is made at initiation period as follows,
{
HDC hdcParent;
hdcParent = GetDC(m_hWnd);
****
Why? Why would you ever use GetDC? If you want a DC for a window, write
CClientDC dc(this);
Learn to use MFC!
****

hdcImage = CreateCompatibleDC(hdcParent);
hbmImage = Create256DIBitmap(hdcParent, cxImage, cyImage, FALSE ); //at
it CreateDIBSection() is called.
SelectObject(hdcImage, hbmImage);

}

****
I would use neither of the two above methods; I would rewrite the code to be in MFC, I
would set the mapping modes in the OnPrepareDC handler to handle the scaling factor (the
scrolling factor is handled by CScrollView), and only after I had all the code rewritten
correctly would I worry in the slightest about the issues you are having here, which would
probably be fixed by the rewrite.
joe

*****
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.


Loading