Solved

Programmatically destroying poup menu

Posted on 1997-08-16
20
1,614 Views
Last Modified: 2013-11-20
I need to destroy poup menu from my application and immideatly create
another popup menu. I tried to set WM_CANCELMODE message to menu's owner
window and the call TrackPopupMenu. Old menu is destroyed but the new fails
to create with an error code  "Popup menu already exists". Please help!
0
Comment
Question by:galkin
  • 8
  • 8
  • 2
  • +2
20 Comments
 
LVL 4

Expert Comment

by:mbhakta
ID: 1303939
Try the following method :

- Initialize m_hMenu a variable to NULL.
- Before you create the popup menu do the following :
void xxxFunction(..)
{
   if ( m_hMenu != NULL)
  {
     DestroyMenu(hMenu);
    m_hMenu = CreatePopupMenu(..);
  }
  TrackPopupMenu(..);
}

Make sure you destroy the menu before you kill the application.


0
 
LVL 7

Author Comment

by:galkin
ID: 1303940
DestroyMenu doesn't destroy popup menu
0
 
LVL 1

Expert Comment

by:cnasarre
ID: 1303941
There is an undocumented API in Win16 to do this named EndMenu
(USER.187) and it seems to still exist in USER32.DLL on my
NT 4.0

void FAR PASCAL EndMenu(void);

It works for me in Win16 but I have never tried it in Win32...
0
 
LVL 7

Author Comment

by:galkin
ID: 1303942
I tried to use this function but ispite of the fact old popup menu is destroyed , the new one fails to be created ,I got the same error code(0x5a6 - "Popup menu already active")
0
 
LVL 1

Expert Comment

by:cnasarre
ID: 1303943
I'm not sure that I have understood what you try to do...
You have called TrackPopupMenu() and if the user click
on a menu item, you want to dismiss the current popup menu
and display a new one. Am I right ?

It may be possible that Windows does not allow you to
create a new popup menu from a menu item message handler but this
is only a guess

Try to post yourself a message after having EndMenu()
and create your new popup menu at that time.

Another point : Is it TrackPopupMenu() which fails or
CreateMenu() ?
0
 
LVL 7

Author Comment

by:galkin
ID: 1303944
What I am trying to do is as follows:
I create popup menu using TrackPopupMenuEx. When user higjlites certain menu item I want to destroy this menu and create the new popup menu instaed of it.
0
 
LVL 8

Expert Comment

by:gelbert
ID: 1303945
Following code works fine in my test application:

CMenu* pMenu = new CMenu();

pMenu->CreatePopupMenu();

pMenu->ApendMenu( x1 );
pMenu->AppendMenu( x2 );

pMenu->TrackPopupMenu();

// if you remove these two lines then you will end up with x1, x2, x3, x4 // items in the menu
pMenu->DeleteMenu( x1 );
pMenu->DeleteMenu( x2 );

pMenu->ApendMenu( x3 );
pMenu->AppendMenu( x4 );

pMenu->TrackPopupMenu();

pMenu->DestroyMenu();

delete pMenu;

0
 
LVL 7

Author Comment

by:galkin
ID: 1303946
You delete menu ONLY when TrackPopupMenu returns it means when popup menu is destroyed but I need to destroy it from my application( when specified menu item is highlited) not by mouse clicking outside menu
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303947
Firstly - this seems to be a BAD UI design.  If you do some action on HILIGHTING a menu item, then that makes it very difficult for the user to select items below it.  It would be better to popup the other menu when you SELECT another item (in which case there is nothing special to do).  Another alternative is to use a cascading menu for that option.

Also I am not sure how you plan to detect a highlight on given item - perhaps through owner draw?  [How ARE you planning to detect a highlight?)

Anyway, if you DO want to do this. I'd suggest you send a mouse click message to the window when you get the highlight so that the menu THINKS you have dismissed it (or selected it), and then carry on from there by displaying another popup.

Note if you simulate the mouse event that selectes the item, the popup menu will send a WM_COMMAND - and this command could popup the subsequent menu.  If you choose to simulate a dismiss (by clicking somewhere else) then you can just follow the TrackPopupMenu call with another (as in gelbert's code)

However, I still feel this is a very strange UI design and would recommend you do something more standard and make sure you have considered the implications.

0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303948
Why the reject??????

A Reject without explanation is not likely to encourage further answers.

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303949
Are you using the word "higlight" to mean selecting an option from the menu, or simply higlighting it (moving mouse over it and the item is higlighted, but not yet selected)?

If it is the first meaning (actually select an item) then the answer is easy, because the popup disappears on its own and you can popup another in the command handler for that message.

If you mean highlight, then why not try:
* Cascading submenu.
* Alter existing menu by deleting old item and adding new ones so it is the same menu object but with different items in it.

Also, if you want to continue with the WM_CANCELMODE options, try sending that message and then posting yourself a message whose handler creates the other windows.  That way you might avoid creating the new popup before the old one is completely destroyed.

And again, I feel that this UI design is a bit odd - can you explain  why you have chosen this method - perhaps we can think of another way of doing it that actually works


0
 
LVL 7

Author Comment

by:galkin
ID: 1303950
Let me not to go deep in my apllication. I just want to underline what I need to implement. When a popup menu is displayed it captures all mouse events. I need when mouse pointer is over some hot area of menu's owner window this menu would "track" to this positions( this implementation is reqired by design of our product). I can determine where the mouse pointer by handling WM_ENTERIDLE message periodically sent by menu temporary window to its owner and calling GetCursorPos. The problem is how to destroy this popup menu?
        Thanks.
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303951
The is NOT what you said before.  You said that the mnue was to disappear when the user higlighted a menu option, not moved somewhere else.  AND you still have not said why you rejected my answers - I think an apology is in order here !!

I am TRYING to help you, but if you change the question on me all the time it is hard.

Anyway - here is code that does exactly what you have said you wanted (in this latest comment).  When a menu is popped up, it detects movement over a hot area of the view and changes the menu accordingly.

I hope THIS is what you want and is good enought for you to accept :-)

static int CurrentMenu = 0;

void CTestView::OnEnterIdle( UINT nWhy, CWnd* pWho ) {
      if (nWhy == MSGF_MENU) {
            TRACE("EnterIdle for menu\n");
            CPoint point; ::GetCursorPos(&point);
            ScreenToClient(&point);
            CRect rect; GetClientRect(rect);
            if (point.x < rect.left+1*rect.Width()/3) {
                  if (CurrentMenu != 1) {
                        SendMessage(WM_CANCELMODE);
                        PostMessage(WM_COMMAND,ID_SHOWMENU_1);
                  }
            }
            if (point.x > rect.left+2*rect.Width()/3) {
                  if (CurrentMenu != 2) {
                        SendMessage(WM_CANCELMODE);
                        PostMessage(WM_COMMAND,ID_SHOWMENU_2);
                  }
            }
      }
      
}
void CTestView::OnLButtonDown( UINT nFlags, CPoint point ) {
      TRACE("OnLButtonDown\n");
      SendMessage(WM_COMMAND,ID_SHOWMENU_1);
}

void CTestView::OnShowMenu1() {
      TRACE("OnShowMenu1\n");
      CurrentMenu = 1;
      CPoint point; ::GetCursorPos(&point);
      CMenu menu; menu.LoadMenu(IDR_MENU1);
      CMenu* pSubMenu = menu.GetSubMenu(0);
      pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
      CurrentMenu = 0;
}

void CTestView::OnShowMenu2() {
      TRACE("OnShowMenu2\n");
      CurrentMenu = 2;
      CPoint point; ::GetCursorPos(&point);
      CMenu menu; menu.LoadMenu(IDR_MENU2);
      CMenu* pSubMenu = menu.GetSubMenu(0);
      pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
      CurrentMenu = 0;
}

Roger

0
 
LVL 7

Author Comment

by:galkin
ID: 1303952
I repeat I don't want to explain to you all the points of my application design. It doesn't matter. I face to pure technical problem. I need to destroy popup menu programatically, it means not by mouse and create the new one.  
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303953
I HAVE TOLD YOU HOW TO DO IT AND YOU KEEP REJECTING ME!!!!

I have given you WORKING CODE doing EXACTLY what you said you wanted it to do. AND YOU STILL REJECTED!!

"I can determine where the mouse pointer by handling WM_ENTERIDLE message periodically sent by menu temporary window to its owner and calling GetCursorPos. The problem is how to destroy this popup menu? "

Here is my answer again.

Anyway - here is code that does exactly what you have said you wanted (in this latest comment). When a menu is popped up, it detects movement over a hot area of the view and changes the menu accordingly.

I hope THIS is what you want and is good enought for you to accept :-)

static int CurrentMenu = 0;

void CTestView::OnEnterIdle( UINT nWhy, CWnd* pWho ) {
if (nWhy == MSGF_MENU) {
TRACE("EnterIdle for menu\n");
CPoint point; ::GetCursorPos(&point);
ScreenToClient(&point);
CRect rect; GetClientRect(rect);
if (point.x < rect.left+1*rect.Width()/3) {
if (CurrentMenu != 1) {
SendMessage(WM_CANCELMODE);
PostMessage(WM_COMMAND,ID_SHOWMENU_1);
}
}
if (point.x > rect.left+2*rect.Width()/3) {
if (CurrentMenu != 2) {
SendMessage(WM_CANCELMODE);
PostMessage(WM_COMMAND,ID_SHOWMENU_2);
}
}
}

}
void CTestView::OnLButtonDown( UINT nFlags, CPoint point ) {
TRACE("OnLButtonDown\n");
SendMessage(WM_COMMAND,ID_SHOWMENU_1);
}

void CTestView::OnShowMenu1() {
TRACE("OnShowMenu1\n");
CurrentMenu = 1;
CPoint point; ::GetCursorPos(&point);
CMenu menu; menu.LoadMenu(IDR_MENU1);
CMenu* pSubMenu = menu.GetSubMenu(0);
pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
CurrentMenu = 0;
}

void CTestView::OnShowMenu2() {
TRACE("OnShowMenu2\n");
CurrentMenu = 2;
CPoint point; ::GetCursorPos(&point);
CMenu menu; menu.LoadMenu(IDR_MENU2);
CMenu* pSubMenu = menu.GetSubMenu(0);
pSubMenu->TrackPopupMenu (TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
CurrentMenu = 0;
}

Roger


0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303954
Please either accept this answer (which shows how to destroy the menu)  or give me a good explanation of WHY it is unaceptable.

I am here to hlpe you, but you need to co-operate here so that I can.  I have take time out of my work to get the above code working and to send it to you.

0
 
LVL 7

Author Comment

by:galkin
ID: 1303955
I tried it long ago but the second menu is not created and GetLastError returned error code "Popup menu already exists"
0
 
LVL 10

Expert Comment

by:RONSLOW
ID: 1303956
Did you do as I did (the above code works) and POST yourself a message after sending the WM_CANCELMODE so that any message that cancel mode generates to destroy the original popup menu have time to operate???

The code I wrote above uses WM_CANCELMODE and WORKS FINE!!.  As you said you were doing, I send the WM_CANCELMODE from within OnEnterIdle and then used PostMessage to POST myself a message about what I want to do next (create another popup).

Please try this method and see if it works for you.

If it does, let me post the answer again so you can reward me - I've worked hard for this question !!!!

Roger

0
 
LVL 7

Author Comment

by:galkin
ID: 1303957
Yes I followed your advise and and did everything as you wrote. Please send me your code and I will try to compile and build it. I expect there is some misunderstanding between us. Either I don't understand anything or you don't understund what I want to do. My E-mail address as follows: sasha@zsoft.com
0
 
LVL 10

Accepted Solution

by:
RONSLOW earned 100 total points
ID: 1303958
Please grade my answer again.

Thank you

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now