我一直在玩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,imgCalculator); end else if TListBox(Control).Items.Strings[Index] = 'Comment' then begin Images.Draw(TListBox(Control).Canvas,imgComment); end else if TListBox(Control).Items.Strings[Index] = 'Time' then begin Images.Draw(TListBox(Control).Canvas,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,imgLayout); TListBox(Control).Canvas.Font.Style := [fsBold]; end else if TListBox(Control).Items.Strings[Index] = 'Calculator' then begin Images.Draw(TListBox(Control).Canvas,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,imgComment); TListBox(Control).Canvas.Font.Color := clRed; end else if TListBox(Control).Items.Strings[Index] = 'Time' then begin Images.Draw(TListBox(Control).Canvas,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,imgTime); end else if TListBox(Control).Items.Strings[Index] = 'Start' then begin Images.Draw(TListBox(Control).Canvas,imgStart); TListBox(Control).Canvas.Font.Style := [fsBold]; end else if TListBox(Control).Items.Strings[Index] = 'End' then begin Images.Draw(TListBox(Control).Canvas,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,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,以便更清楚地看到发生了什么):
Lib.pas
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.
Unit1.pas
unit Unit1; interface uses Windows,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]),imgLayout); end else if TListBox(Control).Items.Strings[Index] = 'Calculator' then begin Images.Draw(TListBox(Control).Canvas,imgCalculator); end else if TListBox(Control).Items.Strings[Index] = 'Comment' then begin Images.Draw(TListBox(Control).Canvas,imgComment); end else if TListBox(Control).Items.Strings[Index] = 'Time' then begin Images.Draw(TListBox(Control).Canvas,imgTime); end else if TListBox(Control).Items.Strings[Index] = 'Start' then begin Images.Draw(TListBox(Control).Canvas,imgStart); end else if TListBox(Control).Items.Strings[Index] = 'End' then begin Images.Draw(TListBox(Control).Canvas,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]),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 []属性分配图像索引但这完全有效:)
解决方法
一种方法是迭代项目并修改文本以指示缩进:
procedure TForm1.FormCreate(Sender: TObject); var i: Integer; Indent: Integer; begin ... Indent := 0; for i := 0 to ListBox3.Items.Count - 1 do begin if Pos('End',ListBox3.Items[i]) > 0 then Dec(Indent); if Indent > 0 then ListBox3.Items[i] := StringOfChar(#32,2 * Indent) + ListBox3.Items[i]; if Pos('Start',ListBox3.Items[i]) > 0 then Inc(Indent); end; 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 Pos('Layout',TListBox(Control).Items.Strings[Index]) > 0 then begin Images.Draw(TListBox(Control).Canvas,imgLayout); end else if Pos('Calculator',TListBox(Control).Items.Strings[Index]) > 0 then ..
(使用这种方法,缩进图像会有点工作,计算项目文本中的前导空格,依此类推……)
如果项目的对象尚未使用,则稍微更好的方法是将缩进存储为整数,并在绘制时使用该信息.例如.迭代时:
Indent := 0; for i := 0 to ListBox3.Items.Count - 1 do begin if ListBox3.Items[i] = 'Start' then Inc(Indent); ListBox3.Items.Objects[i] := Pointer(Indent); if ListBox3.Items[i] = 'End' then Dec(Indent); end;
绘图时:
.. if TListBox(Control).Items.Strings[Index] = 'Layout' then begin Images.Draw(TListBox(Control).Canvas,imgLayout); .. // displays the text TListBox(Control).Canvas.TextOut( Rect.Left + Images.Width + 8 + 8 * Longint(TListBox(Control).Items.Objects[Index]),TListBox(Control).Items.Strings[index]); ..