{"id":1313,"date":"2014-04-07T07:00:00","date_gmt":"2014-04-07T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/04\/07\/using-wm_setredraw-to-speed-up-adding-a-lot-of-elements-to-a-control\/"},"modified":"2014-04-07T07:00:00","modified_gmt":"2014-04-07T07:00:00","slug":"using-wm_setredraw-to-speed-up-adding-a-lot-of-elements-to-a-control","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140407-00\/?p=1313","title":{"rendered":"Using WM_SETREDRAW to speed up adding a lot of elements to a control"},"content":{"rendered":"<p>\nToday&#8217;s Little Program shows one way you can implement\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/01\/24\/10119211.aspx\">\na better version of <code>WM_SET&shy;REDRAW<\/code><\/a>.\nOur first version doesn&#8217;t use\n<code>WM_SET&shy;REDRAW<\/code><\/a> at all.\n<\/p>\n<p>\nStart with the\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a>\nand make the following changes:<\/p>\n<pre>\nHFONT g_hfList;\nint g_yOrigin;\nint g_cyLine;\nint g_cLinesPerPage;\nint g_cItems = 100;\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/08\/05\/54602.aspx\">GetTrackPos<\/a> incorporated by reference\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/31\/54601.aspx\">ScrollTo<\/a> incorporated by reference\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/31\/54601.aspx\">ScrollDelta<\/a> incorporated by reference\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/31\/54601.aspx\">OnSize<\/a> incorporated by reference\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/31\/54601.aspx\">OnVscroll<\/a> incorporated by reference + <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/08\/05\/54602.aspx\">modifications<\/a>\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/25\/54582.aspx\">OnCreate<\/a> incorporated by reference\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/25\/54582.aspx\">OnDestroy<\/a> incorporated by reference\n\/\/ This is the same as the <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/29\/54591.aspx\">earlier version of PaintSimpleContent<\/a>\n\/\/ with one tiny change: Draw the items in reverse order so the effect\n\/\/ is more noticeable.\nvoid\nPaintSimpleContent(HWND hwnd, PAINTSTRUCT *pps)\n{\n HFONT hfPrev = SelectFont(pps-&gt;hdc, g_hfList);  \/* Use the right font *\/\n int iMin = max(pps-&gt;rcPaint.top \/ g_cyLine, 0);\n int iMax = min((pps-&gt;rcPaint.bottom + g_cyLine - 1) \/ g_cyLine, g_cItems);\n for (int i = iMin; i &lt; iMax; i++) {\n  char szLine[256];\n  int cch = wsprintf(szLine, \"This is line %d\", <font COLOR=\"blue\">g_cItems - i<\/font>);\n  TextOut(pps-&gt;hdc, 0, i * g_cyLine, szLine, cch);\n }\n SelectFont(pps-&gt;hdc, hfPrev);\n}\n\/\/ <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/07\/31\/54601.aspx\">PaintContent<\/a> incorporated by reference\n<font COLOR=\"blue\">void AddItem(HWND hwnd)\n{\n g_cItems++;\n InvalidateRect(hwnd, 0, TRUE);\n ScrollDelta(hwnd, 0);\n}\nvoid OnChar(HWND hwnd, TCHAR ch, int cRepeat)\n{\n switch (ch) {\n case TEXT('1'):\n  AddItem(hwnd);\n  break;\n case TEXT('2'):\n  for (int i = 0; i &lt; 10000; i++) {\n   AddItem(hwnd);\n  }\n  break;\n case TEXT('3'):\n  SetWindowRedraw(hwnd, FALSE);\n  for (int i = 0; i &lt; 10000; i++) {\n   AddItem(hwnd);\n  }\n  SetWindowRedraw(hwnd, TRUE);\n  InvalidateRect(hwnd, nullptr, TRUE);\n }\n}\n HANDLE_MSG(hwnd, WM_VSCROLL, OnVscroll);\n HANDLE_MSG(hwnd, WM_CHAR, OnChar);<\/font>\n<\/pre>\n<p>\nMost of this program was stolen from my scroll bar series.\nThe interesting new bits are that you can add one new item\nby hitting <kbd>1<\/kbd>,\nor you can add ten thousand items by hitting <kbd>2<\/kbd>,\nor you can add ten thousand items with redraw disabled\nby hitting <kbd>3<\/kbd>.\n<\/p>\n<p>\nI drew the items in reverse order so that adding an item\nforces everything to change position, so that the effect\nof the redraw is more noticeable.\n<\/p>\n<p>\nObserve that adding one item is fast,\nbut adding ten thousand items with redraw enabled is slow;\nyou can watch the scroll bar as it slowly shrinks.\nBut adding ten thousand items with redraw disabled is not too bad.\n<\/p>\n<p>\nBut we can do better.\n<\/p>\n<pre>\n<font COLOR=\"blue\">BOOL g_fRedrawEnabled = TRUE;<\/font>\nvoid AddItem(HWND hwnd)\n{\n g_cItems++;\n <font COLOR=\"blue\">if (g_fRedrawEnabled) {<\/font>\n  InvalidateRect(hwnd, 0, TRUE);\n  ScrollDelta(hwnd, 0);\n <font COLOR=\"blue\">}<\/font>\n}\n<font COLOR=\"blue\">void OnSetRedraw(HWND hwnd, BOOL fRedraw)\n{\n g_fRedrawEnabled = fRedraw;\n if (fRedraw) {\n  InvalidateRect(hwnd, 0, TRUE);\n  ScrollDelta(hwnd, 0);\n }\n}<\/font>\nvoid\nOnPaint(HWND hwnd)\n{\n <font COLOR=\"blue\">if (g_RedrawEnabled) {<\/font>\n  PAINTSTRUCT ps;\n  BeginPaint(hwnd, &amp;ps);\n  PaintContent(hwnd, &amp;ps);\n  EndPaint(hwnd, &amp;ps);\n <font COLOR=\"blue\">} else {\n  ValidateRect(hwnd, nullptr);\n }<\/font>\n}\n <font COLOR=\"blue\">HANDLE_MSG(hwnd, WM_SETREDRAW, OnSetRedraw);<\/font>\n<\/pre>\n<p>\nWe have a custom handler for the\n<code>WM_SET&shy;REDRAW<\/code> message that updates\na flag that indicates whether redraw is enabled.\nWhen adding an item, we do the visual recalculations\n(updating the scroll bar, mostly)\nonly if redraw is enabled.\nIf a paint message comes in while redraw is disabled,\nwe merely validate the window to say &#8220;It&#8217;s all good,\ndon&#8217;t worry!&#8221;\nWhen redraw is re-enabled, we ask for a fresh repaint\nand update the scroll bars.\n<\/p>\n<p>\nWith this version of the program, adding ten thousand items\nwith redraw disabled is lightning fast.\n<\/p>\n<p>\nNotice that <code>g_fRedrawEnabled<\/code> is not\nreference-counted.\nIt&#8217;s a simply <code>BOOL<\/code>.\nIn other words, if you send the\n<code>WM_SET&shy;REDRAW<\/code> message twice to disable\nredraw,\nyou still only need to enable it once.\nDisabling redraw on a window where redraw is already disabled\nhas no effect.\n<\/p>\n<p>\n<b>Exercise<\/b>:\nCompare the behavior of <code>WM_SET&shy;REDRAW<\/code> with\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/02\/22\/1742084.aspx\">\n(the incorrect)\n<code>Lock&shy;Window&shy;Update<\/code><\/a>\nfor this program.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s Little Program shows one way you can implement a better version of WM_SET&shy;REDRAW. Our first version doesn&#8217;t use WM_SET&shy;REDRAW at all. Start with the scratch program and make the following changes: HFONT g_hfList; int g_yOrigin; int g_cyLine; int g_cLinesPerPage; int g_cItems = 100; \/\/ GetTrackPos incorporated by reference \/\/ ScrollTo incorporated by reference \/\/ [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-1313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s Little Program shows one way you can implement a better version of WM_SET&shy;REDRAW. Our first version doesn&#8217;t use WM_SET&shy;REDRAW at all. Start with the scratch program and make the following changes: HFONT g_hfList; int g_yOrigin; int g_cyLine; int g_cLinesPerPage; int g_cItems = 100; \/\/ GetTrackPos incorporated by reference \/\/ ScrollTo incorporated by reference \/\/ [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=1313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1313\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=1313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=1313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=1313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}