我一直在玩 TListBox 控件,绘制图像和更改字体样式等。我想稍微提高一点,并尝试通过缩进和多级缩进来更多地操作项目。
看看这张图片以获得更好的想法:
这个想法是列表中位于开始和结束项之间的项目应该相应地缩进。
所以,为了给出一个想法,我在 Paint 中编辑了屏幕截图,所以它看起来像这样:
解决这个问题的方法是什么?我的想法是遍历列表框并在 2 个单独的变量中返回开始项和结束项的数量,然后以某种方式确定其他项的位置以及两者之间是否合适 - 但我的逻辑从来没有这么好:(
为了便于使用,我在下面提供了代码来展示我是如何绘制图像和样式的:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ImgList, ComCtrls;
type
TForm1 = class(TForm)
ImageList1: TImageList;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
ListBox1: TListBox;
TabSheet2: TTabSheet;
ListBox2: TListBox;
TabSheet3: TTabSheet;
ListBox3: TListBox;
procedure FormCreate(Sender: TObject);
procedure ListBox1MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
procedure ListBox2MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
procedure ListBox2DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
procedure ListBox3MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
procedure ListBox3DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
// assign quick identifiers to image indexes
const
imgLayout = 0;
imgCalculator = 1;
imgComment = 2;
imgTime = 3;
imgStart = 4;
imgEnd = 5;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
ListStyle: TListBoxStyle;
begin
// set the listbox style here
ListStyle := lbOwnerDrawVariable;
ListBox1.Style := ListStyle;
ListBox2.Style := ListStyle;
ListBox3.Style := ListStyle;
end;
{******************************************************************************}
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
TextPosition: Integer;
Images: TImageList;
begin
TListBox(Control).Canvas.FillRect(Rect);
Images := ImageList1;
// draw the images
if TListBox(Control).Items.Strings[Index] = 'Layout' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgLayout);
end else
if TListBox(Control).Items.Strings[Index] = 'Calculator' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top,
imgCalculator);
end else
if TListBox(Control).Items.Strings[Index] = 'Comment' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgComment);
end else
if TListBox(Control).Items.Strings[Index] = 'Time' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgTime);
end;
// positions the text
TextPosition := (Rect.Bottom - Rect.Top - TListBox(Control).Canvas.TextHeight
(Text)) div 2;
// displays the text
TListBox(Control).Canvas.TextOut(Rect.Left + Images.Width + 8,
Rect.Top + TextPosition, TListBox(Control).Items.Strings[index]);
end;
procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
begin
Height := ImageList1.Height;
end;
{******************************************************************************}
procedure TForm1.ListBox2DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
TextPosition: Integer;
Images: TImageList;
begin
TListBox(Control).Canvas.FillRect(Rect);
Images := ImageList1;
// draw the images
if TListBox(Control).Items.Strings[Index] = 'Layout' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgLayout);
TListBox(Control).Canvas.Font.Style := [fsBold];
end else
if TListBox(Control).Items.Strings[Index] = 'Calculator' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top,
imgCalculator);
TListBox(Control).Canvas.Font.Color := clBlue;
TListBox(Control).Canvas.Font.Style := [fsItalic];
end else
if TListBox(Control).Items.Strings[Index] = 'Comment' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgComment);
TListBox(Control).Canvas.Font.Color := clRed;
end else
if TListBox(Control).Items.Strings[Index] = 'Time' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgTime);
end;
// positions the text
TextPosition := (Rect.Bottom - Rect.Top - TListBox(Control).Canvas.TextHeight
(Text)) div 2;
// displays the text
TListBox(Control).Canvas.TextOut(Rect.Left + Images.Width + 8,
Rect.Top + TextPosition, TListBox(Control).Items.Strings[index]);
end;
procedure TForm1.ListBox2MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
begin
Height := ImageList1.Height;
end;
{******************************************************************************}
procedure TForm1.ListBox3DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
TextPosition: Integer;
Images: TImageList;
begin
TListBox(Control).Canvas.FillRect(Rect);
Images := ImageList1;
// draw the images
if TListBox(Control).Items.Strings[Index] = 'Layout' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgLayout);
end else
if TListBox(Control).Items.Strings[Index] = 'Calculator' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top,
imgCalculator);
end else
if TListBox(Control).Items.Strings[Index] = 'Comment' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgComment);
end else
if TListBox(Control).Items.Strings[Index] = 'Time' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgTime);
end else
if TListBox(Control).Items.Strings[Index] = 'Start' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top,
imgStart);
TListBox(Control).Canvas.Font.Style := [fsBold];
end else
if TListBox(Control).Items.Strings[Index] = 'End' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4, Rect.Top, imgEnd);
TListBox(Control).Canvas.Font.Style := [fsBold];
end;
// positions the text
TextPosition := (Rect.Bottom - Rect.Top - TListBox(Control).Canvas.TextHeight
(Text)) div 2;
// displays the text
TListBox(Control).Canvas.TextOut(Rect.Left + Images.Width + 8,
Rect.Top + TextPosition, TListBox(Control).Items.Strings[index]);
end;
procedure TForm1.ListBox3MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
begin
Height := ImageList1.Height;
end;
{******************************************************************************}
end.
我将不胜感激有关如何确定操纵项目的一些提示。我知道我可以更改位图和文本的放置位置,但它会识别项目是否位于组之间,以及它是否设置了正确的缩进级别。
我希望这是有道理的,这就是我放一些模拟图片的原因。
谢谢 :)
PS,我从不写小帖子对不起!
使用工作演示更新
我已经接受了 Sertac 的回答,感谢 Sertac,我工作得很好。
为了帮助可能正在查看的其他人 - 因为我一直在学习 OOP,所以我想展示我的代码,看看它是否有好处:)
我制作了 2 个单元,Lib.pas 包含列表项的类,而 Unit1.pas 是 Form1 单元(我缩短了单元 1 以便更清楚地了解发生了什么):
库文件
unit Lib;
interface
uses
Classes, StdCtrls;
type
TMyListData = class(TObject)
public
fCaption: string;
fImageIndex: integer;
public
property Caption: string read fCaption write fCaption;
property ImageIndex: integer read fImageIndex write fImageIndex;
constructor Create;
destructor Destroy; override;
end;
type
TLayoutItem = class(TMyListData);
TCalculatorItem = class(TMyListData);
TCommentItem = class(TMyListData);
TTimeItem = class(TMyListData);
TStartItem = class(TMyListData);
TEndItem = class(TMyListData);
const
imgLayout = 0;
imgCalculator = 1;
imgComment = 2;
imgTime = 3;
imgStart = 4;
imgEnd = 5;
procedure NewLayoutItem(aListBox: TListBox);
procedure NewCalculatorItem(aListBox: TListBox);
procedure NewCommentItem(aListBox: TListBox);
procedure NewTimeItem(aListBox: TListBox);
procedure NewStartItem(aListBox: TListBox);
procedure NewEndItem(aListBox: TListBox);
procedure DeleteItem(aListBox: TListBox; aIndex: integer);
procedure CalculateIndents(aListBox: TListBox);
implementation
{ TMyListData }
constructor TMyListData.Create;
begin
inherited Create;
end;
destructor TMyListData.Destroy;
begin
inherited;
end;
procedure NewLayoutItem(aListBox: TListBox);
var
Obj: TLayoutItem;
begin
Obj := TLayoutItem.Create;
try
Obj.Caption := 'Layout';
Obj.ImageIndex := imgLayout;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure NewCalculatorItem(aListBox: TListBox);
var
Obj: TCalculatorItem;
begin
Obj := TCalculatorItem.Create;
try
Obj.Caption := 'Calculator';
Obj.ImageIndex := imgCalculator;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure NewCommentItem(aListBox: TListBox);
var
Obj: TCommentItem;
begin
Obj := TCommentItem.Create;
try
Obj.Caption := 'Comment';
Obj.ImageIndex := imgComment;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure NewTimeItem(aListBox: TListBox);
var
Obj: TTimeItem;
begin
Obj := TTimeItem.Create;
try
Obj.Caption := 'Time';
Obj.ImageIndex := imgTime;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure NewStartItem(aListBox: TListBox);
var
Obj: TStartItem;
begin
Obj := TStartItem.Create;
try
Obj.Caption := 'Start';
Obj.ImageIndex := imgStart;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure NewEndItem(aListBox: TListBox);
var
Obj: TEndItem;
begin
Obj := TEndItem.Create;
try
Obj.Caption := 'End';
Obj.ImageIndex := imgEnd;
aListBox.AddItem(Obj.Caption, Obj);
finally
Obj.Free;
end;
CalculateIndents(aListBox);
end;
procedure DeleteItem(aListBox: TListBox; aIndex: integer);
begin
aListBox.Items.Delete(aIndex);
aListBox.Items.Objects[aIndex] := nil;
CalculateIndents(aListBox);
end;
procedure CalculateIndents(aListBox: TListBox);
var
i: Integer;
Indent: Integer;
begin
Indent := 0;
for i := 0 to aListBox.Items.Count - 1 do
begin
if aListBox.Items[i] = 'End' then
Dec(Indent);
if Indent > -1 then
aListBox.Items.Objects[i] := Pointer(Indent);
if aListBox.Items[i] = 'Start' then
Inc(Indent);
end;
for i := aListBox.Items.Count - 1 downto 0 do
begin
if (aListBox.Items[i] = 'End') and (Indent = -1) then
begin
DeleteItem(aListBox, i);
Break;
end;
end;
end;
end.
单元1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ImgList, ComCtrls, Buttons;
type
TForm1 = class(TForm)
ImageList1: TImageList;
lbMain: TListBox;
btnLayout: TBitBtn;
btnCalculator: TBitBtn;
btnComment: TBitBtn;
btnTime: TBitBtn;
btnStartGroup: TBitBtn;
btnEndGroup: TBitBtn;
btnDelete: TBitBtn;
procedure FormCreate(Sender: TObject);
procedure lbMainMeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
procedure lbMainDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
procedure btnLayoutClick(Sender: TObject);
procedure btnCalculatorClick(Sender: TObject);
procedure btnCommentClick(Sender: TObject);
procedure btnTimeClick(Sender: TObject);
procedure btnStartGroupClick(Sender: TObject);
procedure btnEndGroupClick(Sender: TObject);
procedure btnDeleteClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Lib;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
// set the listbox style here
lbMain.Style := lbOwnerDrawVariable;
end;
procedure TForm1.lbMainDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
TextPosition: Integer;
Images: TImageList;
begin
TListBox(Control).Canvas.FillRect(Rect);
Images := ImageList1;
// draw the images
if TListBox(Control).Items.Strings[Index] = 'Layout' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgLayout);
end
else if TListBox(Control).Items.Strings[Index] = 'Calculator' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgCalculator);
end
else if TListBox(Control).Items.Strings[Index] = 'Comment' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgComment);
end
else if TListBox(Control).Items.Strings[Index] = 'Time' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgTime);
end
else if TListBox(Control).Items.Strings[Index] = 'Start' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgStart);
end
else if TListBox(Control).Items.Strings[Index] = 'End' then
begin
Images.Draw(TListBox(Control).Canvas, Rect.Left + 4 +
8 * Integer(TListBox(Control).Items.Objects[Index]),
Rect.Top, imgEnd);
end;
// positions the text
TextPosition := (Rect.Bottom - Rect.Top - TListBox(Control).Canvas.TextHeight
(Text)) div 2;
// displays the text
TListBox(Control).Canvas.TextOut(
Rect.Left + Images.Width + 8 + 8 * Longint(TListBox(Control).Items.Objects[Index]),
Rect.Top + TextPosition, TListBox(Control).Items.Strings[index]);
end;
procedure TForm1.lbMainMeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
begin
Height := ImageList1.Height;
end;
procedure TForm1.btnLayoutClick(Sender: TObject);
begin
NewLayoutItem(lbMain);
end;
procedure TForm1.btnCalculatorClick(Sender: TObject);
begin
NewCalculatorItem(lbMain);
end;
procedure TForm1.btnCommentClick(Sender: TObject);
begin
NewCommentItem(lbMain);
end;
procedure TForm1.btnTimeClick(Sender: TObject);
begin
NewTimeItem(lbMain);
end;
procedure TForm1.btnStartGroupClick(Sender: TObject);
begin
NewStartItem(lbMain);
end;
procedure TForm1.btnEndGroupClick(Sender: TObject);
begin
NewEndItem(lbMain);
end;
procedure TForm1.btnDeleteClick(Sender: TObject);
begin
if lbMain.ItemIndex <> -1 then
begin
DeleteItem(lbMain, lbMain.ItemIndex);
end;
end;
end.
它可以做得更好,即根据 Items.Objects[] 属性分配图像索引,但这完美无缺:)