|
I've got the same problem...know of any other possible solution or another class to use?
Thx!
|
|
|
|
|
I'm guessing here, but in your example, one of the modes you support is MM_ANISOTROPIC. At first glance, it appears to work. However, the settings for the viewport extent and the window extent effectively make your MM_ANISOTROPIC equivalent to MM_TEXT...
// Equivalent to MM_TEXT which does not experience rounding errors
pDC->SetWindowExt(1,1);
pDC->SetViewportExt(1,1);
In order to effectively use MM_ANISOTRIC or MM_ISOTROPIC, you need to modify the extents which will usually introduce "off by one errors" or "rounding errors". These errors can be observed in your code if you remove the animation, output a line of text or some graphic in Anisotropic and modify the extents in OnPrepareDC. I have had issues with this technique as presented in 5 other books. I would guess this is what others are experiencing but failing to provide you with much information about.
Microsoft article Q89215 "Mapping Modes and Round-Off Errors" Link to the article last time I checked[^] sums this all up and gives a few clues on how to get around this. Be forwarned, the article is OLD (16 bit days) but the material is still relevant. The article does not provide any good "fit to width" or "fit to size" solutions but the hints as to what a programmer should do to circumvent these "rounding errors" are there. You will find that you can still use the mapping modes to do 80% of the work for you but you WILL need to provide work arounds and accept some tradeoffs and reasonable upper limits on scaling but the general offscreen buffer technique presented in your article will work in the "roll your own" modes like MM_ANISOTROPIC or MM_ISOTROPIC without smearing or smudging.
I hope this information helps those who are experiencing "smearing" to adapt the technique to their respective environments and needs.
NOTE:make sure your "Display Properties/Effects" tab property page has the "Show window contents while dragging" setting turned on to observe the effect.
-- modified at 12:22 Friday 9th June, 2006
|
|
|
|
|
Whoever voted the post down obviously did not try the authors code in the context I presented so I will restate it...
"These errors can be observed in (the) code if you remove the animation, output a line of text or some graphic in Anisotropic and modify the extents in OnPrepareDC."
NOTE:make sure your "Display Properties/Effects" tab property page has the "Show window contents while dragging" setting turned on to observe the effect.
Do this and drag the help/about box over the text and you'll see the smudging and smearing. If you sensed some sort of bashing on the article, then your making up stories and reading a bit much into what was intended to help others (like myself) who spent weeks, if not months trying to debug the remnant smearing in the technique presented by Charles Petzold, Jones, and many others in their texts that are pretty much the same as in the article. The technique works when the extents ratio is 1/1 but try changing the extents as you would with MM_ANISOTROPIC or MM_ISOTROPIC and you will find yourself in the same boat, scratching your head, tempted to resort to your own custom scaling.
The Microsoft article referenced made a lightbulb go on for me and I found a solution which allows the use of MM_ISOTROPIC with memory buffering and no smearing so I thought I'd share the fact that Article Q89215 proved helpful for me in my problem context and might be for others. If not, I wish them luck in their endeavors nonetheless. At least I tried to help.
At least post a reply indicating why you voted it down so I could learn something if you had something to say concerning the smudging problem observed by some members of CP.
-- modified at 12:23 Friday 9th June, 2006
|
|
|
|
|
Right so after 4 days of solid work on this i have finally found out what is wrong.
It resides in the rounding errors between DP and LP and that the offscreen bitmap and the DC get misaligned.
It eventually boiled down to SetWindowOrg(m_rect.left, m_rect.top); resulting in misalignment.
I replaced this with:
CPoint viewportOrg = pDC->GetViewportOrg();
SetViewportOrg(viewportOrg);
I have added/removed bits to the class to make it work with my CScrollView. I got rid of the DPtoLP conversions as I was finding errors in the rounding.
You MUST pass it a rectangle that outlines the client box:
CRect clientRect;
GetClientRect(&clientRect);
CMemDC pMemDC(pDC, &clientRect);
Note: This works with my CScrollView. I haven't tested it in any other situations.
class CMemDC : public CDC {
private:
CBitmap m_bitmap;
CBitmap* m_oldBitmap;
CDC* m_pDC;
CRect m_updateRect_LP;
CRect m_clientRect_DP;
BOOL m_bMemDC;
public:
CMemDC(CDC* pDC, const CRect* pClientRect) : CDC()
{
ASSERT(pDC != NULL);
ASSERT(pClientRect != NULL);
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
m_clientRect_DP = *pClientRect;
pDC->GetClipBox(&m_updateRect_LP);
if (m_bMemDC) {
CreateCompatibleDC(pDC);
m_bitmap.CreateCompatibleBitmap(pDC, m_clientRect_DP.Width(), m_clientRect_DP.Height());
SetMapMode(pDC->GetMapMode());
SetWindowExt(pDC->GetWindowExt());
SetViewportExt(pDC->GetViewportExt());
m_oldBitmap = SelectObject(&m_bitmap);
CPoint viewportOrg = pDC->GetViewportOrg();
SetViewportOrg(viewportOrg);
CPoint windowOrg = pDC->GetWindowOrg();
SetWindowOrg(windowOrg);
m_updateRect_LP.InflateRect(1,1);
SelectClipRgn(NULL);
IntersectClipRect(&m_updateRect_LP);
}
else
{
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
}
~CMemDC()
{
if (m_bMemDC)
{
m_pDC->BitBlt(
m_updateRect_LP.left,
m_updateRect_LP.top,
m_updateRect_LP.Width(),
m_updateRect_LP.Height(),
this,
m_updateRect_LP.left,
m_updateRect_LP.top,
SRCCOPY);
SelectObject(m_oldBitmap);
}
else
{
m_hDC = m_hAttribDC = NULL;
}
}
CMemDC* operator->()
{
return this;
}
operator CMemDC*()
{
return this;
}
};
Matt Clarkson
"When the world says 'Give up',
Hope whispers 'Try it one more time.'"
Edit: Added SetWindowOrg.
modified on Wednesday, August 19, 2009 5:57 AM
|
|
|
|
|
I'm writting some text using DrawText function, but it looks bad on the screen, how could I write "nice" text?.
my code is as follows:
init of CFont:
LOGFONT lf;
strcpy(lf.lfFaceName,font_name);
lf.lfHeight=tamy;
lf.lfWeight=bold ? FW_BOLD : FW_NORMAL;
lf.lfEscapement=0;
lf.lfCharSet=ANSI_CHARSET;
lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;
lf.lfItalic=FALSE;
lf.lfOrientation=0;
lf.lfOutPrecision =OUT_DEVICE_PRECIS;
lf.lfPitchAndFamily=FF_DONTCARE;
lf.lfQuality = PROOF_QUALITY;
lf.lfStrikeOut=FALSE;
lf.lfUnderline=FALSE;
lf.lfWidth = tamx; //always is 0
if(!m_font.CreatePointFontIndirect(&lf,NULL))
use of this font:
pDC->SetBkMode(TRANSPARENT);
//centered text
pDC->DrawText(m_text,rectButton,
DT_CENTER|DT_VCENTER|DT_NOCLIP|DT_NOPREFIX|DT_SINGLELINE);
what I'm doing wrong?
thanks in advance.
David.
|
|
|
|
|
Hi there,
I use DrawText as well but have not encountered any problems. What do you mean the text looks bad? Are you drawing on screen or on a button (noticing u have a varialbe 'rectButton')? More source code would help
Cheers,
Isa
|
|
|
|
|
Hi!
Is it possible to get MemDC to work correctly with MM_ISOTROPIC mapping mode? The flicker is gone but when I try to move the bitmap in the window it moves up when I try to drag it down. This is because the y-axis goes upwards in my application. Any help much appreciated!
Thanks!
--
Daniel
|
|
|
|
|
HI Daniel
I am using it with MM_ISOTROPIC. No problem. Does your code work without MemDC? If not you problem lies elsewhere.
joe
If winter comes is spring far behind? - (PBShelley -Ode to the West Wind)
|
|
|
|
|
How can we keep the font is the same one?
|
|
|
|
|
MemDC doesn't reproduce all of the state of the current DC. This is why the examples show defining MemDC immediately in your painting process rather than later.
However, if you need to keep font information, the logical place for you to do this would be in the CMemDC constructor.
Keith Rule
|
|
|
|
|
I'm sorry for my doubt,in my opinion , is there need to free memory resource after we used the variable m_bitmap ?
That is ,in ~CMemDC() function,modify as follow:
<br />
if (m_bMemDC) {<br />
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),<br />
this, m_rect.left, m_rect.top, SRCCOPY); <br />
<br />
SelectObject(m_oldBitmap); <br />
<br />
m_bitmap.DeleteObject();<br />
} else {<br />
m_hDC = m_hAttribDC = NULL;<br />
}
After all ,thanks for your good work!
|
|
|
|
|
I've used this class for years and have never observed a memory leak with it (and believe me I've looked).
Keith Rule
|
|
|
|
|
The whole approach is failing in alternative Mapping Modes. It only can be used in combination with MM_TEXT. I'm using MM_HIMETRIC, which would imply buffering into a bitmap 100x100=10,000 times larger than for MM_TEXT - there's no such PC to handle a multi-gigabyte bitmap for buffering...
Professional C++ libraries for getting images from any TWAIN or DirectShow compatible device on www.neatcpp.com
|
|
|
|
|
VitalyTomilov wrote:
The whole approach is failing in alternative Mapping Modes. It only can be used in combination with MM_TEXT. I'm using MM_HIMETRIC, which would imply buffering into a bitmap 100x100=10,000 times larger than for MM_TEXT - there's no such PC to handle a multi-gigabyte bitmap for buffering...
This technique simply encapsulates a standard double buffering scheme into a convenient class. There's nothing special or magic about this approach. And like any approach, it isn't appropriate for all situations. The situation you just described will break any double buffering scheme.
That doesn't mean this approach is broken (it isn't), it just means it's not appropriate for current application.
I'm sorry for your difficulties. Good Luck.
Keith Rule
|
|
|
|
|
Part of the view where i'm drawing objects within a clipped area isn't drawn at all, i.e. when i use GUI API ::SelectClipRgn nothing will be drawn within the selected clipping region. Any idea how to fix this?
|
|
|
|
|
I've already made a dialog based app which uses a lot of LineTo commands as a result it flickers as I redraw it. But the CDialog class doesn't seem to have the OnEraseBkgnd handler. How can I use this code in this case? The app can be downloaded from http://www.hpi.be/TuneBox2004Install.exe if you want to see it flicker!
Greetz Tom
|
|
|
|
|
Dragging my window half of the screen then back in, shows an update bug. Who solved this?
|
|
|
|
|
I use your CMemDC for years now and I never thanked you:
Merci, Danke, Sposibo, Euxaristw, Be in good health and happy !
|
|
|
|
|
All the people on CP are using this for very simple drawings indeed, and it's true that using update regions, clipping and intersecting rects and regions, resizing, combined with coordinates transforms, lack of generalized methods to do this right, and eventually MFC bugs workaround internally by just redrawing the controls, put a serious burden over the programmer's shoulder who otherwise would waist a lot of time for apparently a very simple problem. The good sollution using the mentioned methods is really missing on CP and in microsoft samples and documentation. Take a professional image application, load and move a picture. Then create a simple MFC project, use CMemDC and try moving the same picture.
I'm aware that almost all GUI projects are using this or variants derived from it, after this article appeared, however I would rather vote 3 for the coziness, knowing it's just for very very simple drawings indeed, no scrolling, no resizing, no zooming.
gugul
|
|
|
|
|
I agree that CMemDC isn't intended for highly optimized drawing. I have used it in scrolling applications and resizing applications, but some additional work is probably required by the programmer. Having said that, I’d still point out that there is a lot of value in simple solutions to difficult problems -- even when they don't cover every case.
Your comments sound to me like you have some specific changes you'd make to CMemDC. If so, I'd be very happy to evaluate them and update this article with your modifications. Alternatively there are probably many people who would value your solution to this gnarly problem. Please feel free to contribute an article on this topic to CodeProject.
|
|
|
|
|
|
This class is simply greate. It saved me a lot of time.
Anyway I'm experiencing this small problem when used in CListView-derived class: When I hold the PageDown key in order to scroll down, the items' labels are getting somehow "cut" and aren't drawn in their proper height. When I drag the vertical scrollbar, it is without problems.
Will someone help please?
|
|
|
|
|
This solved flicker problem, however, sometimes the text line is not fully pained and very reproducable. I am using MM_HIENGLISH mode. To me it seems a rounding issue from LP to DP, but not sure. Any advice?
|
|
|
|
|
Plugged right in, worked the first time and I didn't have to muck my code at all.
Thanks!!
|
|
|
|
|
Background:
I am new to MFC, and WinCE, and eVC (makes for a nice challenge it seems!)!
My Project:
I am trying to build an HMI that displays red, green or yellow circles (Ellipse!) over a bitmap background, switching colour in accordance with changing values (that code sorted-ish).
My eVC project is currently Dialogue-based. Wise?
I have a memDC with a bitmap selected. This BitBlt's OK on to the screen DC in OnPaint().
I then added Ellipse drawing code to OnPaint but this failed deep in MFC: "Assertion Failed in Wingdi".
So (and this is a better plan anyways!), I tried to do everything in the single memDC: ie. Select a bitmap (as background image) then overlay it with a coloured Ellipse or lines.
The code runs OK, but only the bitmap is displayed, no ellipse.
Is it possible to do a ".Select bitmap" followed by ".Select Brush" and maintain all elements in the memDC?
Are the coordinates different?
Do bitmaps and ellipse need separate DC's? How could these be combined on the dialogue DC?
Any assistance appreciated! Tight schedule busting at seams!
Regards
Jack
NON-WORKING PSEUDO CODE with stuff I tried...
=================================================
MyDialog::OnInitDialog...
m_bmp_BackDrop.LoadBitmap(IDB_APP_grey); // load image
// device context of client area of windows (dialogue!Ok?)
CClientDC dc(this);
// create memory device context to hold image
m_memDC_BackDrop.CreateCompatibleDC(&dc);
m_memDC_BackDrop.SelectObject( &m_bmp_BackDrop );
// create memory device context to hold DRAWING
// m_memDC_Overlay.CreateCompatibleDC(&dc);
// m_memDC_Overlay.SelectObject( &Bmp4 ); //select bitmap SAMPLE256
// image is painted in OnPaint function
// create solid brush (m_Brush<colour> defined in .h file)
m_BrushRed.CreateSolidBrush( RGB(255,0,0) );
// CBrush *pBrushSaved = ... //I'VE NO NEED FOR SAVE. NEEDED?
m_memDC_BackDrop.SelectObject ( &m_BrushRed );
// ??? m_memBMP_BackDrop.CreateCompatibleBitmap( &dc, 300, 200)
// draw Circle in bounding rectangle...
m_memDC_Overlay.Ellipse(5,5,30,30);
...
===============================
... ::OnPaint()
...
// bit block transfer image from memory-DC to paint-DC
dc.BitBlt( 0, 0, 300,300, &m_memDC_BackDrop, 0, 0, SRCCOPY);
Regards & Thanks, Jack@SIL
|
|
|
|
|