{"id":94455,"date":"2016-10-05T07:00:00","date_gmt":"2016-10-05T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=94455"},"modified":"2019-03-13T10:32:15","modified_gmt":"2019-03-13T17:32:15","slug":"20161005-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20161005-00\/?p=94455","title":{"rendered":"Why doesn&#8217;t my custom-drawn trackbar get a paint notification when the position changes from 1 to 0?"},"content":{"rendered":"<p>A customer reported that under certain conditions, their custom-drawn trackbar does not generate a <code>NM_CUSTOM&shy;DRAW<\/code> message. <\/p>\n<blockquote CLASS=\"q\"><p>We have found that the trackbar control in the shell common controls library does not generate a <code>NM_CUSTOM&shy;DRAW<\/code> message when the position changes from 1 to 0 and the trackbar&#8217;s range is sufficiently high. <\/p>\n<p>We start with the trackbar position at 1. <\/p>\n<table BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" STYLE=\"border: solid 1px black\">\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">&minus;1000<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\">&nbsp;<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">+1000<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<td COLSPAN=\"4\" ALIGN=\"center\" STYLE=\"width: 20ex;border-bottom: solid black 1px\">            &#x26ca;     <\/td>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"6\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td COLSPAN=\"5\">    Current value: 1     <\/td>\n<\/tr>\n<\/table>\n<p>And then we send the <code>TBM_SET&shy;POS<\/code> message to set the trackbar position to zero. The result is this: <\/p>\n<table BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" STYLE=\"border: solid 1px black\">\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">&minus;1000<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\">&nbsp;<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">+1000<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<td COLSPAN=\"4\" ALIGN=\"center\" STYLE=\"width: 20ex;border-bottom: solid black 1px\">            &#x26ca;     <\/td>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"6\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td COLSPAN=\"5\">    Current value: 1     <\/td>\n<\/tr>\n<\/table>\n<p>Observe that the &#8220;Current value&#8221; is reported as 1, even though we changed the value to 0. On the other hand, if we start with the position at &minus;1: <\/p>\n<table BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" STYLE=\"border: solid 1px black\">\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">&minus;1000<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\">&nbsp;<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">+1000<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<td COLSPAN=\"4\" ALIGN=\"center\" STYLE=\"width: 20ex;border-bottom: solid black 1px\">            &#x26ca;     <\/td>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"6\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td COLSPAN=\"5\">    Current value: &minus;1     <\/td>\n<\/tr>\n<\/table>\n<p>then when we send the <code>TBM_SET&shy;POS<\/code> message to change the position to zero, we do get a <code>NM_CUSTOM&shy;DRAW<\/code> message, and the &#8220;Current value&#8221; updates. <\/p>\n<table BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" STYLE=\"border: solid 1px black\">\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">&minus;1000<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\">&nbsp;<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">+1000<\/td>\n<\/tr>\n<tr>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<td COLSPAN=\"4\" ALIGN=\"center\" STYLE=\"width: 20ex;border-bottom: solid black 1px\">            &#x26ca;     <\/td>\n<td STYLE=\"width: 5ex\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<td COLSPAN=\"2\" STYLE=\"width: 10ex\" ALIGN=\"center\">|<\/td>\n<\/tr>\n<tr>\n<td COLSPAN=\"6\">&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td COLSPAN=\"5\">    Current value: 0     <\/td>\n<\/tr>\n<\/table>\n<p>We have been able to reproduce this problem on every version of the trackbar as far back as we tested. <\/p>\n<\/blockquote>\n<p>Everything is working as it should. <\/p>\n<p>The <code>NM_CUSTOM&shy;DRAW<\/code> notification lets you customize how the common control draws itself. If there is nothing that needs to be redrawn, then there is no <code>WM_PAINT<\/code> message and consequently no <code>NM_CUSTOM&shy;DRAW<\/code> notification. <\/p>\n<p>When the trackbar range is large, then multiple positions have the same visual appearance. This is a natural consequence of the pigeonhole principle: There are 500 (say) pixel positions that the thumb could be drawn, but there are 2001 possible positions, so around four thumb positions all correspond to the same visual appearance. <\/p>\n<p>What appears to be happening is that positions 0 and 1 share the same visual appearance, so when the thumb position changes between 0 and 1, there is no visual change and therefore no <code>NM_CUSTOM&shy;DRAW<\/code> message. <\/p>\n<p>On the other hand, it appears that positions &minus;1 and 0 have different visual apperances, which is why you get a <code>NM_CUSTOM&shy;DRAW<\/code> message when the position changes from &minus;1 to 0. <\/p>\n<p>It sounds like the application is using the <code>NM_&shy;CUSTOM&shy;DRAW<\/code> notification to detect when the trackbar position has changed. That&#8217;s not what it&#8217;s for. The <code>NM_&shy;CUSTOM&shy;DRAW<\/code> notification is for letting you customize the way the trackbar is drawn. <\/p>\n<p>If you want to know when the trackbar position changes, listen for the <code>WM_HSCROLL<\/code> message. Note, however, that the <code>WM_HSCROLL<\/code> message is not generated if the program itself changes the position via the <code>TBM_SET&shy;POS<\/code> message, on the theory that since the program itself changed the value, it can update its own state right there. No need to tell the program what it already knows. <\/p>\n<p><b>Bonus chatter<\/b>: Not generating a notification for program-generated position changes also helps avoid infinite loops. After the program changes the trackbar position, it receives the change notification, and in response to the notification, the program tries to update some state. But the state update fails, so the program tries to undo the change and set the position back. This reset generates its own change notification, and the program responds to the notification by trying to update that same state (to the old value), which still fails, so the program tries to undo the change and set the position back, which generates yet another change notification, and so on. <\/p>\n<p>The theory here is that the code that is listening for the <code>WM_HSCROLL<\/code> or <code>WM_HSCROLL<\/code> message is also the code that is sending the <code>TBM_SET&shy;POS<\/code> message, so there&#8217;s no point in telling the program something it already knows. <\/p>\n<p><b>Exercise<\/b>: Suppose you have a trackbar, and you want to let anybody send it a <code>TBM_SET&shy;POS<\/code> message to change the trackbar position, but you also want to be notified when that happens. How would you do that? <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It had no visible effect.<\/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-94455","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It had no visible effect.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94455","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=94455"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/94455\/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=94455"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=94455"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=94455"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}