WinCE Menüs
« | 26 Dec 2022 | »Alle Jahre wieder…
tauchen die gleichen UI Probleme erneut auf.
Ich hatte doch schon mal Menüs in Windows CE
angefangen … und wieder abgeändert und wieder noch etwas geändert …
und dann lief es nicht mehr.
Oder … hat es überhaupt je richtig funktioniert ?
Es wird Zeit für eine Detailanalyse.
Windows CE ist nicht Windows CE, sondern es ist Windows CE oder (das alte) Windows Mobile. Und im Falle von Windows Mobile ist es ein “Smartphone” von vor 2007 mit Bildschirmauflösungen von 320x240, anders gesagt: Briefmarken-klein.
Jetzt kann man zwar mit CommandBar Controls “echte” Menüzeilen basteln, die dann aber auf diesen Kleingeräten unbenutzbare UIs bedeuten. Und das fällt einem nicht auf bei einem einzigen Menüeintrag, aber bei 3+ wird das schon sehr deutlich.
Die Pseudo-Shell-Menu-Bar
Die AGYShell
von Windows Mobile/CE bringt allerdings ein ähnliches Feature
mit, nämlich die beiden “Software-Buttons” am unteren Rand.
Gedacht waren diese “Tasten” für ein schnelles OK
oder Cancel
,
bzw. Zurück
und Weiter
.
An die beiden schmalen Schaltflächen schmiegt sich in der Mitte auch noch
der Keyboard-Button, mit dem man die virtuelle Tastatur ausfahren kann.
Idee: Popup-Menü durch Software-Button
Ich dachte mir also, dass das Programm-Menü (Datei, Bearbeiten, usw.) unter
Windows Mobile nicht ständig angezeigt werden muss, sondern nur ein Menü
Software-Button angezeigt wird, und erst beim Klick darauf, wird das
eigentliche Menü als Popup-Menü ausgefahren.
Damit wird kein Platz unnötig belegt und die Programmlogik kann dann genau
so aussehen, wie auf einer vollen Desktop App.
Resourcen-Zwang
Die Funktion SHCreateMenuBar erzeugt zwar diese Software-Buttons, doch sie verlangt eine Menü-Ressource in der Programmdatei, und die sieht z.B.: so aus:
1// .rc resource file: 2STRINGTABLE 3BEGIN 4 MY_MENU_BUTTON_1_TEXT "OK" 5 MY_MENU_BUTTON_2_TEXT "HELP" 6END 7 8MY_MENU_ID SHMENUBAR DISCARDABLE 9BEGIN 10 MY_MENU_ID, 11 2, 12 13 I_IMAGENONE, MY_MENU_BUTTON_1_MSG, 14 TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, 15 MY_MENU_BUTTON_1_TEXT, 0, NOMENU, 16 17 I_IMAGENONE, MY_MENU_BUTTON_2_MSG, 18 TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, 19 MY_MENU_BUTTON_2_TEXT, 0, 0, 20END
Im C Code kann man nun auf das MY_MENU_ID
Makro verweisen:
1HWND hwnd_of_windows; 2SHMENUBARINFO mbi; 3RECT rc_window, rc_menu; 4 5// create menu bar 6mbi.cbSize = sizeof(mbi); 7mbi.hwndParent = hwnd_of_window; 8mbi.dwFlags = 0; 9mbi.hInstRes = (HINSTANCE)GetModuleHandle(NULL); 10mbi.nToolBarId = MY_MENU_ID; 11SHCreateMenuBar(&mbi); 12 13// resize main window to exclude menu-bar 14GetWindowRect(hwnd_of_window, &rc_window); 15GetWindowRect(mbi.hwndMB, &rc_menu); 16rc_window.bottom -= (rc_menu.bottom - rc_menu.top); 17MoveWindow(hwnd_of_windows, rc_window.left, rc_window.top, 18 rc_window.right - rc_window.left, rc_window.bottom - rc.top, 19 FALSE); 20DrawMenuBar(hwnd_of_window);
Anschließend lässt sich in der WM_COMMAND
Nachricht die
MY_MENU_BUTTON_1_MSG
und MY_MENU_BUTTON_2_MSG
ID wieder abfangen.
An dieser Stelle kann man dann ein übliches Win32 Popup-Menü mit den
eigentlichen Menüeinträgen anzeigen lassen.
Fazit
Dieser Workaround funktioniert tatsächlich, zumindest konnte ich im
Device-Emulator nun meinen Texteditor laden, der dort sein Menü nur beim
Klick auf den Software-Button anzeigt.
Und die gleiche Anwendungslogik erzeugt am herkömmlichen Desktop
weiter ein Fenster-Menü.
Mein Anliegen ist damit gelöst … doch man lernt daraus wieder, wie verdammt schwierig es ist, mit “einer API” zwei unterschiedliche Plattformen auf den gleichen Nenner zu bringen.
Das erklärt auch, warum der Trend zu Webanwendungen geht, denn dort ist “Responsive Design” mit ein paar Zeilen CSS erreichbar, während man auf der nativen Seite lange hin und her probieren muss, bis man eine akzeptable Lösung gefunden hat.
Nachtrag: RC in CMAKE
Und wie bindet man jetzt Resource-Dateien
.rc
in CMake in ein Projekt ein?
Einfach per target_sources
:
Denn ohne die Resource in der EXE schlägt der Aufruf von
SHCreateMenuBar
fehl.