【问题标题】:Trying to copy a TMenu to another TMenu试图将一个 TMenu 复制到另一个 TMenu
【发布时间】:2022-01-04 22:21:16
【问题描述】:

一些简单的测试代码试图从一个TMainMenu 复制到另一个。我正在制作上下文相关的主菜单。

如果你想重新创建,我已经包含了cpphdfm

此代码有 3 个TMainMenus 设置和 2 个按钮。一个按钮从TMainMenu2 复制到TMainMenu1,另一个按钮从TMainMenu3 复制到TMainMenu1。我发现菜单正在被复制,但看起来就像 MainForm 上的子菜单。

主文件

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}

TMenuItem *CloneMenuItem(TMenuItem *Src)
{
    if (Src) {
        TMenuItem *mi = new TMenuItem(Src->Owner);
        mi->Caption = Src->Caption;
        mi->OnClick = Src->OnClick;
        mi->Tag = Src->Tag;
        mi->Checked = Src->Checked;
        mi->RadioItem = Src->RadioItem;
        for(int i = 0; i < Src->Count; i++) {
            TMenuItem *c = CloneMenuItem(Src->Items[i]);
            if (c)
                mi->Add(c);
        }
        return mi;
    }
    return 0;
}

void CopyMenu(TMenu *Dst, TMenu *Src)
{
    Dst->Items->Clear();
    for(int i = 0; i < Src->Items->Count; i++) {
        TMenuItem *mi = CloneMenuItem(&Src->Items[i]);
        Dst->Items->Add(mi);
    }
}

void CopyMenu(TMainMenu *Dst, TMenu *Src)
{
#ifdef debug
    // just to try and see wtf is going on. Gives exception?!?
    String s1,s2,s3,s4;

    for(int i = 0; i < Dst->Items->Count; i++) {
        s4 = s3; s3 = s2; s2 = s1;
        s1 = Dst->Items[i].Caption;
    }
#else
    Dst->Items->Clear();
#endif
    for(int i = 0; i < Src->Items->Count; i++) {
        TMenuItem *mi = CloneMenuItem(&Src->Items[i]);
        Dst->Items->Add(mi);
//      Dst->Items->Add(mi);
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    CopyMenu(MainMenu1, MainMenu2);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button2Click(TObject *Sender)
{
    CopyMenu(MainMenu1, MainMenu3);
}
//---------------------------------------------------------------------------

头文件

//---------------------------------------------------------------------------

#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Menus.hpp>
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published:    // IDE-managed Components
    TMainMenu *MainMenu1;
    TMainMenu *MainMenu2;
    TMenuItem *MainMenu11;
    TMenuItem *MainMenu1Sub11;
    TMenuItem *MainMenu1Sub21;
    TMainMenu *MainMenu3;
    TMenuItem *MainMenu21;
    TMenuItem *MainMenu2Sub11;
    TMenuItem *MainMenu2Sub21;
    TMenuItem *MainMenu31;
    TMenuItem *MainMenu3Sub11;
    TButton *Button1;
    TButton *Button2;
    void __fastcall Button1Click(TObject *Sender);
    void __fastcall Button2Click(TObject *Sender);
private:    // User declarations
public:     // User declarations
    __fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif

DFM 文件

object Form2: TForm2
  Left = 0
  Top = 0
  Caption = 'Form2'
  ClientHeight = 345
  ClientWidth = 499
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -24
  Font.Name = 'Segoe UI'
  Font.Style = []
  Menu = MainMenu1
  PixelsPerInch = 192
  TextHeight = 32
  object Button1: TButton
    Left = 24
    Top = 160
    Width = 417
    Height = 50
    Margins.Left = 6
    Margins.Top = 6
    Margins.Right = 6
    Margins.Bottom = 6
    Caption = 'Set MainMenu to MainMenu2'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 24
    Top = 232
    Width = 417
    Height = 50
    Margins.Left = 6
    Margins.Top = 6
    Margins.Right = 6
    Margins.Bottom = 6
    Caption = 'Set MainMenu to MainMenu3'
    TabOrder = 1
    OnClick = Button2Click
  end
  object MainMenu1: TMainMenu
    Left = 48
    Top = 24
    object MainMenu11: TMenuItem
      Caption = 'MainMenu1'
      object MainMenu1Sub11: TMenuItem
        Caption = 'MainMenu1->Sub1'
      end
      object MainMenu1Sub21: TMenuItem
        Caption = 'MainMenu1->Sub2'
      end
    end
  end
  object MainMenu2: TMainMenu
    Left = 200
    Top = 24
    object MainMenu21: TMenuItem
      Caption = 'MainMenu2'
      object MainMenu2Sub11: TMenuItem
        Caption = 'MainMenu2->Sub1'
      end
      object MainMenu2Sub21: TMenuItem
        Caption = 'MainMenu2->Sub2'
      end
    end
  end
  object MainMenu3: TMainMenu
    Left = 360
    Top = 32
    object MainMenu31: TMenuItem
      Caption = 'MainMenu3'
      object MainMenu3Sub11: TMenuItem
        Caption = 'MainMenu3->Sub1'
      end
    end
  end
end

【问题讨论】:

  • TMenuItem *mi = new TMenuItem(Src-&gt;Owner); 看起来很可疑。新菜单项不应该归新菜单所有吗?
  • 在两个CopyMenu() 重载中,CloneMenuItem(&amp;Src-&gt;Items[i]) 都是错误的。 SrcTMenuTMenu::Items 不是数组(即不可索引),因此当 i &gt; 0 时,由于您访问无效内存而发生坏事。您将TMenu::ItemsTMenuItem::Items[] 混淆了,后者是一个数组(好吧,无论如何都是可索引的)。您需要改用CloneMenuItem(Src-&gt;Items-&gt;Items[i])Dst-&gt;Items[i] 也有同样的问题。
  • 谢谢雷米,就是这样。你是互联网上最有用的人!

标签: c++ c++builder vcl


【解决方案1】:

将这段代码放在一起,似乎对我有用,只需做一些额外的工作,您就可以将特定项目从一个主菜单复制到另一个主菜单。

我已让 Button5 单击事件显示 MDI 表单上的任何主菜单以查看结果,但尚未测试单击事件但知道它确实有效,就像我在其他应用程序中所做的那样。

void __fastcall TForm6::Button4Click(TObject *Sender)
{
CopyToMenu(MainMenu1, MainMenu3);
}
//---------------------------------------------------------------------------
void CopyToMenu(TMainMenu *ItemSource, TMainMenu *ItemDestination)
{

ItemDestination->Items->Clear();

for(int i = 0; i < ItemSource->Items->Count; i++)
    {
    for(int j = 0; j < ItemSource->Items->Items[i]->Count; j++)
        {
        TMenuItem *item = new TMenuItem(ItemDestination);
        item->Caption = ItemSource->Items->Items[i]->Items[j]->Caption;
        item->OnClick = ItemSource->Items->Items[i]->Items[j]->OnClick;
        item->Checked = ItemSource->Items->Items[i]->Items[j]->Checked;
        ItemDestination->Items->Items[i]->Add(item);
        }
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm6::Button5Click(TObject *Sender)
{
// Menu is the Form menu property
if(Menu == MainMenu1 || Menu == MainMenu2)
   Menu = MainMenu3;
else
   Menu = MainMenu1;
}
//---------------------------------------------------------------------------

【讨论】:

    【解决方案2】:

    根据 Remy Lebeau 的回答,这对我有用。

    TMenuItem *CloneMenuItem(TMenuItem *Src)
    {
        if (Src) {
        TMenuItem *mi = new TMenuItem(Src->Owner);
        mi->Caption = Src->Caption;
        mi->OnClick = Src->OnClick;
        mi->Tag = Src->Tag;
        mi->Checked = Src->Checked;
        mi->RadioItem = Src->RadioItem;
        for(int i=0;i<Src->Count;i++) {
            TMenuItem *c = CloneMenuItem(Src->Items[i]);
            if (c)
                mi->Add(c);
        }
        return mi;
        }
        return 0;
    }
    
    void CopyMenu(TMenu *Dst,const TMenu *Src)
    {
        Dst->Items->Clear();
        for(int i=0;i<Src->Items->Count;i++)
            Dst->Items->Add(CloneMenuItem(Src->Items->Items[i]));
    }
    void CopyMenu(TMainMenu *Dst,const TMenu *Src)
    {
        Dst->Items->Clear();
        for(int i=0;i<Src->Items->Count;i++)
            Dst->Items->Add(CloneMenuItem(Src->Items->Items[i]));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多