C++ Builder 派生的 TComboBox 默认有 Items

C++ Builder derived TComboBox to have Items by default

这里是一个 VCL 组件新手,如果这是一个愚蠢的问题,请原谅我...

我正在尝试制作一个 TComboBox 组件,其中包含默认项目,当它被拖放到表单上时,即 TMonthComboBox 当被拖放到表单上时,它的 Items 列表中将包含月份列表。

我发现在构造期间尝试访问项目 属性 会导致“Control '' has no parent window”错误如果我尝试在表单上放置这样的组合框。

这里是(部分)构造函数:

__fastcall TMonthCombo::TMonthCombo(TComponent *Owner):TComboBox(Owner)
{
    this->Style = csDropDownList; // this is okay
    this->Items->Add("January"); // This is causing problem
}

我认为问题是由于项目 属性 在构建的这个阶段还不可用。

是否有任何方法可以确保组件已准备好在组件源代码本身内将值接受到其项目 属性 中(即在设计时不在属性编辑器中添加列表项目)?

在有人告诉我"Just add the items in your Application code at run time"之前,我必须解释一下,这个ComboBox在很多地方都会被频繁使用,月份选择只是我用来说明问题的一个简单例子,实际值我想在 ComboBox 中添加更多变化,并且大多数时候本质上是动态的。它还必须以多种方式响应用户选择。

我已经尝试了 运行-time 方式,但它变得非常乏味。这就是为什么我将它做成一个组件,这样它就可以自行处理,而不必重复输入多个版本的代码来填充组合框。

感谢您的帮助。

编辑:在尝试了 manlio 的解决方案后,ComboBox 在 运行-time 中看起来很奇怪:

ComboBox 在 运行 次有重影。我做错了什么?

__fastcall TYearCombo::TYearCombo(TComponent* Owner) : TComboBox(Owner), init_items(true)
{

}
//---------------------------------------------------------------------------
void __fastcall TYearCombo::CreateWnd()
{
    unsigned short yr, mn, dy;

    this->Width = 90;
    this->Style = csDropDownList;
    this->DropDownCount = 11;
    TDate d = Today();
    d.DecodeDate(&yr, &mn, &dy);
    year = yr;

    if (init_items)
    {
        init_items = false;
        TComboBox::CreateWnd();
        Items->BeginUpdate();
        for(int i=year-5; i<=year+5; i++)
        {
            Items->Add(IntToStr(i));
        }
        this->ItemIndex = 5;
        Items->EndUpdate();
    }
}
//---------------------------------------------------------------------------

你可以试试这个:

  1. 覆盖 CreateWnd 虚拟方法并添加一个 init_items 私有数据成员:

    class TMonthCombo : public TComboBox
    {
    // ...
    
    protected:
      virtual void __fastcall CreateWnd();
    
    private:
      bool init_items;
    
    // ...
    };
    
  2. 设置init_items标志:

    TMonthCombo::TMonthCombo(TComponent *Owner) : TComboBox(Owner),
                                                  init_items(true)
    {
      // ...
    }
    
  3. CreateWnd内您可以添加新项目:

    void __fastcall TMonthCombo::CreateWnd()
    {
      TComboBox::CreateWnd();
    
      if (init_items)
      {
        init_items = false;
        Items->BeginUpdate();
        Items->Add("January");
        // ...
        Items->EndUpdate();
      }
    }
    

进一步说明:

  • "Control has no parent" in Create ComboBoxTComboBox 需要一个已分配的 HWND 以便在其 Items 属性 中存储字符串)。
  • 简单地将构造函数的Owner参数转换为TWinControl并将结果赋值给组件的Parent属性isn'解决方案:

    TMonthCombo::TMonthCombo(TComponent *Owner) : TComBoBox(Owner)
    {
      Parent = static_cast<TWinControl *>(Owner);
      // ...
    }
    

    赋值解决了 "Control has no parent window error" 但产生了另一个问题:窗体始终是组件的父级(不能将窗体添加到不同的容器)。