📄 jvxchecklistbox.pas
字号:
{if (FTabChar > #0) then
for I := 1 to Length(S) do
if S[I] = FTabChar then S[I] := #9;}
ATabWidth := Round((TabWidth * FCanvas.TextWidth('0')) * 0.25);
Result :=
LoWord(GetTabbedTextExtent(FCanvas.Handle, @S[1], Length(S), 1, ATabWidth));
end
else
Result := FCanvas.TextWidth(S);
end;
end;
procedure TJvxCustomListBox.ResetHorizontalExtent;
var
I: Integer;
begin
FMaxItemWidth := 0;
for I := 0 to Items.Count - 1 do
FMaxItemWidth := Max(FMaxItemWidth, GetItemWidth(I));
SetHorizontalExtent;
end;
procedure TJvxCustomListBox.ResetContent;
begin
SendMessage(Handle, LB_RESETCONTENT, 0, 0);
end;
procedure TJvxCustomListBox.Clear;
begin
FItems.Clear;
end;
procedure TJvxCustomListBox.SetColumnWidth;
begin
if FColumns > 0 then
SendMessage(Handle, LB_SETCOLUMNWIDTH, (Width + FColumns - 3) div FColumns, 0);
end;
procedure TJvxCustomListBox.SetColumns(Value: Integer);
begin
if FColumns <> Value then
if (FColumns = 0) or (Value = 0) then
begin
FColumns := Value;
RecreateWnd;
end
else
begin
FColumns := Value;
if HandleAllocated then
SetColumnWidth;
end;
end;
function TJvxCustomListBox.GetItemIndex: Integer;
begin
Result := SendMessage(Handle, LB_GETCURSEL, 0, 0);
end;
function TJvxCustomListBox.GetSelCount: Integer;
begin
Result := SendMessage(Handle, LB_GETSELCOUNT, 0, 0);
end;
procedure TJvxCustomListBox.SetItemIndex(Value: Integer);
begin
if GetItemIndex <> Value then
SendMessage(Handle, LB_SETCURSEL, Value, 0);
end;
procedure TJvxCustomListBox.SetExtendedSelect(Value: Boolean);
begin
if Value <> FExtendedSelect then
begin
FExtendedSelect := Value;
RecreateWnd;
end;
end;
procedure TJvxCustomListBox.SetIntegralHeight(Value: Boolean);
begin
if Value <> FIntegralHeight then
begin
FIntegralHeight := Value;
RecreateWnd;
end;
end;
function TJvxCustomListBox.GetAutoScroll: Boolean;
begin
Result := FAutoScroll and (Columns = 0);
end;
procedure TJvxCustomListBox.SetOnDrawItem(Value: TDrawItemEvent);
begin
if Assigned(FOnDrawItem) <> Assigned(Value) then
begin
FOnDrawItem := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then
if AutoScroll then
ResetHorizontalExtent
else
SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end
else
FOnDrawItem := Value;
end;
procedure TJvxCustomListBox.SetOnGetItemWidth(Value: TGetItemWidthEvent);
begin
if Assigned(FOnGetItemWidth) <> Assigned(Value) then
begin
FOnGetItemWidth := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then
if AutoScroll then
ResetHorizontalExtent
else
SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end
else
FOnGetItemWidth := Value;
end;
procedure TJvxCustomListBox.SetAutoScroll(Value: Boolean);
begin
if AutoScroll <> Value then
begin
FAutoScroll := Value;
Perform(WM_HSCROLL, SB_TOP, 0);
if HandleAllocated then
if AutoScroll then
ResetHorizontalExtent
else
SendMessage(Handle, LB_SETHORIZONTALEXTENT, 0, 0);
end;
end;
function TJvxCustomListBox.GetItemHeight: Integer;
var
R: TRect;
begin
Result := FItemHeight;
if HandleAllocated and (FStyle = lbStandard) then
begin
Perform(LB_GETITEMRECT, 0, Longint(@R));
Result := R.Bottom - R.Top;
end;
end;
procedure TJvxCustomListBox.SetItemHeight(Value: Integer);
begin
if (FItemHeight <> Value) and (Value > 0) then
begin
FItemHeight := Value;
RecreateWnd;
end;
end;
procedure TJvxCustomListBox.SetTabWidth(Value: Integer);
begin
if Value < 0 then
Value := 0;
if FTabWidth <> Value then
begin
FTabWidth := Value;
RecreateWnd;
end;
end;
procedure TJvxCustomListBox.SetMultiSelect(Value: Boolean);
begin
if FMultiSelect <> Value then
begin
FMultiSelect := Value;
RecreateWnd;
end;
end;
function TJvxCustomListBox.GetSelected(Index: Integer): Boolean;
var
R: Longint;
begin
R := SendMessage(Handle, LB_GETSEL, Index, 0);
if R = LB_ERR then
ListIndexError(Index);
Result := LongBool(R);
end;
procedure TJvxCustomListBox.SetSelected(Index: Integer; Value: Boolean);
begin
if MultiSelect then
begin
if SendMessage(Handle, LB_SETSEL, Ord(Value), Index) = LB_ERR then
ListIndexError(Index);
end
else
begin
if Value then
SetItemIndex(Index)
else
if ItemIndex = Index then
SetItemIndex(-1);
end;
end;
procedure TJvxCustomListBox.SetSorted(Value: Boolean);
begin
if FSorted <> Value then
begin
FSorted := Value;
RecreateWnd;
end;
end;
procedure TJvxCustomListBox.SetStyle(Value: TListBoxStyle);
begin
if FStyle <> Value then
begin
FStyle := Value;
RecreateWnd;
end;
end;
function TJvxCustomListBox.GetTopIndex: Integer;
begin
Result := SendMessage(Handle, LB_GETTOPINDEX, 0, 0);
end;
procedure TJvxCustomListBox.SetBorderStyle(Value: TBorderStyle);
begin
if FBorderStyle <> Value then
begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
procedure TJvxCustomListBox.SetTopIndex(Value: Integer);
begin
if GetTopIndex <> Value then
SendMessage(Handle, LB_SETTOPINDEX, Value, 0);
end;
procedure TJvxCustomListBox.SetGraySelection(Value: Boolean);
begin
if FGraySelection <> Value then
begin
FGraySelection := Value;
if not Focused then
Invalidate;
end;
end;
function TJvxCustomListBox.GetItems: TStrings;
begin
Result := FItems;
end;
procedure TJvxCustomListBox.SetItems(Value: TStrings);
begin
Items.Assign(Value);
end;
function TJvxCustomListBox.ItemAtPos(Pos: TPoint; Existing: Boolean): Integer;
var
Count: Integer;
ItemRect: TRect;
begin
if PtInRect(ClientRect, Pos) then
begin
Result := TopIndex;
Count := Items.Count;
while Result < Count do
begin
Perform(LB_GETITEMRECT, Result, Longint(@ItemRect));
if PtInRect(ItemRect, Pos) then
Exit;
Inc(Result);
end;
if not Existing then
Exit;
end;
Result := -1;
end;
function TJvxCustomListBox.ItemRect(Index: Integer): TRect;
var
Count: Integer;
begin
Count := Items.Count;
if (Index = 0) or (Index < Count) then
Perform(LB_GETITEMRECT, Index, Longint(@Result))
else
if Index = Count then
begin
Perform(LB_GETITEMRECT, Index - 1, Longint(@Result));
OffsetRect(Result, 0, Result.Bottom - Result.Top);
end
else
FillChar(Result, SizeOf(Result), 0);
end;
procedure TJvxCustomListBox.CreateParams(var Params: TCreateParams);
type
PSelects = ^TSelects;
TSelects = array [Boolean] of Longword;
const
BorderStyles: array [TBorderStyle] of Longword = (0, WS_BORDER);
Styles: array [TListBoxStyle] of Longword =
(0, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE
{$IFDEF COMPILER6_UP}, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWFIXED {$ENDIF});
Sorteds: TSelects = (0, LBS_SORT);
MultiSelects: TSelects = (0, LBS_MULTIPLESEL);
ExtendSelects: TSelects = (0, LBS_EXTENDEDSEL);
IntegralHeights: TSelects = (LBS_NOINTEGRALHEIGHT, 0);
MultiColumns: TSelects = (0, LBS_MULTICOLUMN);
TabStops: TSelects = (0, LBS_USETABSTOPS);
var
Selects: PSelects;
begin
inherited CreateParams(Params);
CreateSubClass(Params, 'LISTBOX');
with Params do
begin
Selects := @MultiSelects;
if FExtendedSelect then
Selects := @ExtendSelects;
Style := Style or (WS_HSCROLL or WS_VSCROLL or LBS_HASSTRINGS or LBS_NOTIFY) or
Styles[FStyle] or Sorteds[FSorted] or Selects^[FMultiSelect] or
IntegralHeights[FIntegralHeight] or MultiColumns[FColumns <> 0] or
BorderStyles[FBorderStyle] or TabStops[FTabWidth <> 0];
if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then
begin
Style := Style and not WS_BORDER;
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
end;
WindowClass.Style := WindowClass.Style and not (CS_HREDRAW or CS_VREDRAW);
end;
end;
procedure TJvxCustomListBox.CreateWnd;
var
W, H: Integer;
begin
W := Width;
H := Height;
inherited CreateWnd;
SetWindowPos(Handle, 0, Left, Top, W, H, SWP_NOZORDER or SWP_NOACTIVATE);
if FTabWidth <> 0 then
SendMessage(Handle, LB_SETTABSTOPS, 1, LPARAM(@FTabWidth));
SetColumnWidth;
if FSaveItems <> nil then
begin
FItems.Assign(FSaveItems);
SetTopIndex(FSaveTopIndex);
SetItemIndex(FSaveItemIndex);
FSaveItems.Free;
FSaveItems := nil;
end;
end;
procedure TJvxCustomListBox.DestroyWnd;
begin
if FItems.Count > 0 then
begin
FSaveItems := TStringList.Create;
FSaveItems.Assign(FItems);
FSaveTopIndex := GetTopIndex;
FSaveItemIndex := GetItemIndex;
end;
inherited DestroyWnd;
end;
procedure TJvxCustomListBox.WndProc(var Msg: TMessage);
begin
if AutoScroll then
begin
case Msg.Msg of
LB_ADDSTRING, LB_INSERTSTRING:
begin
inherited WndProc(Msg);
FMaxItemWidth := Max(FMaxItemWidth, GetItemWidth(Msg.Result));
SetHorizontalExtent;
Exit;
end;
LB_DELETESTRING:
begin
if GetItemWidth(Msg.WParam) >= FMaxItemWidth then
begin
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Msg);
ResetHorizontalExtent;
end
else
inherited WndProc(Msg);
Exit;
end;
LB_RESETCONTENT:
begin
FMaxItemWidth := 0;
SetHorizontalExtent;
Perform(WM_HSCROLL, SB_TOP, 0);
inherited WndProc(Msg);
Exit;
end;
WM_SETFONT:
begin
inherited WndProc(Msg);
if not (csDestroying in ComponentState) then
begin
FCanvas.Font.Assign(Self.Font);
ResetHorizontalExtent;
end;
Exit;
end;
end;
end;
{for auto drag mode, let listbox handle itself, instead of TControl}
if not (csDesigning in ComponentState) and ((Msg.Msg = WM_LBUTTONDOWN) or
(Msg.Msg = WM_LBUTTONDBLCLK)) and not Dragging then
begin
if DragMode = dmAutomatic then
begin
if IsControlMouseMsg(TWMMouse(Msg)) then
Exit;
ControlState := ControlState + [csLButtonDown];
Dispatch(Msg); {overrides TControl's BeginDrag}
Exit;
end;
end;
inherited WndProc(Msg);
end;
procedure TJvxCustomListBox.WMLButtonDown(var Msg: TWMLButtonDown);
var
ItemNo: Integer;
ShiftState: TShiftState;
begin
ShiftState := KeysToShiftState(Msg.Keys);
if (DragMode = dmAutomatic) and FMultiSelect then
begin
if not (ssShift in ShiftState) or (ssCtrl in ShiftState) then
begin
ItemNo := ItemAtPos(SmallPointToPoint(Msg.Pos), True);
if (ItemNo >= 0) and Selected[ItemNo] then
begin
BeginDrag(False);
Exit;
end;
end;
end;
inherited;
if (DragMode = dmAutomatic) and not (FMultiSelect and
((ssCtrl in ShiftState) or (ssShift in ShiftState))) then
BeginDrag(False);
end;
procedure TJvxCustomListBox.WMNCHitTest(var Msg: TWMNCHitTest);
begin
if csDesigning in ComponentState then
DefaultHandler(Msg)
else
inherited;
end;
procedure TJvxCustomListBox.CNCommand(var Msg: TWMCommand);
begin
case Msg.NotifyCode of
LBN_SELCHANGE:
begin
inherited Changed;
Click;
end;
LBN_DBLCLK:
DblClick;
end;
end;
procedure TJvxCustomListBox.WMPaint(var Msg: TWMPaint);
procedure PaintListBox;
var
DrawItemMsg: TWMDrawItem;
MeasureItemMsg: TWMMeasureItem;
DrawItemStruct: TDrawItemStruct;
MeasureItemStruct: TMeasureItemStruct;
R: TRect;
Y, I, H, W: Integer;
begin
{ Initialize drawing records }
DrawItemMsg.Msg := CN_DRAWITEM;
DrawItemMsg.DrawItemStruct := @DrawItemStruct;
DrawItemMsg.Ctl := Handle;
DrawItemStruct.CtlType := ODT_LISTBOX;
DrawItemStruct.itemAction := ODA_DRAWENTIRE;
DrawItemStruct.itemState := 0;
DrawItemStruct.HDC := Msg.DC;
DrawItemStruct.CtlID := Handle;
DrawItemStruct.hwndItem := Handle;
{ Intialize measure records }
MeasureItemMsg.Msg := CN_MEASUREITEM;
MeasureItemMsg.IDCtl := Handle;
MeasureItemMsg.MeasureItemStruct := @MeasureItemStruct;
MeasureItemStruct.CtlType := ODT_LISTBOX;
MeasureItemStruct.CtlID := Handle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -