unit ExCheckCombo; {$mode objfpc}{$H+} interface uses LCLIntf, LCLType, Classes, SysUtils, Controls, StdCtrls, GroupedEdit, EditBtn, CheckLst, Forms; type { TCheckComboBoxEx } TCheckItemChange = procedure(Sender: TObject; AIndex: Integer) of object; TCheckComboBoxHintMode = (cbhmDefault, cbhmItems); TCheckComboBoxExStrings = class(TStringList) private function GetChecked(AIndex: Integer): Boolean; function GetEnabled(AIndex: Integer): Boolean; function GetObj(AIndex: Integer): TObject; function GetState(AIndex: Integer): TCheckboxState; procedure SetChecked(AIndex: Integer; AValue: Boolean); procedure SetEnabled(AIndex: Integer; AValue: Boolean); procedure SetObj(AIndex: Integer; AValue: TObject); procedure SetState(AIndex: Integer; AValue: TCheckboxState); protected procedure InsertItem(AIndex: Integer; const AText: string); override; procedure InsertItem(AIndex: Integer; const AText: string; Obj: TObject); override; public destructor Destroy; override; procedure Assign(ASource: TPersistent); override; procedure Clear; override; procedure Delete(AIndex: Integer); override; property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked; property Enabled[AIndex: Integer]: boolean read GetEnabled write SetEnabled; property Objects[AIndex: Integer]: TObject read GetObj write SetObj; property State[AIndex: Integer]: TCheckboxState read GetState write SetState; end; TCheckComboBoxEx = class(TCustomEditButton) private FAllowGrayed: Boolean; FAutoDropDown: Boolean; FButtonWidth: Integer; FCheckListBox: TCheckListBox; FDelimiter: Char; FDropDownCount: Integer; FDroppedDown: Boolean; FEscCancels: Boolean; FItemIndex: Integer; FItems: TCheckComboBoxExStrings; FItemWidth: Integer; FHintMode: TCheckComboBoxHintMode; FSavedChecks: array of Integer; FSorted: Boolean; FOnChange: TNotifyEvent; FOnCloseUp: TNotifyEvent; FOnDropDown: TNotifyEvent; FOnItemChange: TCheckItemChange; FOnItemClick: TCheckListClicked; procedure CheckComboBoxFormCloseHandler(Sender: TObject; var CloseAction: TCloseAction); function GetButtonWidth: Integer; function GetChecked(AIndex: Integer): Boolean; function GetItemEnabled(AIndex: Integer): Boolean; function GetItems: TStrings; function GetState(AIndex: Integer): TCheckBoxState; procedure ItemClickHandler(Sender: TObject; AIndex: Integer); procedure ItemsToCheckListbox(ACheckListbox: TCheckListbox); procedure SetAllowGrayed(AValue: Boolean); procedure SetButtonWidth(AValue: Integer); procedure SetChecked(AIndex: Integer; const AValue: Boolean); procedure SetDelimiter(AValue: Char); procedure SetDropDownCount(AValue: Integer); procedure SetItemEnabled(AIndex: Integer; const AValue: Boolean); procedure SetItemIndex(AValue: Integer); procedure SetItems(const AValue: TStrings); procedure SetItemWidth(AValue: Integer); procedure SetSorted(AValue: Boolean); procedure SetState(AIndex: Integer; const AValue: TCheckboxState); protected procedure ButtonClick; override; procedure CloseUp; procedure CreateHandle; override; procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); override; procedure DoEnter; override; procedure DoChange; virtual; procedure DoItemChange(AIndex: Integer); virtual; procedure DoCloseUp; virtual; procedure DoDropDown; virtual; procedure DoItemClick(AIndex: Integer); virtual; procedure DoOnShowHint(HintInfo: PHintInfo); override; procedure EditKeyDown(var Key: Word; Shift: TShiftState); override; function GetBuddyClassType: TControlClass; override; function GetEditorClassType: TGEEditClass; override; procedure RestoreInitialChecks; procedure SaveInitialChecks; procedure SetBiDiMode(AValue: TBiDiMode); override; procedure ShowPopup; procedure UpdateCaption; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function AddItem(AText: String; AChecked: Boolean = false; AEnabled: Boolean = true): Integer; procedure CheckAll(AState: TCheckBoxState; AAllowGrayed: Boolean = true; AAllowDisabled: Boolean = true); procedure Clear; procedure Toggle(AIndex: Integer); // public properties property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked; property DroppedDown: Boolean read FDroppedDown; property ItemEnabled[AIndex: Integer]: Boolean read GetItemEnabled write SetItemEnabled; property Text; published property AllowGrayed: Boolean read FAllowGrayed write SetAllowGrayed default false; property AutoDropDown: Boolean read FAutoDropDown write FAutoDropDown default false; property ButtonWidth: Integer read FButtonWidth write SetButtonWidth default -1; property Delimiter: char read FDelimiter write SetDelimiter default ';'; property DropDownCount: Integer read FDropDownCount write SetDropDownCount default 8; property EscCancels: Boolean read FEscCancels write FEscCancels default true; property HintMode: TCheckComboBoxHintMode read FHintMode write FHintMode default cbhmDefault; property ItemIndex: Integer read FItemIndex write SetItemIndex default -1; property Items: TStrings read GetItems write SetItems; property ItemWidth: Integer read FItemWidth write FItemWidth default 0; property Sorted: Boolean read FSorted write SetSorted default false; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnCloseUp: TNotifyEvent read FOnCloseUp write FOnCloseUp; property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown; property OnItemChange: TCheckItemChange read FOnItemChange write FOnItemChange; property OnItemClick: TCheckListClicked read FOnItemClick write FOnItemClick; // inherited properties property Align; property Anchors; property AutoSize; property BiDiMode; property BorderSpacing; property Color; property Constraints; property DragCursor; property DragKind; property DragMode; property Enabled; property Font; property Hint; property ParentBidiMode; property ParentColor; property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property Spacing default 0; property TabOrder; property TabStop; property TextHint; property Visible; // inherited events property OnChangeBounds; property OnClick; property OnContextPopup; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseEnter; property OnMouseLeave; property OnMouseMove; property OnMouseUp; property OnStartDrag; end; implementation uses Buttons, Themes, WSForms; { TCCBItem } // CCB = CheckComboBox type TCCBItem = class Caption: String; State: TCheckboxState; Enabled: Boolean; Obj: TObject; constructor Create; end; constructor TCCBItem.Create; begin State := cbUnchecked; Enabled := true; end; { TCheckComboBoxExStrings } destructor TCheckComboBoxExStrings.Destroy; begin Clear; inherited; end; procedure TCheckComboBoxExStrings.Assign(ASource: TPersistent); var i: Integer; begin inherited Assign(ASource); if (ASource is TCheckComboBoxExStrings) then for i := 0 to Count-1 do begin State[i] := TCheckComboBoxExStrings(ASource).State[i]; Enabled[i] := TCheckComboBoxExStrings(ASource).Enabled[i]; end; end; procedure TCheckComboBoxExStrings.Clear; var i: Integer; begin for i := 0 to Count-1 do TCCBItem(inherited Objects[i]).Free; inherited; end; procedure TCheckComboBoxExStrings.Delete(AIndex: Integer); begin TCCBItem(inherited Objects[AIndex]).Free; inherited; end; function TCheckComboBoxExStrings.GetChecked(AIndex: Integer): Boolean; begin Result := GetState(AIndex) = cbChecked; end; function TCheckComboBoxExStrings.GetEnabled(AIndex: Integer): Boolean; begin Result := TCCBItem(inherited Objects[AIndex]).Enabled; end; function TCheckComboBoxExStrings.GetObj(AIndex: Integer): TObject; begin Result := TCCBItem(inherited Objects[AIndex]).Obj; end; function TCheckComboBoxExStrings.GetState(AIndex: Integer): TCheckboxState; begin Result := TCCBItem(inherited Objects[AIndex]).State; end; procedure TCheckComboBoxExStrings.InsertItem(AIndex: Integer; const AText: String); begin inherited InsertItem(AIndex, AText, TCCBItem.Create); end; procedure TCheckComboBoxExStrings.InsertItem(AIndex: Integer; const AText: String; Obj: TObject); begin InsertItem(AIndex, AText); TCCBItem(inherited Objects[AIndex]).Obj := Obj; end; procedure TCheckComboBoxExStrings.SetChecked(AIndex: Integer; AValue: Boolean); begin if AValue then SetState(AIndex, cbChecked) else SetState(AIndex, cbUnchecked); end; procedure TCheckComboBoxExStrings.SetEnabled(AIndex: Integer; AValue: Boolean); var item: TCCBItem; begin item := TCCBItem(inherited Objects[AIndex]); if item.Enabled = AValue then exit; item.Enabled := AValue; end; procedure TCheckComboBoxExStrings.SetObj(AIndex: Integer; AValue: TObject); begin TCCBItem(inherited Objects[AIndex]).Obj := AValue; end; procedure TCheckComboBoxExStrings.SetState(AIndex: Integer; AValue: TCheckBoxState); var item: TCCBItem; begin item := TCCBItem(inherited Objects[AIndex]); if item.State = AValue then exit; item.State := AValue; end; { TCCBEdit } type TCCBEdit = class(TEbEdit) protected procedure DoOnShowHint(HintInfo: PHintInfo); override; end; procedure TCCBEdit.DoOnShowHint(HintInfo: PHintInfo); begin (Parent as TCheckComboBoxEx).DoOnShowHint(HintInfo); end; { TCCBButton } type TCCBButton = class(TSpeedButton) protected procedure DoOnShowHint(HintInfo: PHintInfo); override; procedure Paint; override; end; procedure TCCBButton.DoOnShowHint(HintInfo: PHintInfo); begin (Parent as TCheckComboBoxEx).DoOnShowHint(HintInfo); end; procedure TCCBButton.Paint; const DETAILS: array[TButtonState] of TThemedComboBox = ( tcDropDownButtonNormal, // bsUp = button is up tcDropDownButtonDisabled, // bsDisabled = button is disabled tcDropDownButtonPressed, // bsPressed = button is down tcDropDownButtonPressed, // (not used) tcDropDownButtonHot // bsHot = mouse is under mouse ); var detail: TThemedElementDetails; begin inherited Paint; detail := ThemeServices.GetElementDetails(DETAILS[FState]); ThemeServices.DrawElement(Canvas.Handle, detail, ClientRect); end; { TCheckComboBoxForm } type TCheckComboBoxForm = class(TForm) private FCaller: TControl; FCheckListBox: TCheckListBox; FDropDownCount: Integer; protected procedure ActivateDoubleBuffered; procedure DblClickHandler(Sender: TObject); procedure Deactivate; override; procedure KeepInView(APopupOrigin: TPoint); procedure KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState); procedure MeasureHeight(out AHeight: Integer); public constructor CreateNew(AOwner: TComponent; Num: Integer = 0); override; procedure Initialize(ADropdownCount: Integer; APosition: TPoint; AWidth: Integer); end; constructor TCheckComboBoxForm.CreateNew(AOwner: TComponent; Num: Integer = 0); begin inherited CreateNew(AOwner, Num); BorderStyle := bsNone; FCheckListbox := TCheckListbox.Create(self); FCheckListbox.Align := alClient; FCheckListbox.Parent := self; FCheckListbox.OnDblClick := @DblClickHandler; FCheckListbox.OnKeyDown := @KeyDownHandler; FDropDownCount := 8; end; procedure TCheckComboBoxForm.ActivateDoubleBuffered; begin DoubleBuffered := TWSCustomFormClass(WidgetSetClass).GetDefaultDoubleBuffered; end; procedure TCheckComboBoxForm.Deactivate; begin Close; end; procedure TCheckComboboxForm.DblClickHandler(Sender: TObject); begin {$IFDEF LCLCocoa} Free; {$ELSE} Close; {$ENDIF} end; procedure TCheckComboBoxForm.Initialize(ADropDownCount: Integer; APosition: TPoint; AWidth: Integer); var h: Integer; begin FDropDownCount := ADropDownCount; MeasureHeight(h); SetBounds(APosition.X, APosition.Y, AWidth, h); KeepInView(APosition); AutoScroll := FCheckListBox.Items.Count > FDropDownCount; end; procedure TCheckComboBoxForm.KeepInView(APopupOrigin: TPoint); var R: TRect; begin R := Screen.MonitorFromPoint(APopupOrigin).WorkAreaRect; // take care of taskbar if APopupOrigin.X + Width > R.Right then Left := R.Right - Width else if APopupOrigin.X < R.Left then Left := R.Left else Left := APopupOrigin.X; if APopupOrigin.Y + Height > R.Bottom then begin if Assigned(FCaller) then Top := APopupOrigin.Y - FCaller.Height - Height else Top := R.Bottom - Height; end else if APopupOrigin.Y < R.Top then Top := R.Top else Top := APopupOrigin.Y; if Left < R.Left then Left := 0; if Top < R.Top then Top := 0; end; procedure TCheckComboBoxForm.KeyDownHandler(Sender: TObject; var Key: Word; Shift: TShiftState); begin inherited; if (Key = VK_ESCAPE) and TCheckComboBoxEx(FCaller).EscCancels then TCheckComboBoxEx(FCaller).RestoreInitialChecks; if (Key = VK_ESCAPE) or (Key = VK_TAB) or (Key = VK_RETURN) or (((Key = VK_UP) or (Key = VK_DOWN)) and (Shift = [ssAlt])) then Close; end; procedure TCheckComboBoxForm.MeasureHeight(out AHeight: Integer); var i: Integer; h: Integer = 0; begin AHeight := 0; for i := 0 to FCheckListbox.Items.Count-1 do if i < FDropDownCount then begin FCheckListbox.MeasureItem(i, h); inc(AHeight,h); end; inc(AHeight, 6); end; { TCheckComboBoxEx } constructor TCheckComboBoxEx.Create(AOwner: TComponent); begin inherited Create(AOwner); Spacing := 0; Button.Flat := true; FButtonWidth := -1; FDelimiter := ';'; FDropDownCount := 8; FItems := TCheckComboBoxExStrings.Create; FEscCancels := true; end; destructor TCheckComboBoxEx.Destroy; begin FItems.Free; inherited Destroy; end; function TCheckComboBoxEx.AddItem(AText: String; AChecked: Boolean = false; AEnabled: Boolean = true): Integer; var j: Integer; begin j := FItems.Add(AText); if AChecked then FItems.State[j] := cbChecked else FItems.State[j] := cbUnchecked; FItems.Enabled[j] := AEnabled; if FDroppedDown then with FCheckListBox do begin Result := Items.Add(AText); Checked[Result] := AChecked; ItemEnabled[Result] := AEnabled; end; UpdateCaption; end; procedure TCheckComboBoxEx.ButtonClick; begin ShowPopup; end; procedure TCheckComboBoxEx.CheckAll(AState: TCheckBoxState; AAllowGrayed: Boolean = true; AAllowDisabled: Boolean = true); var i: Integer; begin for i := 0 to FItems.Count-1 do begin if not FItems.Enabled[i] and not AAllowDisabled then Continue; if AState in [cbChecked, cbUnchecked] then FItems.State[i] := AState else if (AState = cbGrayed) then begin if AAllowGrayed then FItems.State[i] := cbGrayed else FItems.State[i] := cbUnChecked; end; end; if FDroppedDown then with FCheckListBox do CheckAll(AState, AAllowGrayed, AAllowDisabled); UpdateCaption; DoChange; end; procedure TCheckComboBoxEx.CheckComboBoxFormCloseHandler(Sender: TObject; var CloseAction: TCloseAction); begin CloseUp; FCheckListBox := nil; CloseAction := caFree; end; procedure TCheckComboBoxEx.Clear; begin FItems.Clear; if FDroppedDown then FCheckListBox.Clear; UpdateCaption; DoChange; end; procedure TCheckComboBoxEx.CloseUp; begin FDroppedDown := false; UpdateCaption; DoCloseUp; end; { procedure TCheckComboBoxEx.CloseUpHandler(Sender: TObject); begin CloseUp; end; } procedure TCheckComboBoxEx.CreateHandle; begin inherited; if FButtonWidth < 0 then Buddy.Width := GetSystemMetrics(SM_CXVSCROLL); end; procedure TCheckComboBoxEx.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: Double); begin inherited; if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then begin if FButtonWidth < 0 then Buddy.Width := GetSystemMetrics(SM_CXVSCROLL) else begin FButtonWidth := round(AXProportion * FButtonWidth); Buddy.Width := FButtonWidth; end; end; end; procedure TCheckComboBoxEx.DoChange; begin if Assigned(FOnChange) then FOnChange(self); end; procedure TCheckComboBoxEx.DoCloseUp; begin if Assigned(FOnCloseUp) then FOnCloseUp(self); end; procedure TCheckComboBoxEx.DoDropDown; begin if Assigned(FOnDropDown) then FOnDropDown(self); end; procedure TCheckComboBoxEx.DoEnter; begin inherited; if FAutoDropDown then ShowPopup; end; procedure TCheckComboBoxEx.DoItemChange(AIndex: Integer); begin if Assigned(FOnItemChange) then FOnItemChange(self, AIndex); end; procedure TCheckComboBoxEx.DoItemClick(AIndex: Integer); begin if Assigned(FOnItemClick) then FOnItemClick(self, AIndex); end; procedure TCheckComboBoxEx.DoOnShowHint(HintInfo: PHintInfo); begin if FHintMode = cbhmItems then HintInfo^.HintStr := StringReplace(Text, FDelimiter+' ', LineEnding, [rfReplaceAll]); inherited; end; procedure TCheckComboBoxEx.EditKeyDown(var Key: Word; Shift: TShiftState); begin if (Key = VK_TAB) then begin inherited; exit; end; if (Key = VK_RETURN) or (Key = VK_SPACE) or (((Key = VK_DOWN) or (Key = VK_UP)) and (Shift = [ssAlt])) then ShowPopup; // Kill all other keys Key := 0; end; function TCheckComboBoxEx.GetBuddyClassType: TControlClass; begin Result := TCCBButton; end; function TCheckComboBoxEx.GetButtonWidth: Integer; begin Result := Buddy.Width; end; function TCheckComboBoxEx.GetChecked(AIndex: Integer): Boolean; begin Result := FItems.Checked[AIndex]; end; function TCheckComboBoxEx.GetEditorClassType: TGEEditClass; begin Result := TCCBEdit; end; function TCheckComboBoxEx.GetItemEnabled(AIndex: Integer): Boolean; begin Result := FItems.Enabled[AIndex]; end; function TCheckComboBoxEx.GetItems: TStrings; begin Result := FItems; end; function TCheckComboBoxEx.GetState(AIndex: Integer): TCheckboxState; begin Result := FItems.State[AIndex]; end; procedure TCheckComboBoxEx.ItemClickHandler(Sender: TObject; AIndex: Integer); begin UpdateCaption; DoChange; DoItemChange(AIndex); DoItemClick(AIndex); end; procedure TCheckComboBoxEx.ItemsToCheckListbox(ACheckListbox: TCheckListbox); var i: Integer; begin ACheckListbox.Items.BeginUpdate; try ACheckListbox.Items.Clear; for i := 0 to FItems.Count-1 do begin ACheckListbox.Items.Add(FItems[i]); ACheckListbox.State[i] := FItems.State[i]; ACheckListbox.ItemEnabled[i] := FItems.Enabled[i]; end; if (FItemIndex > -1) and (FItemIndex < ACheckListbox.Count) then ACheckListbox.ItemIndex := FItemIndex; finally ACheckListbox.Items.EndUpdate; end; end; procedure TCheckComboBoxEx.RestoreInitialChecks; var i: Integer; begin for i := 0 to FItems.Count-1 do FItems.Checked[i] := false; for i := 0 to High(FSavedChecks) do FItems.Checked[FSavedChecks[i]] := true; end; procedure TCheckComboBoxEx.SaveInitialChecks; var i, n: Integer; begin SetLength(FSavedChecks, FItems.Count); n := 0; for i := 0 to FItems.Count-1 do if FItems.Checked[i] then begin FSavedChecks[n] := i; inc(n); end; SetLength(FSavedChecks, n); end; procedure TCheckComboBoxEx.SetAllowGrayed(AValue: Boolean); begin if FAllowGrayed = AValue then exit; FAllowGrayed := AValue; if FDroppedDown then FCheckListBox.AllowGrayed := AValue; end; procedure TCheckComboBoxEx.SetBiDiMode(AValue: TBiDiMode); begin if AValue = BiDiMode then exit; inherited SetBiDiMode(AValue); if FDroppedDown then FCheckListBox.BiDiMode := AValue; if IsRightToLeft then Buddy.Align := alLeft else Buddy.Align := alRight; UpdateCaption; end; procedure TCheckComboBoxEx.SetButtonWidth(AValue: Integer); begin if FButtonWidth = AValue then exit; FButtonWidth := AValue; if FButtonWidth < 0 then Buddy.Width := GetSystemMetrics(SM_CXVSCROLL) else Buddy.Width := FButtonWidth; end; procedure TCheckComboBoxEx.SetChecked(AIndex: Integer; const AValue: Boolean); begin if FItems.Checked[AIndex] = AValue then exit; if AValue then FItems.State[AIndex] := cbChecked else FItems.State[AIndex] := cbUnchecked; if FDroppedDown then FCheckListBox.Checked[AIndex] := AValue; UpdateCaption; DoChange; DoItemChange(AIndex); end; procedure TCheckComboBoxEx.SetDelimiter(AValue: Char); begin if FDelimiter = AValue then exit; FDelimiter := AValue; UpdateCaption; end; procedure TCheckComboBoxEx.SetDropDownCount(AValue: Integer); begin if (FDropDownCount = AValue) or (AValue <= 0) then exit; FDropDownCount := AValue; end; procedure TCheckComboBoxEx.SetItemEnabled(AIndex: Integer; const AValue: Boolean); begin if FItems.Enabled[AIndex] = AValue then exit; FItems.Enabled[AIndex] := AValue; if FDroppedDown then FCheckListbox.ItemEnabled[AIndex] := AValue; end; procedure TCheckComboBoxEx.SetItemIndex(AValue: Integer); begin if FItemIndex = AValue then exit; FItemIndex := AValue; if FDroppedDown then FCheckListBox.ItemIndex := AValue; end; procedure TCheckComboBoxEx.SetItems(const AValue: TStrings); begin FItems.Assign(AValue); if FDroppedDown then FCheckListBox.Items.Assign(AValue); end; procedure TCheckComboBoxEx.SetItemWidth(AValue: Integer); begin if FItemWidth = AValue then exit; if AValue < 0 then FItemWidth := 0 else FItemWidth := AValue; end; procedure TCheckComboBoxEx.SetSorted(AValue: Boolean); begin if AValue = FSorted then exit; FSorted := AValue; if FSorted then FItems.Sort; UpdateCaption; end; procedure TCheckComboBoxEx.SetState(AIndex: Integer; const AValue: TCheckBoxState); begin if FItems.State[AIndex] = AValue then exit; FItems.State[AIndex] := AValue; if FDroppedDown then FCheckListbox.State[AIndex] := AValue; DoChange; DoItemChange(AIndex); end; procedure TCheckComboBoxEx.ShowPopup; var PopupOrigin: TPoint; PopupWidth: Integer; F: TCheckComboBoxForm; begin if FItems.Count = 0 then exit; F := TCheckComboBoxForm.CreateNew(Application); F.FCaller := Self; F.BiDiMode := BiDiMode; if DoubleBuffered then F.ActivateDoubleBuffered; F.FCheckListBox.AllowGrayed := FAllowGrayed; PopupOrigin := ControlToScreen(Point(0, Height)); if FItemWidth > 0 then PopupWidth := FItemWidth else PopupWidth := Self.Width; ItemsToCheckListbox(F.FCheckListbox); F.Initialize(FDropDownCount, PopupOrigin, PopupWidth); SaveInitialChecks; F.FCheckListbox.OnItemClick := @ItemClickHandler; F.OnClose := @CheckComboBoxFormCloseHandler; F.Show; FDroppedDown := true; FCheckListbox := F.FCheckListbox; DoDropDown; end; procedure TCheckComboBoxEx.Toggle(AIndex: Integer); begin SetChecked(AIndex, not GetChecked(AIndex)); end; procedure TCheckComboBoxEx.UpdateCaption; var i: Integer; s: String; begin if FDroppedDown then for i := 0 to FCheckListBox.Items.Count - 1 do FItems.State[i] := FCheckListbox.State[i]; s := ''; if IsRightToLeft then begin for i := FItems.Count-1 downto 0 do if FItems.Checked[i] then s := s + FItems[i] + FDelimiter + ' ' end else begin for i := 0 to FItems.Count-1 do if FItems.Checked[i] then s := s + FItems[i] + FDelimiter + ' '; end; if s <> '' then SetLength(s, Length(s)-2); Text := s; end; end.