【问题标题】:Passing a TForm as an argument to a function将 TForm 作为参数传递给函数
【发布时间】:2020-10-12 15:48:27
【问题描述】:

我有一个包含多个表单的应用程序。其中两个非常相似,它们具有共同的 VCL 对象(标签、图像等)形式的特征,我将它们命名为相同的。 我想在一个特定的类中有一个函数,它可以接受这两个 Form 之一作为参数,以便修改它们共同的参数。我提出的解决方案似乎不起作用。

由于我的应用程序非常庞大且复杂,因此我使用一个小示例复制了该问题。 首先,下面是我的 MainForm 示例:

还有一个subForm的例子(它们的排列方式都差不多)

我有一个附加类,用于填写子表单上的编辑。该类的代码如下:

#pragma hdrstop

#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

Master::Master(void)
{

}

Master::~Master(void)
{

 }

 void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);

TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);

if (self != NULL && self2 == NULL) {
    TForm3* curForm = static_cast<TForm3*>(Form);
}

else if (self == NULL && self2 != NULL) {
    TForm2* curForm = static_cast<TForm2*>(Form);
}

curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}

而在 MainForm 中,“Fill Form2”按钮的代码如下:

Master1 -> WriteToForm(Form2);

其中 Master1 只是 Master 类的一个对象。 这对 Form2 非常有效:

但是对于使用 Master1 -&gt; WriteToForm(Form3) 填充的 Form3,这是我得到的,与我的实际应用程序中的 pb 相同:

所以应该去编辑,是放错地方了。我认为主要的 pb 来自于我没有按相同的顺序创建每个标签、编辑等。我这样做是为了模仿我的真实应用程序。为了验证这一点,我创建了第 3 个子表单,这一次 VCL 对象的创建顺序与我的第一个子表单相同,这很有效:

所以我怀疑这来自最初的演员表

TForm2* curForm = static_cast<TForm2*>(Form);

当我将 Form3 作为参数传递时,Form3 在某种程度上被转换为 Form2 的“形状”,它的定义顺序不同。也许这可以通过直接修改 DFM 文件来纠正,但这对于我的主应用程序来说不是一个现实的方法。

我会执行此初始转换,否则我会收到一个编译错误,指出第一行不知道 curForm

curForm -> Edit1 -> Text = "blablabla_1";

那么,有没有更好的方法将 Form 作为参数传递给 WriteToForm 函数?

【问题讨论】:

    标签: c++ c++builder vcl


    【解决方案1】:

    仅仅因为两种类型相似并不意味着它们是相关。您的代码不起作用,因为您的两个 Form 类没有以任何方式相互关联。你不能随意地将一个投射到另一个。

    要解决这个问题,您有多种选择:

    1. 分别为两个 Form 类编写代码,例如:
    void Master::WriteToForm(TForm* Form)
    {
        TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
        TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
    
        if (curForm2)
        {
            curForm2->Edit1->Text = _D("blablabla_1");
            curForm2->Edit2->Text = _D("blablabla_2");
        }
        else if (curForm3)
        {
            curForm3->Edit1->Text = _D("blablabla_1");
            curForm3->Edit2->Text = _D("blablabla_2");
        }
    }
    

    或者:

    void WriteToForm(TForm2* Form);
    void WriteToForm(TForm3* Form);
    
    ...
    
    void Master::WriteToForm(TForm2* Form)
    {
        Form->Edit1->Text = _D("blablabla_1");
        Form->Edit2->Text = _D("blablabla_2");
    }
    
    void Master::WriteToForm(TForm3* Form)
    {
        Form->Edit1->Text = _D("blablabla_1");
        Form->Edit2->Text = _D("blablabla_2");
    }
    
    1. 让您的函数使用模板(但请注意:Why can templates only be implemented in the header file?):
    template<typename T>
    void WriteToForm(T* Form);
    
    ...
    
    void Master::WriteToForm<T>(T* Form)
    {
        Form->Edit1->Text = _D("blablabla_1");
        Form->Edit2->Text = _D("blablabla_2");
    }
    
    1. 使两个 Form 类派生自一个公共基类或接口,例如:
    class TBaseForm : public TForm
    {
    public:
        inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
        virtual void SetEdit1(const String &Text) = 0;
        virtual void SetEdit2(const String &Text) = 0;
    };
    
    ...
    
    class TForm2 : public TBaseForm
    {
        ...
    public:
        __fastcall TForm2(TComponent *Owner);
        ...
        void SetEdit1(const String &NewText);
        void SetEdit2(const String &NewText);
    };
    
    __fastcall TForm2::TForm2(TComponent *Owner)
        : TBaseForm(Owner)
    {
        ...
    }
    
    void TForm2::SetEdit1(const String &NewText)
    {
        Edit1->Text = NewText;
    }
    
    void TForm2::SetEdit2(const String &NewText)
    {
        Edit2->Text = NewText;
    }
    
    ...
    
    repeat for TForm3...
    
    ...
    
    void Master::WriteToForm(TBaseForm* Form)
    {
        Form->SetEdit1(_D("blablabla_1"));
        Form->SetEdit2(_D("blablabla_2"));
    }
    

    或者:

    __interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
    IMyIntf : public IInterface
    {
    public:
        virtual void SetEdit1(const String &Text) = 0;
        virtual void SetEdit2(const String &Text) = 0;
    };
    
    ...
    
    class TForm2 : public TForm, public IMyIntf
    {
        ...
    public:
        __fastcall TForm2(TComponent *Owner);
        ...
        void SetEdit1(const String &NewText);
        void SetEdit2(const String &NewText);
    };
    
    __fastcall TForm2::TForm2(TComponent *Owner)
        : TForm(Owner)
    {
        ...
    }
    
    void TForm2::SetEdit1(const String &NewText)
    {
        Edit1->Text = NewText;
    }
    
    void TForm2::SetEdit2(const String &NewText)
    {
        Edit2->Text = NewText;
    }
    
    ...
    
    repeat for TForm3...
    
    ...
    
    void Master::WriteToForm(IMyIntf* Intf)
    {
        Intf->SetEdit1(_D("blablabla_1"));
        Intf->SetEdit2(_D("blablabla_2"));
    }
    
    1. 使用 RTTI 访问字段,例如:
    #include <System.Rtti.hpp>
    
    void Master::WriteToForm(TForm* Form)
    {
        TRttiContext Ctx;
        TRttiType *FormType = Ctx.GetType(Form->ClassType());
    
        TRttiField *Field = FormType->GetField(_D("Edit1"));
        if (Field)
        {
            TValue value = Field->GetValue(Form);
            if( (!value.Empty) && (value.IsObject()) )
            {
                TObject *Obj = value.AsObject();
    
                // Either: 
    
                static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
    
                // Or:
    
                TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
                if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
            }
        }
    
        Field = FormType->GetField(_D("Edit2"));
        if (Field)
        {
            TValue value = Field->GetValue(Form);
            if( (!value.Empty) && (value.IsObject()) )
            {
                TObject *Obj = value.AsObject();
    
                // Either: 
    
                static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
    
                // Or:
    
                TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
                if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
            }
        }
    }
    

    【讨论】:

    • #3 是我的最爱。
    • 谢谢雷米。 #2 对内存来说是最简单的,但我无法让它工作。因此,无论如何,由于我已经对实现继承犹豫不决,所以我采用了这个解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多