3

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

我在Mozilla Sunbird(我知道,它不是Delphi ...)中看到了这个精美的实现,方法如下:

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

  2. 如果将鼠标悬停在分隔符上,则不会出现选择

  3. 如果用户单击分隔符,则它也不会被选中并且组合框不会关闭。

No. 1 可以使用 DrawItem 来实现。没有二号我也能活下去,因为我对此一无所知。

对于 3 号,我正在寻求您的帮助。我发现关闭后立即将 CBN_CLOSEUP 消息发送到组合框。

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

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

谢谢!


编辑:对于工作组件,请参阅此线程:

你能帮忙把这个非常小的 C++ 组件翻译成 Delphi 吗?

4

3 回答 3

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 方法可以做到这一点,因此您必须对组合框进行子类化。最好创建封装这些功能的组件,以便您可以轻松地重用它们。

上帝保佑

于 2010-12-04T20:31:06.710 回答
1

我尝试制作不可点击的分隔项(如本答案中所述)并遇到了几个 UI 故障。问题是组合框的行为有几个方面很难完全正确:

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

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

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

  1. 使用可变高度所有者绘制组合框。
  2. 为需要分隔符的任何项目的高度添加 3 个像素。
  3. 在需要分隔符的每个项目的顶部画一条水平线。

这里有一些 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;
  }
}
于 2011-02-03T16:44:32.567 回答
0

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

于 2010-12-04T17:54:45.867 回答