{"id":377,"date":"2008-12-07T17:59:54","date_gmt":"2008-12-07T16:59:54","guid":{"rendered":"http:\/\/blog.m-ri.de\/?p=377"},"modified":"2008-12-09T08:42:15","modified_gmt":"2008-12-09T07:42:15","slug":"aus-zwei-mach-eins-wie-man-zwei-cursor-kombinieren-kann","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2008\/12\/07\/aus-zwei-mach-eins-wie-man-zwei-cursor-kombinieren-kann\/","title":{"rendered":"Aus zwei mach eins: Wie man zwei Cursor kombinieren kann"},"content":{"rendered":"<p>Wer komplexere UIs baut, der\u00a0kommt um Drag&amp;Drop oder andere Extrafunktionen mit der Maus nicht herum. Um den Benutzer\u00a0gut zu unterst\u00fctzen verwendet man nat\u00fcrlich auch spezielle Cursor.<br \/>\nAuff\u00e4llig ist aber oft genug der Unterschied zwischen den sch\u00f6nen Standardzeigern im 3D-Stil und den oft flachen Zeigern, die gerade mal zus\u00e4tzlich ein Plus oder ein Stoppzeichen tragen. Oder ganz und gar der Unterschied , wenn man eigene Cursorstile verwendet, wie z.B. <em>Dirigent<\/em> oder <em>H\u00e4nde.<\/em><\/p>\n<p>Ich habe mich bei meinem aktuellen Projekt gefragt, warum man eigentlich nicht den aktuellen Standard-Cursor verwendet und diesen zus\u00e4tzlich mit dem entsprechenden Symbol versieht (Pluszeichen, Stopp, Dragframe etc). Das w\u00fcrde besser aussehen und Arbeit sparen, weil man sich nur noch Gedanken um die Extrasymbolik machen muss und der Benutzer beh\u00e4lt seinen eingestellten normalen Cursor.<\/p>\n<p>Schaut man sich den Explorer unter <em>XP+Vista<\/em> an, dann macht man die Entdeckung, dass der es genauso macht. Der aktuelle Cursor wird beim Drag&amp;Drop Vorgang um ein Stopp- oder Pluszeichen erg\u00e4nzt.<\/p>\n<p>Warum es also nicht selber auch so machen \u2753<\/p>\n<p>Meine Suche im Internet zu diesem Thema: <em>&#8222;Wie kombiniert man zwei Cursor zu einem?&#8220;<\/em>, war nicht von Erfolg gekr\u00f6nt. Beispielcode dazu habe ich nicht gefunden. Aber auch wirklich gar nichts.<br \/>\nAlso selbst Hand anlegen.<\/p>\n<p>Bei meinem ersten Versuch wollte ich die Cursor-Bitmaps direkt manipulieren. Bei meiner Untersuchung und dem ersten Democode wurde klar, dass Windows gar keinen Unterschied mehr zwischen Icons und Cursor macht. Erstaunlich \u2757 Ob Icon oder Cursor spielt eigentlich keine Rolle. <em>HCURSOR <\/em>und <em>HICON <\/em>sind identische Typedefs. Also egal ob toller Farbcursor oder monochromer Cursor, alles gleich.<br \/>\nMit dieser Entdeckung nahm ich schnell Abstand von <em>BitBlt <\/em>und Konsorten und verwendete eine <em>Imagelist, <\/em>die genau diese Funktion des Overlays von Symbolen bereits unterst\u00fctzt und zudem auch noch perfekt mit Icons umgehen kann.<\/p>\n<p>Herausgekommen ist der folgende Code, der es erlaubt zwei Icons, oder Cursor zu \u00fcberlagern und ein neues Icon oder einen neuen Cursor zu erzeugen.<\/p>\n<p>Man muss sich aso nur mit <em>LoadCursor<\/em>, den aktuellen Cursor laden und kann diesen damit ganz einfach modifzieren. Nicht vergessen: Das erzeugte Icon\/Cursor muss allerdings mit <em>DestroyIcon <\/em>auch wieder entsorgt werden. Das Ganze habe ich der Einfachheit halber mit MFC Funktionen geschrieben, aber das Ganze in pure WinAPI zu transformieren d\u00fcrfte nicht schwer sein. \ud83d\ude09<\/p>\n<p>\u00a0Hier nun der Code. Have fun!<\/p>\n<pre lang=\"cpp\">HICON CombineIcons(HICON hIcon1, HICON hIcon2)\r\n{\r\n\u00a0\/\/ Remember that HCURSOR and HICON are identical!\r\n \/\/ hIcon1 is overlayed by hIcon2.\r\n\u00a0\/\/ hIcon2 isn't adjusted in size or position.\r\n\u00a0\/\/ It just overlays hIcon1\r\n \/\/ Get bitmaps of icon 1\r\n\u00a0ICONINFO iconInfo;\r\n\u00a0::ZeroMemory(&amp;iconInfo,sizeof(iconInfo));\r\n\u00a0if (!GetIconInfo(hIcon1,&amp;iconInfo))\r\n\u00a0\u00a0return NULL;\r\n\r\n \/\/ Attach the bitmaps to get them automatically freed\r\n\u00a0\/\/ upon error.\r\n\u00a0CBitmap bitmap, mask;\r\n\u00a0bitmap.Attach(iconInfo.hbmColor);\r\n\u00a0mask.Attach(iconInfo.hbmMask);\r\n\r\n \/\/ Get size and width\r\n\u00a0BITMAP bm;\r\n\u00a0if (bitmap.m_hObject)\r\n\u00a0\u00a0bitmap.GetObject(sizeof(bm),&amp;bm);\r\n\u00a0else\r\n\u00a0\u00a0mask.GetObject(sizeof(bm),&amp;bm);\r\n\r\n\u00a0\/\/ Get the color depth from the icon and create an image list\r\n\u00a0\/\/ Remember we need a\r\n\u00a0UINT flags = 0;\r\n\u00a0switch (bm.bmBitsPixel)\r\n\u00a0{\r\n\u00a0case 4:\u00a0\u00a0flags = ILC_COLOR4;\u00a0\u00a0break;\r\n\u00a0case 8:\u00a0\u00a0flags = ILC_COLOR8;\u00a0\u00a0break;\r\n\u00a0case 16:\u00a0flags = ILC_COLOR16;\u00a0break;\r\n\u00a0case 24:\u00a0flags = ILC_COLOR24;\u00a0break;\r\n\u00a0case 32:\u00a0flags = ILC_COLOR32;\u00a0break;\r\n\u00a0default:\u00a0flags = ILC_COLOR4;\u00a0\u00a0break;\u00a0\u00a0\r\n\u00a0}\r\n\u00a0CImageList il;\r\n \/\/ be ware that the monochrom cursor bitmap is twice the height\r\n\u00a0if (!il.Create(bm.bmWidth,\r\n      bm.bmHeight\/(iconInfo.hbmColor!=NULL ? 1 : 2),\r\n      ILC_MASK|flags,2,2))\r\n\u00a0\u00a0return NULL;\r\n\r\n \/\/ Load the both icons into the image list\r\n\u00a0il.Add(hIcon1);\r\n\u00a0il.Add(hIcon2);\r\n\r\n\u00a0\/\/ Define the second icon as an overlay image\r\n\u00a0il.SetOverlayImage(1,1);\r\n\r\n\u00a0\/\/ Get a new icon with icon 2 overlayed\r\n\u00a0HICON hCombined = ImageList_GetIcon(il.m_hImageList,0,\r\n              ILD_NORMAL|INDEXTOOVERLAYMASK(1));\r\n\u00a0if (!hCombined)\r\n\u00a0\u00a0return NULL;\r\n\r\n\u00a0\/\/ Need the icon infos for this new icon\r\n\u00a0ICONINFO iconInfoCombined;\r\n\u00a0::ZeroMemory(&amp;iconInfoCombined,sizeof(iconInfo));\r\n\u00a0if (!GetIconInfo(hCombined,&amp;iconInfoCombined))\r\n\u00a0\u00a0return NULL;\r\n\r\n\u00a0\/\/ Destroy the combined icon, we just have the bitmap and the mask\r\n\u00a0::DestroyIcon(hCombined);\r\n\r\n\u00a0\/\/ Get the bitmaps into objects to get them automatically freed\r\n\u00a0CBitmap bitmapCombined, maskCombined;\r\n\u00a0bitmapCombined.Attach(iconInfo.hbmColor);\r\n\u00a0maskCombined.Attach(iconInfo.hbmMask);\r\n\r\n\u00a0\/\/ Get the hotspotinto and cursor data from\r\n\u00a0\/\/ the ICONINFO of hCursor1\r\n\u00a0iconInfoCombined.fIcon = iconInfo.fIcon;\r\n\u00a0iconInfoCombined.xHotspot = iconInfo.xHotspot;\r\n\u00a0iconInfoCombined.yHotspot = iconInfo.yHotspot;\r\n\r\n\u00a0\/\/ OK we have can create a new Cursor out of the target\r\n \/\/ Don't forget to use DestroyIcon for the new Cursor\/Icon\r\n\u00a0return ::CreateIconIndirect(&amp;iconInfoCombined);\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Wer komplexere UIs baut, der\u00a0kommt um Drag&amp;Drop oder andere Extrafunktionen mit der Maus nicht herum. Um den Benutzer\u00a0gut zu unterst\u00fctzen verwendet man nat\u00fcrlich auch spezielle Cursor. Auff\u00e4llig ist aber oft genug der Unterschied zwischen den sch\u00f6nen Standardzeigern im 3D-Stil und den oft flachen Zeigern, die gerade mal zus\u00e4tzlich ein Plus oder ein Stoppzeichen tragen. Oder &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2008\/12\/07\/aus-zwei-mach-eins-wie-man-zwei-cursor-kombinieren-kann\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eAus zwei mach eins: Wie man zwei Cursor kombinieren kann\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":[30,4,3,23,2],"tags":[370,100,352,97,59,61],"class_list":["post-377","post","type-post","status-publish","format-standard","hentry","category-c","category-mfc","category-programmieren","category-ressourcen","category-windows-api","tag-c","tag-gui","tag-mfc","tag-ui","tag-win32","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\/377","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=377"}],"version-history":[{"count":1,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/377\/revisions"}],"predecessor-version":[{"id":378,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/377\/revisions\/378"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=377"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=377"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=377"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}