Как я могу использовать TComboBox с некоторыми элементами, которые отключены? Мне нужно, чтобы пользователь видел эти элементы, но не мог их выбрать.
Спасибо!
Как я могу использовать TComboBox с некоторыми элементами, которые отключены? Мне нужно, чтобы пользователь видел эти элементы, но не мог их выбрать.
Спасибо!
Да, и вот как это сделать:
Отбросьте 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;
Я думаю, что вы понимаете значение true
и false
здесь - это просто означает enabled
.
Это не просто (и это плохая идея, так как это не то, как comboboxes ведут себя в Windows).
Вам придется собственнику самостоятельно вычеркнуть combobox. Используйте массив Items.Objects для хранения того, включен или отключен элемент или нет, и проверьте этот массив перед тем, как рисовать каждый элемент, чтобы правильно установить цвета.
Вам также необходимо обработать события OnChange
и OnClick
и добавить способ отслеживания последнего выбранного ItemIndex
. В OnChange/OnClick
вы отключите обработчик событий, проверьте значение Objects[ItemIndex]
, чтобы увидеть, разрешен ли выбор, если не установить ItemIndex
назад к последнему выбранному ItemIndex
, а затем снова включить обработчик событий.
просто добавьте следующий код в процедуру KeyPress
procedure Tform1.Combobox1editKeyPress(Sender: TObject; var Key: Char);
begin
Key:=#0;
end;