look,at,the,new,icon,oficon是什么文件夹意思

您要找的是不是:
prep. 在(表示存在或出现的地点、场所、...
If a cell in state k has a neighbor in state k + 1, then that cell has a new state of k + 1 at the next tick of the clock.
如果一个细胞的状态是k,它有一个邻居的状态是k +1,那么该状态在下一时刻将会有一个新的状态k +1。
Google+ launched at the end of June and has had more than 20 million unique visitors, according to comScore, though it's unclear whether the visitors have become loyal users.
Google+于6月底推出,据comScore的数据,目前唯一访问者超过2,000万,但不清楚访问者是否成为了忠实的用户。
The +xml at the end of the subtype tells the processors that it? (TM)s XML, the x- warns them that this is an unregistered type, and the tvml tells them what kind of data it is.
子类型后面的 +xml告诉处理程序这是XML,x- 则警告说这是未注册的类型,tvml 说明是什么类型的数据。
Parijata Mackey, chief science officer at Humanity + and a member of the DIY Bio community, has pointed out that "hobbyist biology is still in its infancy."
帕里加塔·麦基是Humanity+的首席科学官和生物DIY社团的一员,他指出「生物爱好者仍处于起步阶段。」
Imagine what’s coming into that “send feedback” inbox that’s at the bottom of every G+ page?
你能想象在每个Google+页面底部的“sendfeedback”的收件箱会有多恐怖吗?
Mouse over the new YouTube icon at the top right of Google+
光标移到Google+右上角新出现的Youtube图标;
To speed accreditation, please fax copies to the FAO Media Office at +39 06 5705 3729 to the attention of Ms. Maria Barroso.
为了加快核准采访,请向粮农组织媒体办事处发送传真(+390657053729),并注明Ms.MariaBarroso收。
Yamaha is taking commercial audio into a new realm at Prolight+Sound 2010, with the first European demonstration of its Thin Light Flexible (TLF) loudspeaker technology.
德国Prolight +Sound2010专业灯光音响展览会上,雅马哈公司第一次于欧洲展示其TLF薄轻巧型扬声器,并以之将商业音响设备引至一个全新的领域。
The timeframe of the charts can be specified using the + and – buttons at the right of a chart. To look at the data in the tree, complete the following steps
可以使用图表右边的 +和 –按钮指定图表的时间段。
To learn or manifest a power, a psychic rogue must have an Intelligence score of at least 10 + the power's level.
要发掘或展现一道异能,灵能游荡者至少需要有10 +该异能能级的智力值。
These are proven by analysis of capacity of the algorithm based on the example of section BK14+599 at assistant tunnel B of Jinping second stage hydropower station.
基于锦屏二级水电站辅助洞BK14+599断面的算法性能分析证实了这一特性。
To get going, click on the + button on the toolbar at the top of the PerfMon screen. This brings up a dialog that lets you choose the counters you want to monitor, as in Figure 3a.
请在PerfMon窗口上方的工具栏中单击 +按钮,这样会打开一个对话框让您选择要监控的计数器,如图3a 所示。
Ageing populations will most rapidly impact developed regions where the percentage of people 65+ is increasing at an annual rate of 1.6%, the fastest ever.
人口老龄化会最迅速的影响发达的地区,在这些地区65岁以上人口的比例以每年1.6%的比例增长,这个比例是有史以来最大的。
At present, the observation of PSR1913+16 is the only available proof of gravitational wave, even though merely an indirect evidence it is.
目前为止,对PSR1913+16致密双星辐射阻尼效应的观测,仍然是引力波存在性的唯一间接证据。
Comparison shopping at the best prices. 100 + mirrors to enlarge our range of magnification 10 times 3 times.
比较购物最好的价格。100 +镜子在我们的范围内放大3倍至10倍的放大倍率。
Results The brain Ca2+ content was not change at unit volume of fresh cerebral tissue, CaM content and PDE activity rose significantly at that time and 12 hours of the brain damage.
结果脑损伤后单位体积湿重脑组织含钙量变化不明显,钙调素含量及磷酸二脂酶活性分别在损伤后即刻及12小时明显升高。
The apparent steady state kinetics of the aminoacylation reaction catalyzed by LeuRS at the participation of some RE 3+ was studied.
对部分稀土离子参与下的氨酰化反应表观稳态动力学性质进行了研究。
The foundation soil in connection section on southern bank is mainly composed of loess. At the south of section marked 1+200, there is …
南岸连接段地基土主要由黄土组成,在桩号1+200以南存在一层软塑状土,强度低,是影响渠坡稳定的关键性土层。
The Easter Brunch is priced at RMB268 + 15% service charge, inclusive of one glass of Champagne;
复活节早午餐每位人民币268元另加15%服务费,含香槟一杯;
My neighborwas an elderly retired woman (80+ seemed ancient to me at that age) whowas the widowed wife of a retired steel worker.
我的邻居是个退休的老太太(80多岁对我那个年纪的年轻人来说够老的了),一位已故钢铁工人的遗孀。
The value of a cell at time t + 1 will depend only on the value of that cell and its immediate neighbors to the left and right at time t.
细胞在时间t +1的值将只取决于这个细胞和它的左右邻居在时间t时的值。
The Visual C++ team is already hard at work on the next major version of Visual C++ and is hoping to address even more performance and scalability issues in the future.
Visual C++团队已经在为下一个主要版本的Visual C++努力工作,并希望能在将来解决更多的有关性能和可缩放性方面的问题。
Send an email to Adam Pash, the author of this post, at tips+.
发送邮件给本文的作者,AdamPash,他的邮箱是tips+.
These are defined in such a way that models at level (n) are compliant with models at any of the higher levels (n+1, etc.).
它们是这样被定义的,层(n)的模型服从于任何比它更高的层(如n+1)所定义的模型。
Scientific evidence suggests that the effects of distributing gases at 30,000ft+ are considerable.
科学证据证明在30,000英尺以上排放气体的影响相当巨大。
The overhead averages about (M+B) bytes (ignoring the pointers at the beginning of each memory block).
内存开销大约为 (M+B)个字节(每个内存块开头的指针忽略不计)。
The overhead averages about (M+B) bytes (ignoring the pointers at the beginning of each memory block).
内存开销大约为 (M+B)个字节(每个内存块开头的指针忽略不计)。
点击关注有道词典
$firstVoiceSent
- 来自原声例句
请问您想要如何调整此模块?
感谢您的反馈,我们会尽快进行适当修改!
请问您想要如何调整此模块?
感谢您的反馈,我们会尽快进行适当修改!Alleged working iPhone 6 images and video leaked, showing new Passbook payment icon | iMoreGive Your Applications the Hot New Interface Look with Cool Menu Buttons
Paul DiLascia
This article assumes you're familiar with MFC
Code for this article:
Paul DiLascia is the author of Windows ++: Writing Reusable Code in C++ (Addison-Wesley, 1992) and a freelance consultant and
writer-at-large. He can be reached at
In one of my recent columns,
I showed you how to implement the new flat-style toolbars and coolbars found in the Office 97 products, like Microsoft Outlook™ and Visual Studio™ 97 (MSJ, ). At the end of the column, I made a crack that everyone would want the new menus next. Well, sure enough, many of you sent email asking how to add buttons to your menus. Naturally I was excited by the prospect of writing code that people were clamoring for.
Implementing the buttons seemed like an easy enough task—and, in theory, it was. Kinda sort of. It ended up over a thousand lines. Along the way I ran into so many quirks, pitfalls, and oddities that I decided the subject deserved a full article. If nothing else, it will amaze and amuse you to see how bizarre Windows(R) can be. Amusing, that is, if you can somehow manage to keep from going postal.
GUI Fashion Rage
It seems that every couple of years, Windows-based programs get a new look. Someone comes out with a new idea like toolbars or 3D controls or Tommy Hilfiger prop sheets (just kidding) and everyone else has to follow suit. The latest ne plus ultra in GUI couture is what I call the cool look (for lack of a better term), since it includes the coolbars in the comctl32.dll that ships with Microsoft Internet Explorer 3.0. (See Strohm Armstrong's article in the October and November 1996 issues, and my
1997 C++ Q&A columns.) The Microsoft Office 97 products and Visual Studio 97 have their own homegrown coolbars.
In addition to coolbars, the new look incorporates menus with button bitmaps (see Figure 1). The idea is that showing the bitmap next to the command helps users learn which buttons perform which commands—the same way menus show accelerator names to help you learn keyboard shortcuts. I'm not sure whether to me it seems like what my graphic designer friends call screen junk. But then I thought the same thing about toolbars when they first came out. (Screen junk is a highly technical term—for an example, see Figure 2.)
Figure 2 Screen Junk
Now I'm willing to bet a nickel that Microsoft will eventually incorporate cool menus into a new DLL, but for those of you who simply can't bear to be seen in anything less than up-to-the-minute GUI fashion chic, I'll show you how to implement cool menus ASAP. My cool menu manager can be installed in less time than it takes to compile your app, or in about thirty seconds if you type fast. Really.
Cruising the Cool Menu Manager
CCoolMenuManager is a C++ class I wrote to do cool menus in MFC apps. To use it, all you have to do is plop an instance in your frame window and call two functions:
class CMainFrame : public CFrameWnd {
CCoolMenuManager m_menuM
// (in your CMainFrame::OnCreate)
m_menuMgr.Install(this);
m_menuMgr.LoadToolbar(IDR_MAINFRAME);
That's it. That's all there is! The toolbar need not be displayed, or even instantiated as a CToolBar object. It only has to exist in your resource file. If you have more than one toolbar, you can call LoadToolbars (note the s).
static UINT toolbars[] {
ID_TOOLBAR_FILE,
ID_TOOLBAR_EDIT,
ID_TOOLBAR_FORMAT,
m_menuMgr.LoadToolbars(toolbars, 3);
I wrote LoadToolbars because it makes me weep when I see code like this:
menuMgr.LoadToolbar(IDR_TOOLBAR1);
menuMgr.LoadToolbar(IDR_TOOLBAR2);
menuMgr.LoadToolbar(IDR_TOOLBAR27);
That kind of repetitive, open coding typical of SDK sample programs is one reason there are apps that take over 80MB on disk. It announces to anyone who reads your code: &I am an ignoramus.&
In any case, you can see how easy CCoolMenuManager is. Just create an object and call two functions. In addition to that basic picture, CCoolMenuManager offers some extra features that I'll discuss a bit later. For example, there's a flag that lets you turn the buttons on or off:
// turn menu buttons off
m_menuMgr.m_bShowButtons = FALSE;
I used m_bShowButtons in my demo program ROPView (described later) to implement a View | Hide Menu Buttons command. This will be well-appreciated by grumpy hackers like me who think retro is the ultimate GUI fashion statement. (Soon, the world will catch up to my advanced taste—I predict that before the year 2005, Windows will revert to its 3.1 look.)
Inside CCoolMenuManager
If all you want is buttons in your menus, you can stop reading, download the code from MSJ, add the four lines to your app, and compile. Then tell your boss you spent hours working late and deserve a raise. But if you're the type who takes your toys apart, keep reading. I'll show you how CCoolMenuManager works. As I said earlier, it's quite amusing. Plus, there are plenty more goodies in store.The basic strategy behind CCoolMenuManager is simple. When the user invokes a menu, CCoolMenuManager converts every item to an owner-draw item that draws itself exactly the same way Windows does—using the same font, colors, and so on—with the added feature of drawing a bitmap in the left margin of every command that has a toolbar button. When the user is finished with the menu, CCoolMenuManager converts all the items back to their original state. Like I said, simple. But the problem with Windows isn't understanding what you want to do, it's getting Windows to understand, too.
Let's begin when your app calls LoadToolbar. ( shows the source code so you can follow along.) LoadToolbar loads the bitmap first, then the toolbar. Remember, a toolbar resource is actually two resources with the same ID: a bitmap and a toolbar. Each step requires a trick.
The first trick is converting the bitmap from gray to the current 3D color scheme. MFC does this with the function AfxLoadSysColorBitmap. It converts the four shades—white, gray, dark gray, and black—to the current 3D system colors. MFC uses this function in its own CToolBar::LoadToolbar, but since AfxLoadSysColorBitmap requires module instance and resource handles, which I'm too lazy to get, I wrote a wrapper that lets you give just the resource ID.
HBITMAP hbmToolbar =
PxLib::LoadSysColorBitmap(nID);
PxLib is a namespace I use for helper functions like these to avoid name collisions.
The second trick to loading toolbars is knowing what a toolbar resource looks like in memory. This you can discover from bartool.cpp in
// RT_TOOLBAR resource
struct TOOLBARDATA {
// should be 1
// bitmap width
WORD wItemC
// num items
WORD items[wItemCount];
// item IDs
The actual size of the TOOLBARDATA the items array has wItemCount items. The nth word in the array is the command ID for the nth button in the bitmap, or zero for a separator. Figure 4 illustrates this. TOOLBARDATA is an MFC there's no RT_TOOLBAR defined in winuser.h like there is for RT_ICON and RT_BITMAP—it's in afxres.h. But the resource compiler knows how to process the TOOLBAR statement, and the Developer Studio IDE knows how to generate it.
TOOLBARDATA
Once LoadToolbar loads the bitmap and TOOLBARDATA, it performs a few sanity checks and—assuming everything comes out clean—adds the bitmap to its image list, m_ilButtons, which contains all the bitmaps of all the loaded toolbars. Next, LoadToolbar adds the command IDs to its button map, m_mapIDtoImage. This association map (CMapWordToPtr) maps each command ID to its index in the image list, so m_mapIDtoImage[nID] is the image list index of the button associated with the command nID. For example, in my demo program ROPView (described later), m_mapIDtoImage[ID_FILE_NEW] is zero since File New is the first button in my toolbar bitmap.
In theory, using CMapWordToPtr instead of a normal array makes looking up IDs faster. I encapsulated the lookup in GetButtonIndex because it's more comprehensible than writing (int)m_mapIDtoImage[nID]. C++ operator overloading is cute, but it's usually clearer to use English names than some cryptic a[i] notation that requires a trip to the header file to grok.
Hooking Messages: CSubclassWnd
Once your app calls LoadToolbar or LoadToolbars, the menu manager has an image list and a way of mapping command IDs to bitmaps. The next step is to seize control of the menus. To do that, the menu manager needs to handle several messages: WM_INITMENUPOPUP, WM_MEASUREITEM, and WM_DRAWITEM, among others. How does CCoolMenuManager get these messages? This is where life gets interesting.
The most obvious way would be to derive a CCoolMenuFrame from CFrameWnd, and let you derive your CMainFrame from CCoolMenuFrame. Then CCoolMenuFrame would have its own message map and handler functions. But this approach is problematic because your app may already be deriving its CMainFrame from some other library class: CXyzFrame. This problem is inherent in C++, where the entire window class hierarchy must be rigidly speci there's no way to derive classes dynamically at runtime, which is exactly what you need to do in this situation.
Another way would be to implement CCoolMenuManager as a non-window class with handler functions for your app to call. In this scenario, the application programmer (that's you, Sherlock) must implement the handlers, but all they do is call the menu manager:
void CMainFrame::OnInitMenuPopup(...)
m_menuMgr.OnInitMenuPopup(...);
Likewise for all the other messages. This avoids the tyranny of the rigid C++ class hierarchy, but it still makes you write many lines of code—and what if you forget one of the handlers? In order to make using CCoolMenuManager totally idiot-proof, I used my CSubclassWnd class (formerly CMsgHook), first described in my MFC Goodies article in the
MSJ. There I used CMsgHook/CSubclassWnd to implement a generic palette message handler. I used CSubclassWnd again in my
column to implement a generic custom caption painter.
CSubclassWnd is the perfect solution whenever you want to handle messages on behalf of a window without changing the window class hierarchy. In essence, CSubclassWnd turns the clock back by letting you do in C++ what you could always do in C: namely, subclass a window dynamically. CSubclassWnd subclasses the window by installing its own window proc, one that passes all messages to a virtual WindowProc function. Specific CSubclassWnd-derived classes like CCoolMenuManager must override this function to do stuff:
LRESULT CCoolMenuManager::WindowProc(UINT msg, WPARAM wp,
LPARAM lp)
switch(msg) {
case WM_MEASUREITEM:
if (OnMeasureItem((MEASUREITEMSTRUCT*)lp))
return TRUE; // handled
case WM_DRAWITEM:
if (OnDrawItem((DRAWITEMSTRUCT*)lp))
return TRUE; // handled
return CSubclassWnd::WindowProc(msg, wp, lp);
Hey, it looks just like it did in the old days—switch case and all! Note that CCoolMenuManager::WindowProc calls CSubclassWnd::WindowProc if it doesn' this is essential. CSubclassWnd::WindowProc routes the message back to MFC—to AfxWndProc, to the CWnd and its message map, and to your handlers. CSubclassWnd is similar to CWnd, but it's not derived from CWnd. It's just an ordinary CObject. Most important, unlike CWnd you can have any number of CSubclassWnd objects &attached& to the same window. Within each CSubclassWnd object, the subclassed window is stored in a data member, m_pWndHooked. To hook the whole thing up, something has to call CSubclassWnd::HookWindow. For CCoolMenuManager, the Install function does it:
void CCoolMenuManager::Install(CFrameWnd* pFrame)
m_pFrame = pF
HookWindow(pFrame);
// (in CSubclassWnd)
Just to make sure you don't call any CSubclassWnd functions, I derived CCoolMenuManager privately from CSubclassWnd. This follows the general C++ paradigm that you use a private derivation when the base class is used to implement the derived class, whereas you use a public derivation when the relationship represents true inheritance (&is a&). If you want to learn more about CSubclassWnd, check out the
issue of MSJ, or download the source code.
Setting Up Owner-Draw
Now that you know how the menu manager handles messages, I can describe the actual handlers. When the user invokes a menu, Windows sends your frame a WM_
INITMENUPOPUP message. CCoolMenuManager::WindowProc intercepts it and passes control to OnInitMenuPopup, which in turn calls ConvertMenu. This rather large and unwieldy function is the heart of CCoolMenuManager. It converts menus from string to owner-draw and back.
Assuming m_bShowButtons is TRUE, ConvertMenu
loops through all the menu items, changing each one to MFT_OWNERDRAW and creating a CMyItemData for each one. Whenever you implement owner-draw menus (or buttons, or whatever), you get to store your own DWORD as the item data. Normally, it's a pointer to some structure of your own design:
struct CMyItemData {
The CString is the item text, like &Open or E& iButton is the index into the image list of the button for this item, or -1 if there isn' and fType holds the original item's type flags, which I use later to restore the item. The magicNum field always stores the same four ASCII bytes: mid0 (My Item Data—version 0). CCoolMenuManager uses this to recognize its own owner-draw items, as opposed to other owner-draw items you may have in your app. I never tested it, but in theory you should be able to mix your own &true& owner-draw items with CCoolMenuManager.
As OnInitMenuPopup allocates each CMyItemData, it copies the item name and style flags, then stores the item data in the menu. It does this only if the item is not already owner- if it is owner-draw, OnInitMenuPopup does nothing. So the first time you invoke a particular menu, CCoolMenuManager converts all the items to owner-draw. But if you move the mouse to another menu—from File to Edit, say—then revisit the File menu, the second time around OnInitMenuPopup does nothing because the menu is already converted.
All this sounds straightforward enough, but there are several subtle points that bear elaboration. First, to get information about the menu items, I use a Win32(R) API function that has no MFC wrapper: GetMenuItemInfo. Instead of calling GetSubMenu, GetMenuItemID, and GetMenuString, GetMenuItemInfo lets you get all the info in one fell swoop. Also, it's the only way to get the owner-draw item data. Likewise, after OnInitMenuPopup determines what menu info it wants to change, it calls SetMenuItemInfo to set everything with one API call. To make life easier and a little more bulletproof, I implemented my own CMenuItemInfo (derived from MENUITEMINFO) with a constructor that zeroes the struct and sets cbSize. These little details are easy to forget, and when you do you're likely to spend several minutes in the debugger wondering why your code doesn't work.
One of the many gotchas that got me when I first wrote OnInitMenuPopup has to do with CCmdUI::SetText. My demo program, ROPView—which I still haven't formally introduced, but which you've probably guessed by now is the app I used to test all this stuff—has a command to turn the buttons on or off. ROPView has an ON_UPDATE_COMMAND_UI handler to dynamically change the name of this command based on the current state.
CMainFrame::OnUpdateViewMenuButtons(CCmdUI* pCmdUI)
pCmdUI-&SetText(m_bShowMenuButtons ?
&Hide &Menu Buttons& : &Show &Menu Buttons&);
What I discovered, to my dismay, is that CCmdUI::SetText changes the menu item to MFT_STRING—clobbering my MFT_OWNERDRAW style!
// in CCmdUI::SetText
UINT nState = m_pMenu-&GetMenuState(...);
nState &= ~(MFT_BITMAP|MFT_OWNERDRAW|MFT_SEPARATOR);
m_pMenu-&ModifyMenu(... MFT_STRING | nState ... );
Well, shoot. But it makes sense. If you're setting the text of a menu item, it has to be a string, right? Conceptually, all the items in a c it's just that I've implemented them as owner-draw so I can draw the darned buttons.
At this point I was thoroughly frustrated. It looked like I'd have to implement a new CCmdUI class for cool menus, one whose SetText function set the text in CMyItemData instead of calling ModifyMenu. Then I'd have to hook it into the whole command update mechanism—all of which would require copying dozens of lines of MFC code just to modify a few because this is one area where MFC doesn't give you the virtual functions you need. So I did what I always do in such circumstances, which is mow the lawn.
As I trudged across the green, I suddenly had an inspiration. The problem is that CCmdUI::SetText changes my menu items to strings. So? I can change them back to owner-draw. I even have a function to do it.
When I first wrote CCoolMenuManager, I handled WM_INITMENUPOPUP like so:
// in CCoolMenuManager::WindowProc
// This is WRONG!
switch(msg) {
case WM_INITMENUPOPUP:
OnInitMenuPopup(...);
return CSubclassWnd::WindowProc(...);
When processing WM_INITMENUPOPUP, it's important to let CSubclassWnd process the message, too (as opposed to returning). That lets CFrameWnd::OnInitMenuPopup get it, which is where MFC does all its magic command update UI stuff for menu items. It's where MFC creates a little CCmdUI object for each menu item and routes to your ON_UPDATE_COMMAND_UI handlers, and where those handlers might call CCmdUI::SetText to clobber my owner-draw items.But the question is, should CCoolMenuManager process WM_INITMENUPOPUP first, and then let CSubclassWnd/CFrameWnd get it—or the other way around? The first time I wrote the code, I did it in the first order—CCool-MenuManager first, then CFrameWnd—not because I thought about it, but because I figured it didn't matter. But it does! If I let CFrameWnd handle WM_INITMENUPOPUP first, then it's OK if some ON_UPDATE_COMMAND_UI handler calls CCmdUI::SetText to blow my owner-draw menu item out of the water, because the menu manager will fix it when it gets control afterward. So the correct code is:
case WM_INITMENUPOPUP:
// Let frame window handle it first!
CSubclassWnd::WindowProc(...);
OnInitMenuPopup(...);
Now if MFC changes an item to MFT_STRING, CCoolMenuManager::OnInitMenuPopup will call ConvertMenu, which changes it back to MFT_OWNERDRAW. I had to modify the logic in ConvertMenu slightly to never assume that once it had converted the menu it would stay converted, and also to adjust for the fact that when MFC modifies the item to MFT_STRING, the item data (CMyItemData) is still there. Apparently, when you call ModifyMenu to change a menu from owner-draw to string, Windows isn't smart enough to zero-out the item data. The old item data is still there, so there's no need all I have to do is update the item name. It's all very delicate and a bit hairy—as well as serendipitous—but it flies OK.
The last ConvertMenu problem has to do with the system menu. That's the menu that pops up from the icon at the left end of the title bar (see Figure 5). Old-time Windows hackers know you don't ever munge the system menu directly—for example, to add your own commands—but instead call GetSystemMenu to first create a copy. The app may or may not have done this, so to be safe, ConvertMenu simply ignores system commands (any command in the system menu that has an ID &= 0xF000).
Measuring Menu Items
At this point, the user has invoked a menu, Windows has sent WM_INITMENUPOPUP, and the menu manager has converted it to an owner-draw menu. Now what? Windows asks the frame to draw the menu. But first it has to know how big the menu is, so it sends the frame a WM_MEASUREITEM message for each item. CCoolMenuManager::WindowProc intercepts the message using its CSubclassWnd trick, and calls OnMeasureItem to measure the item. This function calls DrawText with the DT_CALCRECT flag to compute the size of the text, adds some extra space for margins, and returns the result to Windows in the MEASUREITEMSTRUCT. Very simple and straightforward, but once again you have to remember you're dealing with Windows.
The first problem is getting the menu font. To do that, you have to call ::SystemParametersInfo.
NONCLIENTMETRICS
info.cbSize = sizeof(info);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(info), &info, 0);
font.CreateFontIndirect(&info.lfMenuFont);
I encapsulated the font-creation process in GetMenuFont, which creates the font in a new member, m_fontMenu.
The next problem comes in computing the size of the item. The height is easy, just use GetSystemMetrics(SM_CYMENU) or the height of the text, whichever is bigger. The width is a little more complicated. It's the width of the text plus a bunch of margins and spacing defined by some const symbols. I'll spare you the gory minu Figure 6 tells the story. If you do this on your own, just remember: it's important to get this stuff right, down to the last pixel.
Menu Metrics
Once you've added up all the pixels, you're still not ready to return from OnMeasureItem because this is where you run into Windows kludge #1: whatever value you return in MEASUREITEMSTRUCT as the itemWidth, Windows will add the width of a checkmark. Oh, of course. Why didn't you think of that? Actually, experience shows that Windows adds one less than this value, so to make your menu item come out exact, you must subvert the Windows logic by subtracting from your final desired value:
lpms-&itemWidth -= GetSystemMetrics(SM_CXMENUCHECK)-1;
OK, I did that—proud that I'd remembered this piece of trivia from the old days, even if it was a waste of precious neurons. But that's not the end of the story. Even after I coded the fudge factor, my menu items still came out too wide. Try as OnMeasureItem might to tell Windows the width was x, Windows insisted on calling my draw function with x+30. And the strange thing is, it only happened for some menus!
I figured I must finally be losing my marbles. (Too much Windows programming isn't healthy, you know.) Since the lawn was already mowed, there was nothing to do but pull my hair and gnash my teeth. Eventually, I noticed that the width &correction& only occurred in popups that contain separators. Hmmm... something to do with separators.
In my original implementation of OnInitMenuPopup, I didn't bother to make the item owner-draw if it was a separator (MFT_SEPARATOR). Why should I bother to draw a separator when Windows can do it? Well, now I know the answer: if you let Windows draw the separators, it performs its own width calculations. It seems to add 30 pixels to the largest width returned from WM_MEASUREITEM. The truly astonishing thing is, what possible algorithm could ever cause the existence of a separator to make the menu wider? The lesson is, if you want to take over the menu, you have to do separators, too. Once I did that, my widths came out exact.
Drawing the Items
OK, it's almost halfway into the article and your computer still hasn't displayed the menu yet. But I'm almost there. Once Windows has measured the menu, it creates the menu window, sets up a device context and finally sends your frame a WM_DRAWITEM message, one for each item. Once again, CCoolMenuManager traps the message, and passes it to yet another function, OnDrawItem. Finally, it's time to draw the item! Using the Microsoft Office 97 products as my model (they're slightly different from Visual Studio), I drafted the following spec for how to draw menu buttons:
If a menu item has a button that is unselected (unhighlighted), the button should have the flat look (no 3D border).
If a menu item has a button that is selected (highlighted), the button should have the 3D popped-out look (button is up).
If a menu item has a button and the command is checked, the button should have the pushed-in look (button is down) with a light (item unselected) or normal (selected) background color.
When an item is checked but has no button, draw as above (3D pushed-in with changing background) using the standard checkmark or whatever bitmap is specified in the MENUITEMINFO.
If a menu item with a button is disabled, the button should appear with the disabled, embossed look.
As I pondered the possibilities (difficult as it is to restrain your fingers, it's always good to ponder before you type), it all seemed pretty straightforward. Dra CImageList::Draw does that. Coloring backgrounds and drawing 3D edges are likewise pretty simple. But how do you draw a disabled button? This turned into a major piece of detective work.
Figure 7 ROPView—An Exploration Tool
CImageList::Draw (ImageList_Draw) has a bunch of style flags for drawing images in different states. Perhaps it can draw disabled buttons? Not trusting the documentation, I wrote a little program to explore it. This program evolved into ROPView, which serves as both demo program and Windows exploration tool. Figure 7 shows what happens when ROPView draws my toolbar bitmap with each of the different ImageList_Draw flags. It's all quite interesting, but I don't see anything that looks like a disabled, embossed button. That's because ImageList_Draw was designed for drawing desktop/folder icons in different states, not disabled buttons.
Further searching through the docs, MSDN, and ultimately winuser.h uncovered a new Win32 function: DrawState. According to the documentation, &The DrawState function displays an image and applies a visual effect to indicate a state, such as a disabled or default state.& Well, this must be my lucky day! It took a few minutes to grok the arcane, combine-seventeen-functions-into-one, assembly language mentality of the Windows API designers, but eventually I managed to wrap my already-overstressed brain around it. Fortunately, MFC has several CDC functions that wrap DrawState's 10 arguments into eight different overloaded varieties that make sense to a human.
DrawState can draw many different kinds of objects, but I'm only interested in bitmaps. As with image lists, there are several flags you can use, including DSS_DISABLED, which—according to the documentation—&embosses the image.& Great! You even get to specify the brush to use to do the embossing. So I quickly added some lines to ROPView to explore what DrawState actually does (see Figure 8).
Figure 8 DrawState/Bitmap View
Now, I'm perfectly willing to admit that I still haven't figured out how to program this function properly. Perhaps tomorrow someone from Microsoft will send me email beginning with &Paul, you idiot!& and telling me all I need to do is select the dooble into the mumble while I touch my left pinky to my sternum and say &Windows is great.& But I tried many different combinations of such things until my fingers were in danger of carpal collapse. At the very least it's fair to say this function is miserably documented. Frankly, I think it just doesn't work.
Figure 9 DrawState/Icon View
So, what else to try in search of the elusive embossed look? Well, probing the cryptic DrawState documentation again reveals that it can also draw icons. Maybe if I first extract the button image as an icon? To make a long story short, Figure 9 shows the result. Much better. So here's the magic code to draw a button image with the embossed look:
HICON hIcon = imagelist.ExtractIcon(i);
dc.DrawState(p, CSize(0,0), hIcon, DSS_DISABLED,
(HBRUSH)NULL);
DestroyIcon(hIcon);
DrawState works fine for government work, and even for CCoolMenuManager, but it's not perfect. Extracting and destroying an icon for every paint operation is a bit on the pokey side. ROPView demonstrates this nicely: if you select the DrawState/Icon view from the menu or coolbar combobox and resize the window, you'll see how slowly it paints. Then select any other view and see how snappily it responds. On the other hand, ROPView draws 12 X 16 = 192 icons, whereas it's extremely unlikely any app will ever have more than five or six disabled buttons in any given popup menu. But for those especially masochistic speed purists like me, I wrote a function, PxLib::DrawEmbossed that draws disabled buttons manually, using BitBlt operations. There isn't space I plan to do so in a future column.
Back to Buttons
Now that I've shown you how to draw disabled buttons, the rest is more or less straightforward. (I almost said easy, but that would be an overstatement.) When Windows sends your frame WM_DRAWITEM, CCoolMenuManager intercepts it and calls OnDrawItem. This function looks rather messy, but the logic is mostly an application of the rules from the mini button spec I presented earlier. I won't take you through it step-by-step, but instead I'll focus on the tough spots.
Figure 10 Popup Menu
The worst part is drawing checkmarks or radio buttons. Figure 10 shows a popup menu with normal and radio-style checkmarks redone with the 3D look. CCoolMenuManager::Draw3DCheckmark is the function that does it. There are two tricks here. The first is getting Windows to use the bitmap for the checkmark:
bm.LoadOEMBitmap(OBM_CHECK);
OBM_CHECK is not normally defined in winuser.h unless you #define the symbol OEMRESOURCE before loading it. So, following in the hack footsteps of MFC, instead of asking you to define OEMRESOURCE in your StdAfx.h, I simply define the symbol I need:
#ifndef OBM_CHECK
#define OBM_CHECK 32760
I guarantee you the value won't change anytime soon. Draw3DCheckmark only uses OBM_CHECK if the menu item doesn't have its own checkmark bitmap. You may not know this, but Windows lets you specify any bitmap to use on a per-item basis for a checked or unchecked menu item. In fact, that's how MFC implements the radio-style menu items you get when you call pCmdUI-&SetRadio from your update handler.
// in cmdtarg.cpp
void CCmdUI::SetRadio(BOOL bOn)
if (afxData.hbmMenuDot = = NULL)
_AfxLoadDotBitmap();
if (afxData.hbmMenuDot != NULL)
SetMenuItemBitmaps(...,
NULL, afxData.hbmMenuDot);
_AfxLoadDotBitmap doesn't actually load the bitmap, but creates it manually. Unfortunately, it does a sad job. Figure 11 shows what MFC generates if you select a large menu font, something you might do if you forgot to bring your glasses to work. Whoever wrote _AfxLoadDotBitmap went to heroic lengths to create a bitmap from raw hex data, when all he or she had to do was call CDC::Ellipse. Go figure.
Figure 11 BadDot
In any case, I couldn't bear letting anyone using my menu code have such a pitiful radio button, so I wrote FixMFCDotBitmap to set the dot straight. This required more subterfuge. MFC stores the bitmap in afxData.hbmMenuDot, but there's no safe way to access afxData since it's a private structure. Instead, I create a menu with one item and set up a CCmdUI object for it. I call CCmdUI::SetRadio(TRUE), then call GetMenuItemInfo to see what bitmap MFC set as the checkmark. Pretty clever. Once I have the bitmap, I draw a proportional dot on it that's centered properly. Just to be nice, I broke out a separate static function, GetMFCDotBitmap, which you can use to customize the radio check your own way.
Astute readers may be wondering: if Windows lets you specify custom checked and unchecked bitmaps for any menu item, why not use them to implement menu buttons in the first place? Nice idea, but it doesn't work for two reasons. First, you only get two bitmaps (checked/unchecked), whereas cool menus need four because the image also depends on the item's selection state. Second, checkmark bitmaps can only be monochrome, not color.
In any case, if the MENUITEMINFO has a custom hbmpChecked or hbmpUnchecked, CCoolMenuM otherwise it
uses the default OBM_CHECK for checked items. Once Draw3DCheckmark has the bitmap, it gives it the 3D treatment: a pushed-in edge with background = COLOR_3DLIGHT (unselected) or COLOR_3DFACE (selected). To get the desired background color, I call SetBkColor on the destination (menu) DC, relying on the fact that the checkmark is a monochrome bitmap. When Windows translates a monochrome bitmap to color, it maps white to background and black to foreground colors. The rest of Draw3DCheckmark is just a lot of painful Cartesian arithmetic to get
the bitmap perfectly centered, something even Visual Studio doesn't do right. The checkmark could be bigger or smaller than the standard
16 X 15 to do it right, you have to anticipate either possibility.
Finally, after whatever button/checkmark is required, OnDrawItem draws the text. This entails drawing the highlighted background, if necessary, and then the text in the proper color. OnDrawItem uses a helper function, DrawMenuText, which draws the text in two stages. First it draws everything preceding the tab character (if there is one) using DT_LEFT for left-justification, then it draws everything to the right of the tab—usually the accelerator key name—using DT_RIGHT. This gives the menus the justified cool look. For disabled text, OnDrawItem draws the text twice: once for highlight, once for shadow. Finally, the item appears on the screen (see Figure 1). Amazing.
Remembering Mnemonics
At this point, the menu is converted, measured, and drawn. Everything looks hunky-dory and works fine, just the way it does in Windows—except for one little problem: menu mnemonics. You know, the letters that have an ampersand that gets converted to an underline, like &File for File. If you type Alt-F to get the File menu, Win but if you then type O for Open or S for Save, nothing happens. Sigh. But, how do you expect Windows to know what to do with keyboard input when you went and changed all the items to owner-draw?
The solution is to reinvent the wheel. WM_MENUCHAR is the message Windows sends OnMenuChar is the CCoolMenuManager function that processes it. It's just a straightforward matter of looking for ampersand-prefixed characters that match what was typed and returning the proper magic code to tell Windows what to do. If there are no matches, if one, return MNC_EXECUTE; if there's more than one match, return MNC_SELECT. In the last two cases, you actually have to return a LONG with the code in the high word and the index of the menu item in the low word. It's all dreadfully tedious, so I'll spare you the details. Note that OnMenuChar applies to accelerator keys remain unaffected by owner-draw because accelerators get translated in the program's main message loop.
Automagic Accelerators
While I was implementing CCoolMenuManager, I had a bright idea. Have you ever found it cumbersome to type accelerator names in all your menus? Say you decide to make Control-G a shortcut for the File | Gobble command. You add the accelerator, but do you remember to add the key name to your menu?
MENUITEM &&Gobble\tCtrl-G&
Even if you're the fastidious sort of person who remembers, what if you have an item whose name you change dynamically by calling CCmdUI::SetText? Do you remember to add the accelerator then, too? And how do you abbreviate Control—Cntrl, Ctl, or Cntl? Personally, I can't be bothered to remember that stuff, so my bright idea was to let the code do it. In addition to all the other neat stuff CCoolMenuManager does, it adds all the correct accelerator names to your menus!
How does it perform this magic? If you remember way back, the very first thing your app did was call CCoolMenuManager::Install.
// in CMainFrame::OnCreate
m_menuMgr.Install(this);
So the menu manager has a pointer to your frame window, which it stores as m_pFrameWnd. From this it can get the handle of your app's accelerator table by calling m_pFrameWnd-&GetDefaultAccelerator. Once it has the HACCEL, it's just a matter of writing a little code to figure out the key names and IDs. The API functions you need are CopyAcceleratorTable and GetKeyNameText. CopyAcceleratorTable copies the HACCEL into an array of ACCEL structures. GetKeyNameText does what its name implies. The mechanics see CCoolMenuManager::
LoadAccel and AppendAccelName for details.
Figure 12 Accelerator
LoadAccel is even clever enough to handle multiple accelerators for the same command. It does this by linking multiple ACCEL
structures, using ACCEL::cmd as an offset to the next ACCEL. The upshot is that if you have more than one accelerator for a command—which is entirely possible—they all appear in the menu, as Figure 12 shows. If you don't want automagic accelerators, you can turn the feature off by setting m_bAutoAccel = FALSE.
Bye-bye Menu
I've shown you how CCoolMenuManager loads the toolbars, traps messages on behalf of your frame, and uses WM_INITMENUPOPUP to convert the menu to owner-draw. I also showed how it measures, draws, processes keystrokes, and even appends accelerators to your app's menu items automatically. The next and almost final step is cleanup. Remember all those little CMyItemData objects allocated in ConvertMenu? I need some way to destroy them before the app exits or else the Memory Police will be hot on my tail. It would be nice if Windows sent a WM_DELETEITEM message when it's time to delete the menu item data—the way it does with owner-draw lists and comboboxes. But no, with menus you have to make your own provisions to avoid memory leaks.
When I first implemented CCoolMenuManager, I simply added all the CMyItemData objects to a list and deleted them in the destructor. Easy. But later I changed the implementation entirely. To understand why, I have to tell you about my mouse.
Theoretical Digression
Before Windows was invented, I programmed for Interleaf on a workstation with a three-button mouse. Ever since, I simply can't live without a three-button mouse. Today I use the Logitech MouseMan, whose driver has the wonderful option of mapping the middle button to double-click. No more nervous finger- I just press the middle button to open something or launch an app. MouseMan has another neat feature: if you press and hold the middle button you can invoke the menu of whatever app you're in. In effect, MouseMan brings the menu to the mouse, so you don't have to move your mouse to the menu. Very cool, and something Interleaf did ages ago.
The MouseMan driver does this by peeking inside the app and grabbing its menus. It feeds the app messages like WM_INITMENUPOPUP and so on to make it think you invoked the menu the normal way. The MouseMan driver is an example of a program that dynamically snoops other app's menus. Other programs that do this are debugging tools that record keyboard and mouse actions, and accessibility products for people with handicaps. For example, Kurzweil has a voice product that reads menus al Microsoft Voice does the same thing.
Many of these products depend on being able to read the menu names as strings. In other words, they depend on the menu items being MFT_STRING; they may not work with owner-draw menus. The MouseMan driver does because it only needs to display the menu, not read the actual text in the items. But other programs that depend on reading the text will be completely bewildered by an owner-draw item. The Microsoft Office 97 and Visual Studio 97 products have the same problem: they fail completely with MouseMan because they don't have menus at all—they implement their &menus& as special command bar classes (msoCommandBar). The Office 97 products also fail with many accessibility products.
Has Microsoft hung blind people out to dry? No, of course not. Microsoft has a whole new scheme for doing accessibility. It's called MSAA.
To make a long story short, in order to make CCoolMenuManager as accessible as possible, I decided to convert all the menus back to strings as soon as the menu is closed. That way, only programs that try to read a CCoolMenuManager-enabled app's menus while they're actually displayed will fail. Programs that read the menus while your app is idle—for example, when the accessibility program starts up—should work fine.
Back to Cleanup
All that was just to explain why I chose to convert the menu back to its original state when I close it. How do you know when that happens? When Windows sends a WM_
MENUSELECT message with a NULL menu and the special flag 0xFFFF. This means the menu was closed because the user either selected a command or clicked outside the menu. Either way, CCoolMenuManager handles the event by calling the same ConvertMenu function used to make the menu owner-draw. Only this time it calls ConvertMenu with bShowButtons = FALSE, in which case ConvertMenu does the opposite of what it did before: it converts all the menu items back to their original MFT_STRING state. In the process, ConvertMenu also destroys all the CMyItemData objects, taking care of my cleanup problem.
There's just one catch. A single trip to the menu bar could end up firing several WM_INITMENUPOPUP messages as the user moves the mouse over File, Edit, View, and so on, whereas Windows only sends one WM_
MENUSELECT (0xFFFF) for the entire trip. So as ConvertMenu converts each menu to owner-draw, it adds the menu to a list. OnMenuSelect then uses this list to know which menus to unconvert.
I added some TRACE diagnostics to help you see what's going on. You can turn them on or off through the static member CCoolMenuManager::bTRACE. Figure 13 shows the output from CCoolMenuManager as I moved the mouse over the Help | About command a couple of times. The menu manager converts the menu to owner-draw, then handles a WM_MEASUREITEM, then handles a few WM_
DRAWITEMs, and finally converts the menu back to strings. It seems so simple, but now you know everything that goes on behind the scenes.
Figure 13 CCoolMenuManager Output
While I chose the convert/unconvert implementation to deal with accessibility as best I could, it turns out that it simplifies a number of things. For example, it's trivial to implement the m_bShowButtons flag. Since the menu is always in its normal (MFT_STRING) state, all OnInitMenuPopup has to do to turn off the cool look is not call ConvertMenu if the flag is off.
Also, because OnInitMenuPopup converts the menu to owner-draw each time, there's no need to do anything special if the user changes the system font, which can affect the size of the menu items. Normally, Windows sends
WM_MEASUREITEM once and never again. This causes a problem if the user c you have to
do something special to get Windows to send WM_
MEASUREITEM again (you have to call ModifyMenu to reset the type to MFT_OWNERDRAW, even though it already is). But the way I wrote it, if you select a new menu font, the code just works.
Of course, converting and unconverting the items every time a user invokes a menu requires a few more CPU cycles—but hey, this is the age of Pentium! It's not as if the user will ever notice.
Coping with Colors
The last problem I have to mention deals with system colors and fonts. This is always an agonizing bugaboo, and few commercial apps get it right (as Figure 14 shows). Not even the Windows Start menu is smart enough to shrink itself if you go from a large font to small font, so you've gotta reboot.
To cope with a changing world, always remember to use GetSysColor and GetSystemMetrics, and don't let any hardwired colors or dimensions sneak into your app. You must handle WM_SYSCOLORCHANGE and WM_SETTINGCHANGE as well.
shows the system colors and metrics used in CCoolMenuManager. As for WM_SYSCOLORCHANGE and WM_SETTINGCHANGE, the most reliable way to handle them is the brute force approach: when you get either message, simply destroy everything and reconstruct the world. This is what CCoolMenuManager does in a function called Refresh. I don't know why so many programs don't handle these messages right because it's really not that hard. Of course, now that I said that, I just know someone is going to find a bug in my code.
There are plenty of other bizarre things to worry about. Take a look at Figure 16. Aside from the ghastly color scheme (apologies to anyone who likes brown), check out that menu! It has the MENUBARBREAK style set on one of the items to make it a two-column menu. The first time I tried this, I discovered bugs where my drawing code assumed the leftmost x-coordinate was zero, which is only true for a single-column menu. I also found what appears to be an extremely nutty bug in Windows: if you have a menu item with a MENUBARBREAK, then all items following the break lose all text following a tab character. You can try it yourself on a vanilla AppWizard app. There's no way to ant you just have to find the bugs one by one—or download the code from someone who already has.
Figure 16 Multicolumned Menu
To demonstrate CCoolMenuManager in action, I wrote a demo program called ROPView. I used ROPView to discover what ImageList_Draw and DrawState actually do with all those different flags. ROPView implements a right-button context menu with some of the same commands that appear in the main menu. Since Windows does the same WM_INITMENUPOPUP/WM_MENUSELECT shtick for context menus too, the menu manager automatically handles them without having to add extra code.
The full source code for ROPView is way too long to print here and not really that interesting anyway.
shows CCoolMenuManager, which is the most important part. Happy programming!
Acknowledgment
I'd like to thank Gerry Polucci of MindStorm Technologies for helping me with CCoolMenuManager. Gerry developed a similar class on his own and sent it to me via email, hoping to publish it in MSJ. Alas, I was already booked for this article. Gerry was nevertheless gracious enough to swap notes, put me onto some good ideas and help me test my code. Thanks, Gerry!
From the January 1998
issue of .
Get it at your local newsstand, or better yet, .
For related information see:
MFC 4.0: The Story Can Be Told, /msdn/library/periodic/periodic/msdnn/news4_6/mfc.htm. Also check
/msdn for daily updates on developer programs, resources and events.

我要回帖

更多关于 icon是什么文件夹 的文章

 

随机推荐