Board index » cppbuilder » !! BCB5 Serious Menu Merge BUG!!

!! BCB5 Serious Menu Merge BUG!!

Inprise didn't fix a bug in BCB 4, they made it WORSE!!! Try the
following to reproduce this bug.

1) Create an application using File|New.
2) On the Projects Tab select MDI Application then select OK
3) Select a empty destination directory for this project then select OK
4) Double Click on the MainMenu1 object on the MainForm
5) Click on the Edit menu item and change its GroupIndex to 1
6) Click on the Window menu item and change its GroupIndex to 2
7) Now open the ChildWin Form and insert a TMainMenu Component
8) Add a menu item to the TMainMenu on the child
9) Name this item EditChild and make sure its GroupIndex is also 1
10) Run the application
11) Open two or more windows in the app by clicking on the new button
12) You should notice the Edit Menu is replaced with EditChild when the
first window is open (if not you did something wrong)
12) Maximize one of the NONAMEX windows
13) Now click on the Window menu and select one of the other NONAMEX
windows (not the one you are currently on)
14) The system menu for the child window should disappear along with the
Minimize, Restore, and Close buttons for the child window. If they
don't, it does not matter, they aren't functional anyway, try one of
them, or try a menu item and see what happens.
15) Try switching back to the previous window, these will sometimes
reappear, but are not functional!

At this point there is no way to restore the window back to it original
size. You will have to tile, arrange, or close them.

In BCB4 a similar problem will occur when you try this. Although nothing
will disappear, what occurs is that the close button will be grayed out,
it does, however, still work.  This is a little annoying to my users,
but it is not a show stopper.  The situation with BCB5 definitely is a
SHOW STOPPER. I can not release products to my customers with these
conditions, they will kill me.

I am not sure what is causing this bug. I know has to do with the
merging of menus. If you don't add menus to child windows this does not
happen. I also tried to make one main menu with all the menu items and
options and making items visible or invisible depending on the current
child. This however produced other problems just as severe..

I like a lot of the new features in BCB5, however I get a lot of weird
access violations with the VCL package and lockups I never got with
BCB4. I know what some people may say, these are isolated problem with
your install.  I tend to disagree.  I have been using Borland/Inprise
products for 12 years, and BCB5 has given me more trouble then all the
others I used combined.  If I can't find a resolution to this problem
quickly, I will have to revert back to BCB4 and loss some much needed
functionality.  I really don't want to have to tell y customers this
either!!

John McDermott

 

Re:!! BCB5 Serious Menu Merge BUG!!


In message <38F02BA8.BB13C...@agilent.com>, John McDermott stated:

Quote
> <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
> <html>
> Inprise didn't fix a bug in BCB 4, they made it WORSE!!! Try the following
> to reproduce this bug.

Please don't post in HTML. As well as going against newsgroup rules, it
inconveniences everyone whose news reader is not HTML capable. You will find
the rules at

http://www.borland.com/newsgroups/guide.html

Thanks for your cooperation.

===
Regards
Ralph (TeamB)
===

Re:!! BCB5 Serious Menu Merge BUG!!


Quote
John McDermott wrote:

>    Part 1.1    Type: Plain Text (text/plain)
>            Encoding: 7bit

I hope you've resubmitted this bug! Don't be -too- {*word*193} in the
comments section! I sympathize -- but none of my bugs have been
"show-stoppers" so far; except my own fat fingers, of course! (If
you've not been paying attention to the Community site, they just
asked a relevant question in "Pulse" that you might be interested in.
It will be interesting to see what they do with the information ...)

Cheers

Bob

PS Oh, BTW, they get really fried when you post in HTML. You might
avoid it in the future ...

Re:!! BCB5 Serious Menu Merge BUG!!


Hi John,
Quote
> Inprise didn't fix a bug in BCB 4, they made it WORSE!!! Try the
> following to reproduce this bug.

<snip menu merging bug>

This problem is indeed caused by the menu merging mechanism, and moreover a
problem with the TMenuItem::RebuildHandle() member function.  You'd be surprised
how many times the handle is rebuilt, specifically due to the frequent insertion
and removal of items.  Your best bet is to avoid the menu merging altogether,
rather add all the items to the MainMenu of the frame form (MainForm) and toggle
the visibllity and enabled state of these "child" items once the active form
changes.  Use the TScreen::OnActiveFormChange event to help you out here.  So,
at design-time, remove the MainMenu from the MDIChild form, if present, then
manually add these items to the main menu of the MainForm, setting the Tag
property of each "child" item to 1.  Next, set the GroupIndex property of these
"child" menu bar items to the same as those menu bar items of the MainForm that
you want replaced.  Finally, add the following...

// in header...
    void __fastcall ActiveFormChange(TObject* Sender);
    void __fastcall DoToggleChildItems(TMenuItem* AFrameItems,
        int AAffectTag);

// in source...
__fastcall TMainForm::TMainForm(TComponent *Owner)
    : TForm(Owner)
{
    Screen->OnActiveFormChange = ActiveFormChange;

Quote
}

void __fastcall TMainForm::DoToggleChildItems(TMenuItem* AFrameItems,
    int AAffectTag)
{
    SNDMSG(Handle, WM_SETREDRAW, false, 0);
    try
    {
        int count = AFrameItems->Count;
        for (int index = 0; index < count; ++index)
        {
            TMenuItem* Item = AFrameItems->Items[index];
            if (Item->Tag == AAffectTag)
            {
                for (int index2 = 0; index2 < count; ++index2)
                {
                    TMenuItem* Item2 = AFrameItems->Items[index2];
                    if (Item != Item2 && Item2->Tag != AAffectTag &&
                        Item->GroupIndex == Item2->GroupIndex)
                    {
                        Item->Visible = true;
                        Item->Enabled = true;

                        Item2->Visible = false;
                        Item2->Enabled = false;
                    }
                }
            }
        }
    }
    catch (...)
    {
        SNDMSG(Handle, WM_SETREDRAW, true, 0);
    }
    SNDMSG(Handle, WM_SETREDRAW, true, 0);
    RedrawWindow(Handle, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
    DrawMenuBar(Handle);

Quote
}

void __fastcall TMainForm::ActiveFormChange(TObject* Sender)
{
    if (!ComponentState.Contains(csDestroying))
    {
        if (ActiveMDIChild &&
            !ActiveMDIChild->ComponentState.Contains(csDestroying))
        {
            DoToggleChildItems(Menu->Items, 1);
        }
        else DoToggleChildItems(Menu->Items, 0);
    }

Quote
}

Good luck!

--
Damon Chandler (TeamB)
http://bcbcaq.freeservers.com

Re:!! BCB5 Serious Menu Merge BUG!!


Damon,

Thanks for the suggestion and the attached code.  I implemented your
solution in a test application since I wanted to make sure this would
work.  I got it to work fine in the test application.  I then spent
about 8 hours making the change to the real application.  Once complete,
there are no TMainMenu objects on any of the child windows, and the
MDIParent does all the responding to menu clicks and passes this to the
appropriate child.

I have three child windows who all have different menu choices. Two of
the three children interact fine and the problem I described does not
occur.  When the third child is introduced, with both or just one of the
other children, the problem reoccurs all over again.

I have looked at all possible reasons for this and have not come up with
a solution.  Is this a common problem reported or is this an isolated
case.  From your response it seems you have seen this problem before.
Any other suggestions?

Quote
"Damon Chandler (TeamB)" wrote:

> Hi John,
> > Inprise didn't fix a bug in BCB 4, they made it WORSE!!! Try the
> > following to reproduce this bug.
> <snip menu merging bug>

> This problem is indeed caused by the menu merging mechanism, and moreover a
> problem with the TMenuItem::RebuildHandle() member function.  You'd be surprised
> how many times the handle is rebuilt, specifically due to the frequent insertion
> and removal of items.  Your best bet is to avoid the menu merging altogether,
> rather add all the items to the MainMenu of the frame form (MainForm) and toggle
> the visibllity and enabled state of these "child" items once the active form
> changes.  Use the TScreen::OnActiveFormChange event to help you out here.  So,
> at design-time, remove the MainMenu from the MDIChild form, if present, then
> manually add these items to the main menu of the MainForm, setting the Tag
> property of each "child" item to 1.  Next, set the GroupIndex property of these
> "child" menu bar items to the same as those menu bar items of the MainForm that
> you want replaced.  Finally, add the following...

> // in header...
>     void __fastcall ActiveFormChange(TObject* Sender);
>     void __fastcall DoToggleChildItems(TMenuItem* AFrameItems,
>         int AAffectTag);

> // in source...
> __fastcall TMainForm::TMainForm(TComponent *Owner)
>     : TForm(Owner)
> {
>     Screen->OnActiveFormChange = ActiveFormChange;
> }

> void __fastcall TMainForm::DoToggleChildItems(TMenuItem* AFrameItems,
>     int AAffectTag)
> {
>     SNDMSG(Handle, WM_SETREDRAW, false, 0);
>     try
>     {
>         int count = AFrameItems->Count;
>         for (int index = 0; index < count; ++index)
>         {
>             TMenuItem* Item = AFrameItems->Items[index];
>             if (Item->Tag == AAffectTag)
>             {
>                 for (int index2 = 0; index2 < count; ++index2)
>                 {
>                     TMenuItem* Item2 = AFrameItems->Items[index2];
>                     if (Item != Item2 && Item2->Tag != AAffectTag &&
>                         Item->GroupIndex == Item2->GroupIndex)
>                     {
>                         Item->Visible = true;
>                         Item->Enabled = true;

>                         Item2->Visible = false;
>                         Item2->Enabled = false;
>                     }
>                 }
>             }
>         }
>     }
>     catch (...)
>     {
>         SNDMSG(Handle, WM_SETREDRAW, true, 0);
>     }
>     SNDMSG(Handle, WM_SETREDRAW, true, 0);
>     RedrawWindow(Handle, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
>     DrawMenuBar(Handle);
> }

> void __fastcall TMainForm::ActiveFormChange(TObject* Sender)
> {
>     if (!ComponentState.Contains(csDestroying))
>     {
>         if (ActiveMDIChild &&
>             !ActiveMDIChild->ComponentState.Contains(csDestroying))
>         {
>             DoToggleChildItems(Menu->Items, 1);
>         }
>         else DoToggleChildItems(Menu->Items, 0);
>     }
> }

> Good luck!

> --
> Damon Chandler (TeamB)
> http://bcbcaq.freeservers.com

Re:!! BCB5 Serious Menu Merge BUG!!


Well I have learned some rather important leasons with the new BCB5.  As
stated in my last reply, the problem is still reoccuring. I now have
some additional info though.

There are two situations your fix will work, and another that will not.
The code works fine when:

1) There is only one type of MDI child window used. In this case hiding
or showing a top level menu does generate the problem. (I am not sure
why)

2) There is more than one type of MDI child used, and you do NOT hide or
show top level menu items.

The problem occurs any time you use multiple types of child windows and
hide or show different top level menu items.   This will always cause
the TMainMenu to Rebuild the Menu, which is the root of the problem.
Anytime RebuildMenu is called, the entire menu is destroyed and
rebuilt.  If the child happens to be maximized when this happens, the
child system menu will be destroyed along with the system buttons on the
header.

I am working on fix, but I feel this will require using windows
functions to add and remove the top level items without a complete
rebuild.  I would rather not have to do this, but unless the issue is
resolved in the VCL, then I can only try this non-standard solution or
return to BCB4.  Niether is really too attractive at this point.

John McDermott

Quote
"Damon Chandler (TeamB)" wrote:

> Hi John,
> > Inprise didn't fix a bug in BCB 4, they made it WORSE!!! Try the
> > following to reproduce this bug.
> <snip menu merging bug>

> This problem is indeed caused by the menu merging mechanism, and moreover a
> problem with the TMenuItem::RebuildHandle() member function.  You'd be surprised
> how many times the handle is rebuilt, specifically due to the frequent insertion
> and removal of items.  Your best bet is to avoid the menu merging altogether,
> rather add all the items to the MainMenu of the frame form (MainForm) and toggle
> the visibllity and enabled state of these "child" items once the active form
> changes.  Use the TScreen::OnActiveFormChange event to help you out here.  So,
> at design-time, remove the MainMenu from the MDIChild form, if present, then
> manually add these items to the main menu of the MainForm, setting the Tag
> property of each "child" item to 1.  Next, set the GroupIndex property of these
> "child" menu bar items to the same as those menu bar items of the MainForm that
> you want replaced.  Finally, add the following...

> // in header...
>     void __fastcall ActiveFormChange(TObject* Sender);
>     void __fastcall DoToggleChildItems(TMenuItem* AFrameItems,
>         int AAffectTag);

> // in source...
> __fastcall TMainForm::TMainForm(TComponent *Owner)
>     : TForm(Owner)
> {
>     Screen->OnActiveFormChange = ActiveFormChange;
> }

> void __fastcall TMainForm::DoToggleChildItems(TMenuItem* AFrameItems,
>     int AAffectTag)
> {
>     SNDMSG(Handle, WM_SETREDRAW, false, 0);
>     try
>     {
>         int count = AFrameItems->Count;
>         for (int index = 0; index < count; ++index)
>         {
>             TMenuItem* Item = AFrameItems->Items[index];
>             if (Item->Tag == AAffectTag)
>             {
>                 for (int index2 = 0; index2 < count; ++index2)
>                 {
>                     TMenuItem* Item2 = AFrameItems->Items[index2];
>                     if (Item != Item2 && Item2->Tag != AAffectTag &&
>                         Item->GroupIndex == Item2->GroupIndex)
>                     {
>                         Item->Visible = true;
>                         Item->Enabled = true;

>                         Item2->Visible = false;
>                         Item2->Enabled = false;
>                     }
>                 }
>             }
>         }
>     }
>     catch (...)
>     {
>         SNDMSG(Handle, WM_SETREDRAW, true, 0);
>     }
>     SNDMSG(Handle, WM_SETREDRAW, true, 0);
>     RedrawWindow(Handle, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
>     DrawMenuBar(Handle);
> }

> void __fastcall TMainForm::ActiveFormChange(TObject* Sender)
> {
>     if (!ComponentState.Contains(csDestroying))
>     {
>         if (ActiveMDIChild &&
>             !ActiveMDIChild->ComponentState.Contains(csDestroying))
>         {
>             DoToggleChildItems(Menu->Items, 1);
>         }
>         else DoToggleChildItems(Menu->Items, 0);
>     }
> }

> Good luck!

> --
> Damon Chandler (TeamB)
> http://bcbcaq.freeservers.com

Other Threads