{"id":382,"date":"2008-12-14T15:52:42","date_gmt":"2008-12-14T14:52:42","guid":{"rendered":"http:\/\/blog.m-ri.de\/?p=382"},"modified":"2008-12-13T16:16:43","modified_gmt":"2008-12-13T15:16:43","slug":"der-etwas-bessere-cmemdc","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2008\/12\/14\/der-etwas-bessere-cmemdc\/","title":{"rendered":"Der etwas bessere CMemDC"},"content":{"rendered":"<p><em>CMemDC <\/em>aus dem Artikel <a href=\"http:\/\/www.codeproject.com\/KB\/GDI\/flickerfree.aspx\">Flicker free drawing with MFC<\/a>\u00a0ist wohl der Klassiker f\u00fcr Doublebuffering und ist wohl jedem MFC Entwickler bekannt.<\/p>\n<p>Er macht was er soll und ich habe ihn selbst \u00fcber Jahre hinweg unver\u00e4ndert verwendet. Solange man einfache Sachen macht und ausschlie\u00dflich den <em>MM_TEXT <\/em>Mappingmode verwendet ist alles OK.<br \/>\nHat man sich aber was spezielles &#8211; zoomf\u00e4higes &#8211; zusammengebaut mit <em>MM_ANISOTROPIC<\/em> dann funktioniert das Ganze nicht mehr, weil Keith an den Window Origin\u00a0Koordinaten dreht und nicht am Viewport.<\/p>\n<p>Meine abgewandelte Variante tr\u00e4gt einer entsprechende Verwendung auch f\u00fcr andere Mappingmodes Rechnung. Es m\u00fcsste IMHO f\u00fcr jeden funktionieren. Intensiv getestet habe ich es mit <em>MM_ANISOTROPIC<\/em>.<\/p>\n<p>Will\/muss man auch an den Viewport Koordinaten drehen, dann sollten die alten Viewport Koordinaten gelesen werden und dann entsprechend durch ein Offset ge\u00e4ndert werden.<br \/>\nAlles anderen Werte wie die Extents k\u00f6nnen beliebig ver\u00e4ndert werden.<br \/>\nBei der Verwendung sollte <em>MM_TEXT <\/em>eingeschaltet sein (entsprechende <em>ASSERTs <\/em>habe ich erg\u00e4nzt). <em>MM_TEXT <\/em>ist normalerweise gesetzt, wenn <em>CMemDC <\/em>direkt nach Instanzierung des <em>CPaintDC <\/em>zum Einsatz kommt. Der Destruktor setzt dann den Mappingmode auf <em>MM_TEXT <\/em>zur\u00fcck.<\/p>\n<p>Dieser neue, modifizierte <em>CMemDC<\/em> kann einfach die bisherige Implementierung ersetzen.<\/p>\n<p>Have fun &amp; Happy coding \ud83d\ude42<\/p>\n<pre lang=\"cpp\" line=\"1\">class CMemDC : public CDC\r\n{\r\npublic:\r\n  \/\/ constructor sets up the memory DC\r\n  CMemDC(CDC* pDC)\r\n    : CDC()\r\n    , m_pDC(pDC)\r\n    , m_pOldBitmap(NULL)\r\n    , m_bMemDC(!m_pDC-&gt;IsPrinting())\r\n  {\r\n    ASSERT(pDC != NULL);\r\n\r\n    if (m_bMemDC)\r\n    {\r\n      \/\/ Create a Memory DC.\r\n      \/\/ At this moment we should have mapping mode text\r\n      ASSERT(m_pDC-&gt;GetMapMode()==MM_TEXT);\r\n      ASSERT(m_pDC-&gt;GetWindowOrg()==CPoint(0,0));\r\n      ASSERT(m_pDC-&gt;GetViewportOrg()==CPoint(0,0));\r\n\r\n      \/\/ Get the clip box and create bitmap for this size\r\n      m_pDC-&gt;GetClipBox(&amp;m_rect);\r\n      CreateCompatibleDC(m_pDC);\r\n      m_bitmap.CreateCompatibleBitmap(m_pDC, \r\n              m_rect.Width(), m_rect.Height());\r\n      m_pOldBitmap = SelectObject(&amp;m_bitmap);\r\n\r\n      \/\/ Adjust the view port so that we hit the clip rect.\r\n      SetViewportOrg(-m_rect.left, -m_rect.top);\r\n      IntersectClipRect(m_rect);\r\n\r\n      \/\/ Fill background in case the user has overridden\r\n      \/\/ WM_ERASEBKGND.  We end up with garbage otherwise.\r\n      FillSolidRect(m_rect, m_pDC-&gt;GetBkColor());\r\n    }\r\n    else\r\n    {\r\n      \/\/ Make a copy of the relevant parts of the current DC for printing\r\n      m_bPrinting = m_pDC-&gt;m_bPrinting;\r\n      m_hDC     = m_pDC-&gt;m_hDC;\r\n      m_hAttribDC = m_pDC-&gt;m_hAttribDC;\r\n    }\r\n  }\r\n\r\n  \/\/ Destructor copies the contents of the mem DC to the original DC\r\n  ~CMemDC()\r\n  {\r\n    if (m_bMemDC)\r\n    {\r\n      \/\/ The mapping mode might effect the BitBlt. So we need to return to\r\n      \/\/ MM_TEXT. This makes m_rect.left and m_rect.top again the\r\n      \/\/ coordinates of our clipped rectangle. And to make sure that the\r\n      \/\/ coordinates are really used we just clear the ViewportOrg and the\r\n      \/\/ WindowOrg\r\n      SetMapMode(MM_TEXT);\r\n      SetViewportOrg(0,0);\r\n      SetWindowOrg(0,0);\r\n\r\n      \/\/ Copy the off screen bitmap onto the screen.\r\n      \/\/ For this we just make sure that we really target the rectangle of\r\n      \/\/ our temporal bitmap.\r\n      m_pDC-&gt;BitBlt(m_rect.left, m_rect.top, \r\n              m_rect.Width(), m_rect.Height(),\r\n              this, 0, 0, SRCCOPY);\r\n\r\n      \/\/Swap back the original bitmap.\r\n      SelectObject(m_pOldBitmap);\r\n    }\r\n    else\r\n    {\r\n      \/\/ All we need to do is replace the DC with an illegal value,\r\n      \/\/ this keeps us from accidentally deleting the handles associated\r\n      \/\/ with the CDC that was passed to the constructor.\r\n      m_hDC = m_hAttribDC = NULL;\r\n    }\r\n  }\r\n\r\n  \/\/ Allow usage as a pointer\r\n  CMemDC* operator-&gt;()  {   return this;  }\r\n\r\n  \/\/ Allow usage as a pointer\r\n  operator CMemDC*()  {   return this;  }\r\n\r\nprivate:\r\n  CBitmap  m_bitmap;    \/\/ Offscreen bitmap\r\n  CBitmap* m_pOldBitmap;  \/\/ bitmap originally found in CMemDC\r\n  CDC*   m_pDC;     \/\/ Saves CDC passed in constructor\r\n  CRect  m_rect;    \/\/ Rectangle of drawing area.\r\n  bool   m_bMemDC;    \/\/ true if CDC really is a Memory DC.\r\n};<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>CMemDC aus dem Artikel Flicker free drawing with MFC\u00a0ist wohl der Klassiker f\u00fcr Doublebuffering und ist wohl jedem MFC Entwickler bekannt. Er macht was er soll und ich habe ihn selbst \u00fcber Jahre hinweg unver\u00e4ndert verwendet. Solange man einfache Sachen macht und ausschlie\u00dflich den MM_TEXT Mappingmode verwendet ist alles OK. Hat man sich aber was &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2008\/12\/14\/der-etwas-bessere-cmemdc\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eDer etwas bessere CMemDC\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[25,30,4,3,2],"tags":[370,352,61],"class_list":["post-382","post","type-post","status-publish","format-standard","hentry","category-atl","category-c","category-mfc","category-programmieren","category-windows-api","tag-c","tag-mfc","tag-winapi"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/comments?post=382"}],"version-history":[{"count":1,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/382\/revisions"}],"predecessor-version":[{"id":383,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/382\/revisions\/383"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=382"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=382"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}