Delphi:有可能有一个带有禁用项目的组合框吗?

时间:2011-04-07 15:45:21

标签: delphi combobox

如何让TComboBox包含一些禁用的项目?我需要用户查看这些项目,但无法选择它们。

谢谢!

3 个答案:

答案 0 :(得分:16)

是的,这是怎么做的:

在表单上放置TComboBox,并将Style设置为csOwnerDrawFixed。然后添加事件处理程序

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
const
  INDENT = 3;
begin
  with TComboBox(Control) do
  begin
    FillRect(Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
    inc(Rect.Left, INDENT);
    if boolean(Items.Objects[Index]) then
      SetTextColor(Canvas.Handle, clBlack)
    else
      SetTextColor(Canvas.Handle, clGray);
    DrawText(Canvas.Handle,
      PChar(Items[Index]),
      length(Items[Index]),
      Rect,
      DT_SINGLELINE or DT_LEFT or DT_VCENTER or DT_END_ELLIPSIS)
  end;
end;

procedure TForm1.ComboBox1CloseUp(Sender: TObject);
begin
  with TComboBox(Sender) do
    if (ItemIndex <> -1) and not boolean(Items.Objects[ItemIndex]) then
    begin
      beep;
      Perform(CB_SHOWDROPDOWN, integer(true), 0);
    end;
end;

此外,在表单的接口部分,在声明表单类之前,添加

TComboBox = class(StdCtrls.TComboBox)
protected
  procedure WndProc(var Message: TMessage); override;
end;

并将WndProc实现为

procedure TComboBox.WndProc(var Message: TMessage);

  function NextItemIsDisabled: boolean;
  begin
    result := (ItemIndex < Items.Count - 1) and
      not boolean(Items.Objects[ItemIndex + 1]);
  end;

  procedure SelectNextEnabledItem;
  var
    i: Integer;
  begin
    for i := ItemIndex + 1 to Items.Count - 1 do
      if boolean(Items.Objects[i]) then
      begin
        ItemIndex := i;
        Exit;
      end;
    beep;
  end;

  procedure KillMessages;
  var
    msg: TMsg;
  begin
    while PeekMessage(msg,
      Handle,
      WM_KEYFIRST,
      WM_KEYLAST,
      PM_REMOVE) do;
  end;

  function PrevItemIsDisabled: boolean;
  begin
    result := (ItemIndex > 0) and
      not boolean(Items.Objects[ItemIndex - 1]);
  end;

  procedure SelectPrevEnabledItem;
  var
    i: Integer;
  begin
    for i := ItemIndex - 1 downto 0 do
      if boolean(Items.Objects[i]) then
      begin
        ItemIndex := i;
        Exit;
      end;
    beep;
  end;

begin
  case Message.Msg of
    WM_KEYDOWN:
      case Message.WParam of
        VK_DOWN:
          if NextItemIsDisabled then
          begin
            SelectNextEnabledItem;
            KillMessages;
            Exit;
          end;
        VK_UP:
          if PrevItemIsDisabled then
          begin
            SelectPrevEnabledItem;
            KillMessages;
            Exit;
          end;
      end;
  end;
  inherited;
end;

要测试组合框,请编写,例如

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComboBox1.Items.AddObject('Alpha', TObject(true));
  ComboBox1.Items.AddObject('Beta', TObject(true));
  ComboBox1.Items.AddObject('Gamma', TObject(false));
  ComboBox1.Items.AddObject('Delta', TObject(true));
end;

我认为你在这里得到了truefalse的含义 - 它只是意味着enabled

答案 1 :(得分:6)

这并不容易(这是一个坏主意,因为这不是组合框在Windows上的行为方式)。

你必须自己画出组合框。使用Items.Objects数组来存储项目是否已启用或禁用,并在绘制每个项目之前检查该数组,以便正确设置颜色。

您还需要处理OnChangeOnClick个事件,并添加一种方法来跟踪上次选择的ItemIndex。在OnChange/OnClick中,您断开事件处理程序,检查Objects[ItemIndex]值以查看是否允许选择,如果未将ItemIndex设置回上次选择的ItemIndex,然后重新启用事件处理程序。

答案 2 :(得分:-2)

只需在KeyPress过程

上添加以下代码即可
procedure Tform1.Combobox1editKeyPress(Sender: TObject; var Key: Char);
begin
   Key:=#0;
end;