CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 28
  1. #1
    Join Date
    Mar 2005
    Posts
    16

    Question scrolling popup menu via Page Up/Down

    In the case where a popup menu is too long to fit on the screen, I would like it to scroll in response to the Page Up, Page Down, Home, and End keys. Is there any way to accomplish this? It would also be nice if the menu scrolled in response to the mouse wheel. It seems that by default the only way to scroll a popup menu is via the arrow buttons at the top and bottom of the menu, or via the up and down keys. This is counter-intuitive, particularly on small screens.

    I understand that long popup menus are suboptimal, and that the stock behavior may be Microsoft's subtle way of discouraging me from using such menus, but I want it to work better regardless. I would be willing to use a hook function if necessary, however even if I manage to intercept the relevant keys it's not obvious how I can tell the menu to scroll, since it isn't a window.

    I have observed this behavior on Windows 7 using Common Controls 6, in both Aero and Classic themes. Is the behavior likely to differ in Windows 8, and/or in later versions of Common Controls?

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,395

    Re: scrolling popup menu via Page Up/Down

    "the case where a popup menu is too long to fit on the screen" is just a very bad design!
    How could your user choose an item in the list of more than 30-40 ones?confused:
    Please, don't struggle against the scrolling. Just change your design.
    Perhaps, you could split it into two or more single popup menus? Or implement some additional popups within a main menu?
    Victor Nijegorodov

  3. #3
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: scrolling popup menu via Page Up/Down

    Pop up menu behavior is determined by OS. You cannot override it. The only option here is to implement your own one. Which looks like a really bad idea. Say your users work with Windows menus all the time. Now, how could they figure out that your menu supports page keys unlike to standard menus?

    I agree with Victor, nested menu hierarchy looks much more attractive.
    Best regards,
    Igor

  4. #4
    Join Date
    Mar 2005
    Posts
    16

    Re: scrolling popup menu via Page Up/Down

    Thank you for your response. OK I did say I wanted it to work even though Microsoft and others may think it's a bad idea. If the shortcut keys worked as expected, it wouldn't be so difficult to make a choice in a long menu, especially if the list is properly sorted. Long drop lists are common, but they usually aren't problematic because drop lists support Page Up/Down, Home/End, and the wheel. Anyway for sure I'm not the first to discover this obvious shortcoming of Windows. In Firefox for example, Home/End does work in menus (though not Page Up/Down), presumably because whichever toolkit they use rolled their own menus. Also note that both list boxes and menus support mnemonic selection, i.e. in either case if I press a letter key and there's a menu item or list item that starts with that letter it's automatically scrolled into view. So in fact the two UI elements handle similar problems already. If popup menus supported the standard navigation keys they would become more useful (to me, and no doubt to others) without harming existing users in any way.

    Regarding the suggestion to use multiple popups, I have considered this of course! Even assuming the items can logically be broken into groups, there is the problem that I'm expecting the popup menu to show which item is selected, e.g. via a radio button. In a single short menu this isn't a problem. But in a long menu it's suboptimal, again because of stupid behavior: unlike with drop lists, the selected item is not scrolled into view automatically. But with multiple lists, how do I show which list the selected item is in? Suppose I had a submenu for each possible starting letter, A-Z. And suppose the selected item is "Foo" so it's in the F submenu. Does Windows permit me to place a radio button on the F submenu?

    FWIW The domain in this case happens to be chord types, e.g. maj7, -7, mM7#5, etc.

  5. #5
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,395

    Re: scrolling popup menu via Page Up/Down

    Quote Originally Posted by ckorda View Post
    Thank you for your response. OK I did say I wanted it to work even though Microsoft and others may think it's a bad idea. If the shortcut keys worked as expected, it wouldn't be so difficult to make a choice in a long menu, especially if the list is properly sorted. ...
    Again it is a very bad design!
    Look at the VS IDE: there is a menu Window where a list of currently opened files is displayed.
    Although there may be opened some hundred files, only about ten of them you will see in the menu list. To see the full list of files you need to click corresponding menu item (or a toolbar button) and then a dialog with the list of all opened files is displayed. The list has a scrollbar so you will be able very easy (using arrows, mouse, Page Up, Page Down, Home, and End keys) select what you need.
    Victor Nijegorodov

  6. #6
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: scrolling popup menu via Page Up/Down

    Quote Originally Posted by ckorda View Post
    In the case where a popup menu is too long to fit on the screen, I would like it to scroll in response to the Page Up, Page Down, Home, and End keys. Is there any way to accomplish this? It would also be nice if the menu scrolled in response to the mouse wheel. It seems that by default the only way to scroll a popup menu is via the arrow buttons at the top and bottom of the menu, or via the up and down keys. This is counter-intuitive, particularly on small screens.

    I understand that long popup menus are suboptimal, and that the stock behavior may be Microsoft's subtle way of discouraging me from using such menus, but I want it to work better regardless. I would be willing to use a hook function if necessary, however even if I manage to intercept the relevant keys it's not obvious how I can tell the menu to scroll, since it isn't a window.

    I have observed this behavior on Windows 7 using Common Controls 6, in both Aero and Classic themes. Is the behavior likely to differ in Windows 8, and/or in later versions of Common Controls?
    If you really want to do this (think again as others have indicated), one way would be to subclass the popup menu. WM_INITMENUPOPUP (http://msdn.microsoft.com/en-us/libr...v=vs.85).aspx) is received when the menu is about to become active so you can subclass the menu in the code to handle this message. You can then program whatever behaviour is required for the menu.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  7. #7
    Join Date
    Mar 2005
    Posts
    16

    Re: scrolling popup menu via Page Up/Down

    Thanks but I didn't ask whether it was a good idea, I asked how to do it. The substantive problem is this: Obfuscation notwithstanding, a popup menu is a window. It is relatively straightforward to obtain a popup menu's HWND, e.g. via the subclassing method described in this Transparent Menu article. Using this HWND, I am able to move the popup menu anywhere via ::MoveWindow. This at least proves that I have the right HWND and that it accepts messages. But now do I scroll the popup menu? I have tried using ::ScrollWindow, but it merely causes the window to repaint itself. I speculate that this occurs because the menu maintains its scroll state in some non-standard way, instead of using the Windows scrolling API. There may be a way around it, such as an internal message. Unfortunately it is difficult to study the internal behavior of popup menus because they are so ephemeral. I had hoped that someone here could point me in the direction of a source that might provide such information. But maybe not. Must I wait until MS loses another antitrust suit for the details of popup menu scrolling to finally become public?
    Last edited by ckorda; July 5th, 2014 at 03:48 PM.

  8. #8
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: scrolling popup menu via Page Up/Down

    The article referenced doesn't describe subclassing menus. It describes super-classing a menu class (not what is required) and other things. You need to subclass the popupmenu in WM_INITMENUPOPUP and then in your code for the new menu wndproc function you can handle the messages as needed to create scroll bars and respond to their messages just as you would if you were adding scroll bars to your own window.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  9. #9
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: scrolling popup menu via Page Up/Down

    Quote Originally Posted by ckorda View Post
    Regarding the suggestion to use multiple popups, I have considered this of course! Even assuming the items can logically be broken into groups, there is the problem that I'm expecting the popup menu to show which item is selected, e.g. via a radio button. In a single short menu this isn't a problem. But in a long menu it's suboptimal, again because of stupid behavior: unlike with drop lists, the selected item is not scrolled into view automatically. But with multiple lists, how do I show which list the selected item is in? Suppose I had a submenu for each possible starting letter, A-Z. And suppose the selected item is "Foo" so it's in the F submenu. Does Windows permit me to place a radio button on the F submenu?
    Yes, you could do that. but it sounds to me like a list box is better suited for your user interface. This would also allow the user to select an item by typing multiple characters, which is much more powerful than mnemonics.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  10. #10
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: scrolling popup menu via Page Up/Down

    Typically speaking, and this holds true for ALL the windows common controls.

    Most of them can be tweaked (to a degree) to change how they look.
    It is either impossible, or very difficult to change the BEHAVIOUR of a common control to make it do something it wasn't designed for.

    And even in the case where you can change behaviour, it often will have edge cases where things don't work, or it may totally break down on another version of Windows. It can be particularly problematic if you have external tools that assume a menu works in a certain way (such as the screen narrator, the disabilities features, ...) changing bahaviour could make your software unusable for people needing those.

    So as already pointed out, if you don't like HOW it works, use something different, or create your own.

    A menu isn't an ideal UI for what you are trying to do, so I would imaging that you'd want to look for an alternative method even if you coud get it to work.

    That said, Home/End/PgUp/PgDn seems like a doable feature since you're not trying to "change behaviour" rather, you're trying to do something with keys which are not currently being used. Subclass the menu, handle the keys yourself.
    Note that this could totally mess up if in the next version of Windows MS decided to do something with those keys.

  11. #11
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: scrolling popup menu via Page Up/Down

    Quote Originally Posted by ckorda View Post
    Does Windows permit me to place a radio button on the F submenu?
    Yes, I believe it does. But even if you had nested menus with the selected item indicated by a radio button, is that a good user experience? You'll probably need some other indicator to show when an item is selected (other than a user working their way through the menus).

  12. #12
    Join Date
    Mar 2005
    Posts
    16

    Post Re: scrolling popup menu via Page Up/Down

    Regarding subclassing menus, it's not clear what this would mean since CMenu isn't derived from CWnd and therefore doesn't even have a message map. I enclose some test code from a dialog app below. I hook menu creation by installing an alternate window procedure for all menus. This is admittedly crude, but it provides me with the menu's window handle, even for nested popups. There are two distinct problems:

    1) I can catch WM_KEYDOWN messages, but I find that no messages are generated for the page up/down or home/end keys. Normally I would get around this via PreTranslateMessage, but I don't know what the equivalent method would be in a window procedure.

    2) I have not found any way to tell the menu to scroll itself. I can move the menu anywhere with ::MoveWindow, but ::ScrollWindow has no effect.

    Code:
    WNDPROC wpOldMenuProc;
    LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch(uMsg) {
    	case WM_CREATE:
    		printf("!");
    		break;
    	case WM_KEYDOWN:
    		printf("k=%x ", wParam);
    //		::MoveWindow(hWnd, 0, 0, 100, 100, 1); // works fine but not helpful
    		{
    			CRect	r;
    			::GetClientRect(hWnd, r);
    			::ScrollWindow(hWnd, 100, 0, 0, r);  // doesn't work, -100 doesn't work either
    		}
    		return 0;
    	}
    	printf("%x ", uMsg);
    	return CallWindowProc(wpOldMenuProc, hWnd, uMsg, wParam, lParam);
    }
    
    In OnInitDialog, install menu window proc:
    	// TODO: Add extra initialization here
    	WNDCLASS wc;
    	GetClassInfo(NULL, _T("#32768"), &wc);
    	wc.hInstance = AfxGetApp()->m_hInstance;
    	wpOldMenuProc = wc.lpfnWndProc;
    	wc.lpfnWndProc = (WNDPROC)MenuWndProc;
    	SetLastError(0);
    	RegisterClass(&wc);
    
    // in OnSysCommand or wherever, create and track the popup menu:
    	CMenu	menu;
    	menu.LoadMenu(IDM_TEST);
    	CMenu	*mp = menu.GetSubMenu(0);
    	CMenu	*pPopup = mp->GetSubMenu(0);
    	pPopup->DeleteMenu(0, MF_BYPOSITION); // remove placeholder item
    	for (int i = 0; i < 60; i++) { // add enough items to exceed screen height
    		CString	s;
    		s.Format("item%d\n", i);
    		pPopup->AppendMenu(MF_STRING, 1000 + i, s);
    	}
    	mp->TrackPopupMenu(0, 100, 100, this);
    	return;
    Last edited by ckorda; July 8th, 2014 at 02:21 PM.

  13. #13
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: scrolling popup menu via Page Up/Down

    The virtual keycodes for pageup/down etc in wparam are described here http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx. If you are not getting messages for pageup/down what does your message loop code look like?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  14. #14
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: scrolling popup menu via Page Up/Down

    Quote Originally Posted by ckorda View Post
    it provides me with the menu's window handle, even for nested popups
    You may be missing a key point about Win32 API design. Generally it's not enough to have a window handle to control the window behavior. Your window must implement some particular control API by defining certain messages it is agree to comply with, maybe along with some data exchange protocol.

    Once your window does not implement this, your messages you send to it will be just ignored, i.e. drained down to DefWindowProc with no visible effect. Which means that once menu window does not process page keys, and provides no other API to be controlled with the way you need, you have no option but to accept this humbly.

    Subclassing menu window is going to be of no value either. What would be your design for intercepting page keys in your subclassed window procedure? You will catch those, but what will you do to make the menu to change item selection? AFAIK, menu does not provide such API.
    Best regards,
    Igor

  15. #15
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: scrolling popup menu via Page Up/Down

    "subclassing" in windows terminology does not mean "derive a class from a base class (such as CWnd).

    rather, it means "replace the windows' messageloopprocedure with my own". SO it doesn't matter if CMenu is or isn't derived from CWnd. what matters is that what windows is concerned, it's a control with a window and a messageloop and you can "subclass" the actual Windows window. (See http://msdn.microsoft.com/en-us/libr...v=vs.85).aspx)
    WIth MFC, this is typically done by rewiring the messageloop into that other object that has a messageloop... a CWnd (or derived). Even if the windows you're replacing fron has nothing to do at all with CWnd.



    You can change the active selection in a menu programmatically with SetMenuItemInfo (MFS_HILITE to turn it on, MFS_UNHILITE to turn it off).

Page 1 of 2 12 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured