From: Robert M. <rob...@us...> - 2007-04-27 19:40:10
|
Glenn Linderman wrote: > So I have a menu that has dynamic entries, that can grow quite long. > There seem to be no particular limits on how many entries a menu can > have, but when it exceeds the size of the screen, you get these > annoying up and down arrows at the top and bottom. They can be used > to scroll the contents of the menu. That is not as annoying as not > being able to access the menu entries at all, of course, but the >scrolling behavior is relatively slow. I've not seen it before, and here on my win98 box it looks horrible, as well as being slow. > I'm aware (I've used this feature for fixed size menus) that I can > add columns to a menu explicitly by doing stuff like: > > $m_config->{'sUpdate'}->Change( -menubarbreak => 1 ); Right. > but I was wondering if there is a way to get Windows to figure out > how many entries will fit vertically, and add the breaks >automatically? Not that I'm aware of. > If not, then I am wondering how to do the size calculations... I can > get the screen size, I can get the position of the mouse when the menu > is invoked, but I'm not sure how to get the vertical or horizontal > size of a menu item... Windows seems to calculate those automatically > when displaying them, so I'm sure there is a way, somewhere... but I > haven't found it. I haven't even found documentation for the > existence of the scrolled menus... I was expecting there to be a GetSystemMetrics() call to get the vertical size of a menu, but it appears there is not. I found a very likely looking API call - GetMenuItemRect (see code at end) - but having played with it I can't make it give me the correct dimensions until after the menu has been displayed at least once, and you really want the dimensions *before* the menu is displayed :-( It also sees to give the location (in window co-ordinates), as if the menu was to be drawn in it's 'normal' position, although this wouldn't be a problem for you, as you only want the height, not the absolute position. Note, also, that although I haven't checked I'm pretty sure that separators have a smaller height than regular menu items, so you would need to take this into account. > The Windows Start / Programs menu is an example of where Windows > uses one type or the other (scrolled, or multi-column). From what I've read the start menu isn't a real menu at all, and when it's in it's scrolling mode it's actually a custom drawn pager control. > Here's a related question that might not be related at all... is > there any way to use a real vertical scrollbar, instead of the up/down > arrows, when displaying a large menu list? Some way to constrain the > overall height, but add a scrollbar to scroll the items, kind of like > the way a list box does it? I'm pretty sure there's not. > [OK, one solution would be to dynamically choose whether to use a menu > or a list box based on the size of the list, I suppose... but that > would require quite different code for the two cases, especially if > one has to deal with submenus....[I don't have a reference where > Windows uses a scrollbar for menus, which makes me doubt the existence > of this type of solution.]] You could always uses a Listbox - You'd only need one set of code. As an alternative, you could look at the code in my CoolBar module (http://www.robmay.me.uk/win32gui), simulate your menu bar using a toolbar, and have a real listbox that you position and size as a result of a click on one of the buttons. In general the UI experience of having to pick one item from a very long, flat, list needs re-thinking - but without knowing more about what you are trying to get the use to do, it's hard to know if the general rules apply here. Regards, Rob. #!perl -w use strict; use warnings; use Win32::GUI qw(CW_USEDEFAULT WM_ENTERMENULOOP); use Win32::API(); Win32::API->Import('user32', 'GetMenuItemRect', 'LLLP','L') or die; my @array = map { +">Item$_" => "Item$_" } (1 .. 60); my $menu = Win32::GUI::Menu->new( "File" => "File", @array, ); my $mw = Win32::GUI::Window->new( -left => CW_USEDEFAULT, -size => [400,300], -menu => $menu, ); $mw->Hook(WM_ENTERMENULOOP, \&show); $mw->AddButton( -text => 'Show Size', -pos => [10,10], -onClick => \&show, ); $mw->Show(); Win32::GUI::Dialog(); $mw->Hide(); exit(0); sub show { my $rect = pack("LLLL", 0,0,0,0); my $result = GetMenuItemRect( $mw->{-handle}, $menu->{File}->{-handle}, 11, $rect, ); if (! $result) { print "Result: $result ($^E)\n"; } else { print "Result: $result\n"; my ($l, $t, $r, $b) = unpack("LLLL", $rect); print "$l, $t, $r, $b\n"; } return 1; } __END__ |