TVirtualDrawTree - Как разместить узлы в одном ряду?
Это продолжение моего другого вопроса здесь.
как мне было предложено в комментарии, чтобы задать новый вопрос по этому вопросу
Мне предложили нарисовать разные изображения в строке. моя цель с самого начала вставлять узлы бок о бок мне сказали, что это не может быть сделано с VDT, это не сделано для этой цели. но что делает меня уверенным, что есть способ, потому что я вижу онлайн-проект, использующий тот же VDT
вот скриншот из этого проекта
с помощью средства просмотра ресурсов, как PE Explorer, я нашел эти данные формы
object VDT: TVirtualDrawTree
AlignWithMargins = True
Left = 5
Top = 5
Width = 457
Height = 227
Margins.Left = 5
Margins.Top = 5
Margins.Right = 5
Margins.Bottom = 5
Align = alClient
BevelInner = bvNone
BevelOuter = bvNone
DefaultNodeHeight = 55
Header.AutoSizeIndex = 0
Header.Font.Charset = DEFAULT_CHARSET
Header.Font.Color = clWindowText
Header.Font.Height = -11
Header.Font.Name = 'Tahoma'
Header.Font.Style = []
HotCursor = crHandPoint
TabOrder = 0
TreeOptions.PaintOptions = [toHideFocusRect, toHideSelection, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toAlwaysHideSelection, toUseBlendedSelection]
TreeOptions.SelectionOptions = [toExtendedFocus, toMiddleClickSelect, toRightClickSelect]
OnBeforeCellPaint = VDTBeforeCellPaint
OnGetNodeWidth = VDTGetNodeWidth
OnMouseUp = VDTMouseUp
ExplicitLeft = 3
ExplicitTop = 3
Columns = <
item
Position = 0
Width = 54
WideText = '55'
end
item
Position = 1
Width = 54
WideText = '55'
end
item
Position = 2
Width = 54
WideText = '55'
end
item
Position = 3
Width = 54
WideText = '55'
end
item
Position = 4
Width = 54
WideText = '55'
end
item
Position = 5
Width = 54
WideText = '55'
end
item
Position = 6
Width = 54
WideText = '55'
end
item
Position = 7
Width = 54
WideText = '55'
end>
end
end
так что я сказал себе, что я должен использовать Tviruaildrawtree
чтобы получить ту же цель, то я начинаю создавать данные
type
TAnmiClass = class
private
Fanmigraphic : TGifImage;
public
property anmigraphic: TGifImage read Fanmigraphic write Fanmigraphic;
public
constructor Create;
destructor Destroy; override;
end;
type
PAnimeData = ^TAnimeData;
TAnimeData = record
FObject: TAnmiClass;
end;
так как я думал, что мне нужно создать объект изображения для узла, потому что я буду загружать некоторый список изображений из URL, затем добавлю их в узел, как показано ниже, поэтому следующий код загружает изображения из списка строк в рабочий стол, а затем загружает его в узел Tgifimage
For i := 0 To animationimages.Count-1 do
begin
Animaturl := animationimages.Strings[i];
URI := TIdURI.Create(Animaturl);
try
ImageName := URI.Document;
finally
FreeAndNil(URI);
end;
if (ExtractFileExt(ImageName) = '.gif') then
begin
addanimation(Animaturl);
end;
end;
procedure TForm2.addanimation(AAnimationUrl: String);
var
AnmiClass: TAnmiClass;
path: string;
begin
VDTAni.BeginUpdate;
try
AnmiClass := TAnmiClass.Create;
path := AAnimationUrl;
if fileexists(path) then
begin
AnmiClass.anmigraphic.LoadFromFile(path);
AnmiClass.anmigraphic.Animate := True;
AnmiClass.anmigraphic.Transparent := True;
end;
AddAnmiToVD(VDTAni, nil, AnmiClass);
finally
VDTAni.EndUpdate;
end;
и вот, как я рисую узлы внутри VDT
procedure TForm2.VDTAniBeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
var
Data: PAnimeData;
NewRect: TRect;
R: TRect;
begin
//
if not Assigned(Node) then
begin
exit;
end;
Data := VDTAni.GetNodeData(Node);
case Column of
0 :
begin
NewRect := ContentRect;
NewRect.Left := NewRect.Left +2;
NewRect.Width := 55;
NewRect.Height := 55;
NewRect.Top := NewRect.Top + 2;
NewRect.Bottom := NewRect.Bottom;
TargetCanvas.StretchDraw( NewRect, Data.FObject.anmigraphic);
end;
end;
end;
но я не могу расположить узлы так же, как изображение, которое я показываю выше
и кажется, что это не может быть сделано в onbeforecellpanit
,
в моем другом вопросе Том Брунберг предложил разделить изображения на 10 узлов, если добавленное изображение равно 80, а в качестве примера необходимо 8 на строку, каждое из которых имеет 8 изображений и каждое изображение отображается в своем собственном столбце. но я не знаю, как это сделать в коде или с чего начать.
Выдача действующего кода
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, Gifimg, Vcl.StdCtrls,
Vcl.Grids, Vcl.ExtCtrls;
type
TImageOBJArr = array of TGifimage;
type
TaniDataclass = class
ImageOBJArr: TImageOBJArr;
private
FAnirefrence: String;
FAniIMage: TGifimage;
public
property Anirefrence: String read FAnirefrence write FAnirefrence;
property AniIMage: TGifImage read FAniIMage write FAniIMage;
public
constructor Create;
destructor Destroy; override;
end;
type
Panidata = ^Tanidata;
Tanidata = record
FObject: TaniDataclass;
end;
type
TForm1 = class(TForm)
VDTani: TVirtualStringTree;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure VDTaniBeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
procedure FormCreate(Sender: TObject);
procedure VDTaniFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure VDTaniGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
private
{ Private declarations }
ImageOBJArr: TImageOBJArr; // Main storage of images
public
{ Public declarations }
Dimagelist : Tstringlist;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TaniDataclass }
constructor TaniDataclass.Create;
begin
FAniIMage := TGifImage.Create;
end;
destructor TaniDataclass.Destroy;
begin
FAniIMage.Free;
inherited;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Node: PVirtualNode;
Data: Panidata;
i, row, col: integer;
fn: String;
begin
// Load images to main store ImgArr
SetLength(ImageOBJArr, Dimagelist.Count);
for i := 0 to Dimagelist.Count -1 do
begin
fn := Dimagelist[I];
ImageOBJArr[i] := TGifimage.Create;
ImageOBJArr[i].LoadFromFile(fn);
end;
// Setup vdt nodes and assign images eight in a row
// hardcoded for now. You may want to add dynamics
// for varying window and image sizes
row := 0;
while row <= (Dimagelist.Count div 8) do
begin
Node := VDTani.AddChild(nil);
Data := VDTani.GetNodeData(Node);
SetLength(Data.FObject.ImageOBJArr, 8);
for col := 0 to 7 do
Data.FObject.ImageOBJArr[col] := ImageOBJArr[row * 8 + col];
inc(row);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Dimagelist := Tstringlist.Create;
VDtAni.NodeDataSize := SizeOf(Tanidata);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if Assigned(Dimagelist) then
begin
FreeAndNil(Dimagelist);
end;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
Dimagelist.Add('1mm.gif');
Dimagelist.Add('2mm.gif');
Dimagelist.Add('3mm.gif');
Dimagelist.Add('4mm.gif');
Dimagelist.Add('5mm.gif');
Dimagelist.Add('6mm.gif');
end;
procedure TForm1.VDTaniBeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
var
Data: Panidata;
begin
if not Assigned(Node) then
begin
exit;
end;
Data := VDTani.GetNodeData(Node);
Sender.NodeHeight[Node] := 54;
CellRect.Height := 54;
TargetCanvas.StretchDraw( CellRect, Data.FObject.ImageOBJArr[Column]);
end;
procedure TForm1.VDTaniFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
Data: Panidata;
begin
Data := VDTani.GetNodeData(Node);
if Assigned(Data) then
Data.FObject.Free;
end;
procedure TForm1.VDTaniGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
begin
NodeDataSize := SizeOf(Tanidata);
end;
end.
я получил исключение здесь в следующем коде, я добавил 6 изображений путь к списку строк, а затем попытаться нарисовать на каждом столбце
row := 0;
while row <= (Dimagelist.Count div 2) do
begin
Node := VDTani.AddChild(nil);
Data := VDTani.GetNodeData(Node);
SetLength(Data.FObject.ImageOBJArr, 2);
for col := 0 to 7 do
Data.FObject.ImageOBJArr[col] := ImageOBJArr[row * 2 + col];
inc(row);
end;
1 ответ
Вот реализация того, что я предложил.
type
TImgArr = array of TBitmap;
TVdtData = record
FObject: TimgArr;
end;
PVdtData = ^TVdtData;
TForm2 = class(TForm)
Vdt: TVirtualDrawTree;
...
private
{ Private declarations }
ImgArr: TImgArr; // Main storage of images
implementation
procedure TForm2.Button1Click(Sender: TObject);
var
Node: PVirtualNode;
Data: PVdtData;
p: pointer;
i, row, col: integer;
fn: TFileName;
begin
// Load images to main store ImgArr
SetLength(ImgArr, 100);
for i := 0 to 99 do
begin
fn := Format('c:\tmp\nums\%.2d.bmp',[i]);
ImgArr[i] := TBitmap.Create;
ImgArr[i].LoadFromFile(fn);
end;
// Setup vdt nodes and assign images eight in a row
// hardcoded for now. You may want to add dynamics
// for varying window and image sizes
row := 0;
while row <= (100 div 8) do
begin
Node := Vdt.AddChild(nil);
p := Node.GetData;
Data := Vdt.GetNodeData(Node);
// SetLength(Data.FObject, 8);
SetLength(Data.FObject, Vdt.Header.Columns.Count);
for col := 0 to 7 do
Data.FObject[col] := ImgArr[row * 8 + col];
inc(row);
end;
end;
procedure TForm2.VdtBeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
var
Data: PVdtData;
begin
if not Assigned(Node) then exit;
Data := Vdt.GetNodeData(Node);
Sender.NodeHeight[Node] := 64;
CellRect.Height := 64;
if Assigned(Data.FObject[Column]) then
TargetCanvas.StretchDraw( CellRect, Data.FObject[Column]);
end;
Нет гарантии, что ошибки не несут.
И результат
А если серьезно, как уже отмечали другие, было бы гораздо проще просто использовать TDrawGrid
или же TStringGrid
, Конечно, это ваш звонок.