使用一个或多个分隔项创建ComboBox?

时间:2010-12-04 17:46:39

标签: delphi combobox delphi-7 separator

我正在使用Delphi7,我想要一个带分隔符项目的ComboBox(就像在弹出菜单中一样)。

我已经在Mozilla Sunbird(我知道,它不是Delphi ......)中看到了这个以下方式:

  1. 分隔项是一条简单的灰线 在项目的中心绘制

  2. 如果将鼠标悬停在分隔符上 鼠标,选择没有 出现

  3. 如果用户点击了分隔符, 它也没有被选中 combobox没特写。

  4. 没有。可以使用DrawItem实现1。我可以没有第二名,因为我不知道。

    对于3号,我正在寻求你的帮助。我发现在关闭CBN_CLOSEUP消息后直接发送到组合框。

    我想过挂钩窗口proc并且如果CBN_CLOSEUP被发送到某个组合框然后反击它。但我不确定这是否是最好的解决方案,或者还有其他更优雅的方式?

    无论解决方案是什么,我都希望有一个标准的ComboBox,它可以正确支持WinXP / Vista / 7主题。

    谢谢!


    编辑:对于工作组件,请参阅此主题:

    Can you help translating this very small C++ component to Delphi?

3 个答案:

答案 0 :(得分:1)

你想要的是一个拥有者绘制的组合框。请参阅:http://delphi.about.com/od/vclusing/a/drawincombobox.htm

此外,这似乎解决了使项目无法解决的问题: http://borland.newsgroups.archived.at/public.delphi.vcl.components.using.win32/200708/0708225320.html

据我所知,没有VCL方法可以做到这一点,所以你必须将组合框子类化。创建封装这些功能的组件会很好,这样您就可以轻松地重用它们。

上帝保佑

答案 1 :(得分:1)

我玩弄了无法点击的分隔符项目(如this answer中所述)并遇到了几个UI故障。问题是,组合框的行为有几个方面很难完全正确:

  • 按下向上和向下箭头键可在列表下拉时导航列表。
  • 按Enter键关闭下拉列表,选择当前项目。
  • 按Escape键关闭下拉列表,选择当前项目(如果使用向上和向下箭头键选择当前项目)或最后选择的项目。
  • 如果组合框具有焦点,则按向上和向下箭头键可更改当前选择而不显示列表。
  • 如果组合框具有焦点,则键入任何内容将选择与正在键入的内容匹配的组合框项目。
  • 如果组合框具有焦点,则按F4会下拉组合框列表,然后可以通过键盘或鼠标控制它。

确保已禁用的分隔符项不响应这些事件中的任何(加上我可能遗失的任何其他事件,例如屏幕阅读器?)似乎充满了错误。

相反,我正在使用的方法是将分隔符绘制为项目的一部分:

  1. 使用可变高度所有者绘制组合框。
  2. 为需要分隔符的任何项目添加3个像素高度。
  3. 在需要分隔符的每个项目的顶部绘制一条水平线。
  4. 这是完成此任务的一些C ++ Builder代码;把它翻译成Delphi应该很容易。

    void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control,
        int Index, TRect &Rect, TOwnerDrawState State)
    {
      bool draw_separator = NeedsSeparator(Index) && 
          !State.Contains(odComboBoxEdit);
    
      TCanvas *canvas = dynamic_cast<TCustomCombo*>(Control)->Canvas;
      canvas->FillRect(Rect);
    
      TRect text_rect = Rect;
      // Add space for separator if needed.
      if (draw_separator) {
        text_rect.Top += 3;
      }
    
      canvas->TextOut(text_rect.Left + 3,
          (text_rect.Top + text_rect.Bottom) / 2 - 
            canvas->TextHeight(ComboBox1->Items->Strings[Index]) / 2), 
          ComboBox1->Items->Strings[Index]);
    
      // Draw a separator line above the item if needed.
      if (draw_separator) {
        canvas->Pen->Color = canvas->Font->Color;
        canvas->MoveTo(Rect.Left, Rect.Top + 1);
        canvas->LineTo(Rect.Right, Rect.Top + 1);
      }
    }
    
    void __fastcall TForm1::ComboBox1MeasureItem(
        TWinControl * /* Control */, int Index, int &Height)
    {
      Height = ComboBox1->ItemHeight;
    
      // Add space for the separator if needed.
      if (Index != -1 && NeedsSeparator(Index)) {
        Height += 3;
      }
    }
    

答案 2 :(得分:0)

如果您希望控件看起来不错,请使用免费SpTBXLib。它支持组合样式组件,弹出带有行的弹出菜单。