Jak narysować ikonkę w VirtualStringTree?

Jak narysować ikonkę w VirtualStringTree?
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Cześć,

szukałem rozwiązania w googlach i nie udało mi się znaleźć rozwiązania dlatego prośba o pomoc.

W bazie danych mam pole Blob w którym przechowuję plik BMP z obrazkiem.
Obrazek ten ma być wyświetlane przy głównym więźle tzn NodeLevel = 0

W jaki sposób namalować bitmapę obok więzła?
W załączniku screen aktualnego drzewa.

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Najprościej:

  1. załadować pod - TImage.
  2. Obsłużyć OnGetIndex
    Bardziej skomplikowane, BeforePaint lub AfterPaint

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

OK spróbuję tak jak opisałeś

EDIT:
No nie daję rady, nie podstawia obrazka do Image1...

Wczytywanie z bazy danych

Kopiuj
procedure TfrmRepository.BuildTree(Tree: TVirtualStringTree; ID_U, ID_S: integer);
var
  Dataset: TIBDataset;
  MS: TMemoryStream;
  Bmp: TBitmap;
  Blob: TBlobField;
begin

  Tree.Clear;

  try
    Dataset := TIBDataset.Create(nil);
    Dataset.Database := frmdm.IBDatabase1;
    Dataset.Transaction := frmdm.IBTransaction1;
    Dataset.BufferChunks := 10;
    Dataset.SelectSQL.Text := 'select * from repository where id_u = :id_u and id_s = :id_s';
    Dataset.ParamByName('id_u').AsInteger := ID_U;
    Dataset.ParamByName('id_s').AsInteger := ID_S;
    Dataset.DisableControls;
    Dataset.Open;

    while not Dataset.Eof do
    begin
      MS := TMemoryStream.Create();
      Bmp := TBitmap.Create();
      Bmp.Width := 16;
      Bmp.Height := 16;
      (Dataset.FieldByName('icon') as TBlobField).SaveToStream(MS);
      MS.Position := 0;
      Bmp.LoadFromStream(MS);
      
      // Jeśli zrobię to tutaj to obrazek jest widoczny
      //Image1.Picture.Bitmap.Handle :=  Bmp.Handle;
      // Niestety wszystko musi się dziać w funkcji AddItem (ostatni parametr)

      AddItem(Tree,
        Dataset.FieldByName('ID_Rep').AsInteger,
        Dataset.FieldByName('process_name').AsString,
        Dataset.FieldByName('window_class').AsString,
        Dataset.FieldByName('window_title').AsString,
        Dataset.FieldByName('control_class').AsString,
        Dataset.FieldByName('control_name').AsString,
        Dataset.FieldByName('control_text').AsString,
        Bmp.Handle); // hicon

      Bmp.Free;
      MS.Free;
      Dataset.Next;
    end;

    Dataset.Close;
    Dataset.EnableControls;

    Tree.ClearSelection;
    Tree.FullCollapse();
    Tree.FocusedNode := nil;

    FreeAndNil(Dataset);
  except
    on e:exception do
    begin
      frmMenu.ShowMessageDlg('Błąd wczytywania repozytorium!#13#13<b>' + e.Message + '</b>', 'err');
      FreeAndNil(Dataset);
    end;
  end;
end;
Kopiuj
Funkcja AddNode
function TfrmRepository.AddItem(Tree: TVirtualStringTree; ID_Rep: integer; ProcessName, WindowClass, WindowTitle,
  ControlClass, ControlName, ControlText: string; hIcon: hIcon): integer;
var
  Data: PRepository;

  ms: TMemoryStream;
  bmp: TBitmap;
begin
  Tree.BeginUpdate;

    ProcessNode := Tree.AddChild(nil);
    Data := Tree.GetNodeData(ProcessNode);
    Data.ProcessIcon := hIcon; // przypisuję hIcon do daty

  end;
end;

a tak wygląda wskaźnik z danymi:

Kopiuj
type // Lista instrukcji
  PRepository = ^TRepository;
  TRepository = record
    ProcessIcon: hIcon;
  end;

Zrobiłem dla tesów na OnClick nody podstawianie obrazka do Image na podstawie hIcon handle

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  Data: PRepository;
begin
  Data := VST.GetNodeData(HitInfo.HitNode);

  Image1.Picture.Bitmap.Handle := Data.ProcessIcon;

end;

no i niestety ale obraz nie jest wyświetlany... o co chodzi? Dodam, że jak debuguję zdarzenie OnClick to w zmiennej Data.ProcessIcon mam wartość.

edytowany 2x, ostatnio: user322
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Gorlice
2

Bo nie do TImage tylko do TImageList który ustawiasz w Object Inspector jako Images i w zdarzeniu OnGetImageIndex podajesz Indeks obrazka dla danego Node (z tego image list).


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Ok, nie do TImage, ale możecie mi wytłumaczyć dlaczego powyższy kod nie działa? Podstawianie działa tylko w przypadku, gdy robię to zaraz pod wczytaniem ze streamu, po przekazaniu do PRepository i zaczytaniu z nody, nie wyświetla...

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Bo Icon to nie jest Bitmapa.

Kopiuj
var
  MyIcon:TIcon;
  icoHandle: HIcon;
begin
  MyIcon:=TIcon.Create;
  try
   icoHandle := ExtractIcon(application.handle,'c:\windows\explorer.exe', 0) ;
   MyIcon.Handle:=icoHandle;
   Image1.Picture.Icon:=MyIcon;
  finally
   MyIcon.free;
  end;
end;

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
U3
Ja nie używam ikony tylko Bitmap, wczytuję bitmapę do TBitmap i przykazuję jej handle do funkcji AddItem, następnie wewnątrz chcę na podstawie handle odrysować ją w TImage
_13th_Dragon
O tak! ProcessIcon: hIcon; ... Image1.Picture.Bitmap.Handle := Data.ProcessIcon;
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Robię:

Kopiuj
var
  Data: PRepository;
begin
Data.ProcessIcon := hIcon; // hIcon = TBitmap;
 Image1.Picture.Bitmap.Assign(Data.ProcessIcon);
end;

I obrazek się pojawia, ale w OnNodeClick, gdy wykonuję:

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  Data: PRepository;
begin
  Data := VST.GetNodeData(HitInfo.HitNode);


  Image1.Picture.Bitmap.Assign(Data.ProcessIcon);

end;

To obrazka nie ma, dodatkowo uchwyt tej bitmapy = 0... możecie pomóc mi to rozwiązać?

_13th_Dragon
Odpowiedź masz w poście wyżej.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0
Kopiuj
type 
  PRepository = ^TRepository;
  TRepository = record
    ProcessIcon: hIcon;
  end;
Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  Data: PRepository;
  ico: TIcon;
begin
  Data := VST.GetNodeData(HitInfo.HitNode);

  Ico := TIcon.Create();
  Ico.Handle := Data.ProcessIcon;
  Image1.Picture.Icon := Ico;
 // Image1.Picture.Bitmap.Assign(Data.ProcessIcon);

end;

Nie działa. Ta odpowiedź nie bardzo chce działać...

_13th_Dragon
Trzymaj w TRepository TIcon a nie hIcon
U3
Ale czemu mam trzymać TIcon skoro z bazy wczytuję Bitmapę TBitmap? mam rzutować ja na TIcon?
olesio
O ile wiem, to rzutowania nie stosuje się w przypadku takich typów. Nie zadziała raczej.
olesio
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Czy ProcessIcon zawiera właściwą ikonę na 100%? Bo taki kod, jak poniżej działa.

Kopiuj
var
  Ico : TIcon;
begin
  Ico := TIcon.Create;
  Ico.Assign(Application.Icon);
  Image1.Picture.Icon.Handle := Ico.Handle;
  Ico.Free;
end;

Tak samo jak taki jego wariant:

Kopiuj
var
  Ico : TIcon;
begin
  Ico := TIcon.Create;
  Ico.Handle := Application.Icon.Handle;
  Image1.Picture.Icon.Handle := Ico.Handle;
  Ico.Free;
end;

Pozdrawiam.
edytowany 1x, ostatnio: olesio
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Nie wiem jak dlaczego miałby posiadać nie własciwą ikonkę, przekazuję dokładnie te same parametry, tak jak by odczyt z VirtualStringTree nie był w pełni kompatybilny... nie wiem o co chodzi, męczę to od rana...

Bezpośrednio po zapisie do wskaźnika i linijka po przypisaniu odczyt obrazka działa, ale jeśli robię odczyt w OnNodeClick to obrazek nie jest wczytywany...

edytowany 1x, ostatnio: user322
olesio
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
1

To nie wiem. Ja na ogół wszelkie Data zawarte w ListItemach, ale głownie TListView rzutuje do zmiennej typu obiektu, typem obiektowym, a nie wskaźnikowym. I nie miałem raczej problemów. Może ktoś jeszcze coś Ci tutaj doradzi, bo ja tego komponentu co używasz nie znam. I nie musiałem do tej pory poznać.


Pozdrawiam.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

odczyt.png
po przypisaniu.png
Po odczycie ze wskaźnika TIcon ma całkiem inny uchwyt, inne rozmiary wychodzące poza integer zamiast 16x16 - bo taki obrazek tam przechowuję. HOWARD WHY????

edytowany 4x, ostatnio: flowCRANE
flowCRANE
To przetestuj wstawianie obrazków w tym poście :)
flowCRANE
Jeśli chcesz określić jego szerokość, to po nazwie załącznika dodaj dwa znaki | oraz jego szerokość w pikselach, np. ![Foo.png](//static.4programmers.net/uploads/attachment/Foo-image(400x400).png) - ustali szerokość obrazka na 400px (tylko do wyświetlenia, fizycznie nie zmieni rozmiaru obrazka w załączniku);
flowCRANE
Tylko pamiętaj, żey każdy obrazek wstawiać zawsze w osobnej linii, bo parser może wariować;
olesio
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Może dlatego, że dodajesz do własności przechowującej Pointery obiekt jako Pointer. Albo tak też się odwołujesz. Na przykład taki kod jak poniżej, wyświetli ikonę Aplikacji, ale dopiero po naciśnięciu Button2. Po tym gdy klikniemy na Button1, teoretycznie nic się nie dzieje w kwestii wyświetlania i Handle też będzie inne niż pokazuje się w zerowej kolumnie ListView. Analogicznie dzięję się z wszelkimi komponentami przechowującymi Dane jako Pointery. W tym pewnie i ten, którego używasz u siebie w kodzie.

Kopiuj
//...
type
  TObj = class(TObject)
    AnIcon : HICON;
  end;
  PObj = ^TObj;

procedure TForm1.FormCreate(Sender : TObject);
var
  Obj : TObj;
  LI : TListItem;
begin
  LI := ListView1.Items.Add;
  Obj := TObj.Create;
  Obj.AnIcon := Application.Icon.Handle;
  LI.Caption := IntToStr(Obj.AnIcon);
  LI.Data := Obj;
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  ObjPtr : PObj;
  LI : TListItem;
begin
  LI := ListView1.Items.Item[0];
  ObjPtr := LI.Data;
  Image1.Picture.Icon.Handle := ObjPtr.AnIcon;
  Caption := IntToStr(ObjPtr.AnIcon);
end;

procedure TForm1.Button2Click(Sender : TObject);
var
  Obj : TObj;
  LI : TListItem;
begin
  LI := ListView1.Items.Item[0];
  Obj := LI.Data;
  Image1.Picture.Icon.Handle := Obj.AnIcon;
  Caption := IntToStr(Obj.AnIcon);
end;
//...

EDIT: teraz widzę. Trzymasz to jako rekord. Nie znam się, z tym zawsze miałem problemy. Lepiej przechowywać to co siedzi w Data, jako obiekt i już. Nie ma też wtedy problemu przekazywania go jako Pointer dla wątków w kodzie korzystającym z WinAPI.

EDIT #2: dla obsługi typu rekordowego, jeśli się przy nim upierasz. Musisz "pokombinować" mniej więcej tak, jak pokazuje poniżej:

Kopiuj
//..
type
  TObj = record
    AnIcon : HICON;
  end;

procedure TForm1.FormCreate(Sender : TObject);
var
  Obj : TObj;
  ObjPtr : ^TObj;
  LI : TListItem;
begin
  LI := ListView1.Items.Add;
  Obj.AnIcon := Application.Icon.Handle;
  ObjPtr := @Obj;
  LI.Caption := IntToStr(Obj.AnIcon);
  LI.Data := Pointer(Obj);
end;

procedure TForm1.Button1Click(Sender : TObject);
var
  ObjPtr : ^TObj;
  LI : TListItem;
begin
  LI := ListView1.Items.Item[0];
  ObjPtr := @LI.Data;
  Image1.Picture.Icon.Handle := ObjPtr.AnIcon;
  Caption := IntToStr(ObjPtr.AnIcon);
end;
//...

Pozdrawiam.
edytowany 4x, ostatnio: flowCRANE
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

O matko :P spróbuję jutro i dam znać, dzisiaj już nie mam siły na to... Dzięki Olesio

U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

@olesio w tym rekordzie lepiej trzymać hIcon czy może całą ikonkę TIcon? Będzie jakaś różnica?

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Przecież już dostałeś odpowiedź na to pytanie, HICON który dostałeś od systemu może zostać zwolniony przez system w nieoczekiwanym momencie.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Porażka...
Odczyt

Kopiuj
var
  Data: PRepository;

  ObjPtr : ^TRepository;
begin
  Data := VST.GetNodeData(HitInfo.HitNode);
  ObjPtr := @Data.ProcessIcon;

  Image1.Picture.Icon := ObjPtr.ProcessIcon;

Zapis:

Kopiuj
var
  Data: PRepository;
  ObjPtr : ^TRepository;
  Obj : TRepository;
begin

    ProcessNode := Tree.AddChild(nil);
    Data := Tree.GetNodeData(ProcessNode);
    Data.ProcessIcon := Ico;

    // Wersja Olesio
    Obj.ProcessIcon := Ico;
    ObjPtr := @Obj;
end;

Access Violation na odczycie ;/

olesio
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Nie znam tego komponentu, pokazałem Ci jak to się robi z typami rekordowymi dla celów TListView. A czy na pewno dane w Nodzie są przechowywane jako typ Pointer? Poza tym wydaje się mi, że jednak ja dodaje i odczytuje nieco inaczej. Ale kombinuj, jak uważasz.


Pozdrawiam.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Zrobiłem tak:

Odczyt:

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  ObjPtr : ^TRepository;
begin
  ObjPtr := VST.GetNodeData(HitInfo.HitNode);
  Image1.Picture.Icon:= ObjPtr.ProcessIcon;
end;

Zapis:

Kopiuj
    Data := Tree.GetNodeData(ProcessNode);
var
  Ico: TIcon;
  Data: PRepository;

  Obj : TRepository;
  ObjPtr : ^TRepository;
begin
    Ico := Application.Icon;

    Obj.ProcessIcon := Ico;
    ObjPtr := @Obj;
    Data.ProcessIcon := Pointer(Obj.ProcessIcon);

Rekord

Kopiuj
type 
  PRepository = ^TRepository;
  TRepository = record
    ProcessIcon: TIcon;
end;

Po kliknięci pierwszy raz na Node podczas odczytu w zmiennej Obj.ProcessIcon mam ikonkę, lecz po przejściu na następną pozycję w drzewku i powrót na poprzednią powoduje, że obiekt znowu ma dziwne dane, dodatkowo, gdy w kodzie przed przypisaniem obiektu wykonam taki kod:

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  ObjPtr : ^TRepository;
begin
  Image1.Picture.Icon := nil; // magiczna linijka
  
  // ObjPtr od razu ma nieprawidłowe wartości nawet przy pierwszym kliknięciu

  ObjPtr := VST.GetNodeData(HitInfo.HitNode);
  Image1.Picture.Icon:= ObjPtr.ProcessIcon;
end;

Jeszcze robię coś źle?

flowCRANE
Skoro nie działa prawidłowo, to coś na pewno jest źle :)
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Tuchów
  • Postów:12168
0
user322 napisał(a):

@olesio w tym rekordzie lepiej trzymać hIcon czy może całą ikonkę TIcon? Będzie jakaś różnica?

Skoro już programujesz z wykorzystaniem VCL, to nie baw się w pointery - trzymaj po prostu referencję do instancji klasy ikony typu TIcon; Pamięć dla ikony i tak będzie musiała być zarezerwowana, więc te kilka bajtów więcej nie będzie stanowić wielkiego problemu;

Zyskasz większą wygodę i prostotę użytkowania, bo ominiesz rzutowanie i zabawę wskaźnikami, z którymi coś się motasz;

Kopiuj
Image1.Picture.Icon := nil; // magiczna linijka

IMHO tą magiczną linijką powodujesz wyciek pamięci, jeśli takie przypisanie nie jest odpowiednio obsługiwane przez wewnętrzne mechanizmy komponentu (obsługa właściwości nie zwalnia zarezerwowanej dla ikony pamięci); Trzeba by to zwąchać.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

@furious programming mistrzu poradź jak rozwiązać ten problem! :)

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Tuchów
  • Postów:12168
0

Przede wszystkim stwórz sobie zestaw ikon, zawierający ikonki mogące zostać załadowane do instancji klas w jak najprostszy sposób; Rekord który pakujesz do danych itema także może być prostą klasą - ułatwisz sobie pracę na rzecz kilku(nastu) bajtów więcej;

Ja nie znam tego komponentu, więc napisz jakiego typu dane zwraca ta instrukcja:

Kopiuj
VST.GetNodeData(HitInfo.HitNode);

i co kryje się w typie THitInfo i polu/właściwości HitInfo.HitNode.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0
Kopiuj
VST.GetNodeData(HitInfo.HitNode);

zwraca Pointer, nastomiast HitInfo jest klasą zawierającą metody dot. aktualnie zaznaczonej pozycji np. HitNode (aktualnie wybrana noda), HitColumn (Kolumna w której kliknęliśmy), z kolei HitNode jest typem TVirtualNode;

Kopiuj
edytowany 2x, ostatnio: user322
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Tuchów
  • Postów:12168
0

No dobra, napisz jeszcze czym jest TRepository i PRepository, oraz dlaczego zmienne deklarujesz jako:

Data: PRepository;
lub

Kopiuj
ObjPtr: ^TRepository;

Jeśli PRepository to wskaźnik na TRepository, to raczej nie ma sensu deklarować ich inaczej.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0
Kopiuj
Data: PRepository;

nauczyłem się korzystać tak z wielu przykładów i także stąd Virtual Treeview

Kopiuj
ObjPtr: ^TRepository;

Jest to kombinowanie w stylu tego co @olesio poradził, jak on to robi z ListView, ale no mi to nie działa na VirtualStringTree, albo źle coś robię.

A TRepository jest to rekord z danymi dla wskaźnika:

Kopiuj
type 
  PRepository = ^TRepository;
  TRepository = record
    Nazwa: string;
    Kolumna1: string;
    Kolumna2: string;
    ProcessIcon: TIcon;
  end;
edytowany 3x, ostatnio: user322
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 8 godzin
  • Lokalizacja:Tuchów
  • Postów:12168
0

Zapisy PRepository i ^TRepository są równoznaczne na poziomie języka, jednak mogą mylić;

Z drugiej strony tak patrzę na ten tutorial z podanego linka i mam wątpliwości... Birąc pod lupę poniższy kod:

Kopiuj
var
  Data: PWirtualnyRekord;
begin
  Data := Sender.GetNodeData(Node);
  if Length(Data.Caption) = 0 then
  Data.Caption := 'Wiersz ' + IntToStr(Sender.AbsoluteIndex(Node)+1);  // tu problem...
  CellText := Data.Caption;
end; 

już na pierwszy rzut oka widać błędy; Jeśli PWirtualnyRekord jest wskażnikiem na rekord typu TWirtualnyRekord, to odwołanie do zmiennej Data jako wskaźnika w sposób Data.Caption jest niepoprawne i taki kod powinien walić błędami Access Violation; Prawidłowym zapisem było by Data^.Caption;

Dlatego też jeśli wrzucasz wskaźnik do danych węzła, to po jego pobraniu powinieneś się odwoływać do jego składowych za pomocą operatora ^; @olesio pokazał Ci przykład z wykorzystaniem obiektu, a nie rekordu, więc musisz analizować podawane kody i rozumieć jak działają;</del>
Dobrze jest jednak - zapomniałem że brak operatora ^ w Delphi jest dopuszczalny; Przesiadłem się na FPC, a tam bez daszka kod się nie skompiluje;

Obstawiałbym, że poniższy kod:

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var
  ObjPtr : ^TRepository;
begin
  ObjPtr := VST.GetNodeData(HitInfo.HitNode);
  Image1.Picture.Icon:= ObjPtr.ProcessIcon;
end;

powinien wyglądać coś w ten deseń:

Kopiuj
procedure TfrmRepository.VSTNodeClick(Sender: TBaseVirtualTree; const HitInfo: THitInfo);
var
  ptrRep : PRepository;
begin
  ptrRep := PRepository(VST.GetNodeData(HitInfo.THitInfo));
  Image1.Picture.Icon := ptrRep^.ProcessIcon;
end;

Napisałem "w ten deseń", bo składniowo było by poprawnie, jednak nie mam jak tego przetestować; No i musisz pamiętać, że jeśli korzystasz ze wskaźników, to rekordy na które wskaźniki wskazują muszą posiadać zaalokowaną pamięć; Bez względu na to czy istnieją one w jakichś zmiennych, polach klasy, macierzach, czy alokowane dynamicznie, za pomocą np. GetMem; Osobiście wybrałbym dynamiczną alokację i trzymanie wskaźników na ich pamięć tylko w danych elementów; Dzięki temu przy tworzeniu nowego elementu drzewa, alokowałoby się pamięć dla nowego rekordu i przypisywało wskaźnik do zaalokowanej pamięci, a przy usuwaniu zwalniałoby się ją;

Jak widzisz korzystanie ze wskaźników daje ciekawe możliwości, ale ich obsługa nie jest taka prosta i łatwo się pogubić, przez co kod może nie działać prawidłowo, a program generować wycieki pamięci; Jeśli jeszcze motasz się ze wskaźnikami, to poćwicz sobie wcześniej na dedykowanym jedynie dla testów programie - mniej będziesz miał później problemów.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 9x, ostatnio: flowCRANE
szopenfx
w Delphi można pominąć operator dereferencji Data.Caption jest równoważne Data^.Caption.
flowCRANE
Aj jaj jaj, faktycznie - przerzuciłem się już jakiś czas temu na FPC, a tam to błąd już na poziomie kompilacji... Dzięki za przypomnienie;
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Twój kod się kompiluje, jednak po klinkięciu otrzymuję komunikat

Kopiuj
Stream read error

po kliknięciu Debug przenosi mnie do Unitu System.Classes

Kopiuj
```delphi
procedure TStream.ReadBuffer(var Buffer; Count: Longint);
var
  Buf: TBytes;
  LTotalCount,
  LReadCount: Longint;
begin
  SetLength(Buf, Count);
  if Count = 0 then Exit;

  { Perform a read directly. Most of the time this will succeed
    without the need to go into the WHILE loop. }

  LTotalCount := Read(Buf, 0, Count);

  while (LTotalCount < Count) do
  begin
    { Try to read a contiguous block of <Count> size }
    LReadCount := Read(Buf, LTotalCount, (Count - LTotalCount));

    { Check if we read something and decrease the number of bytes left to read }
    if LReadCount <= 0 then
      raise EReadError.CreateRes(@SReadError) // TĄ LINIJKE PODŚWIETLA
    else
      Inc(LTotalCount, LReadCount);
  end;
  Move(Buf[0], Buffer, Count);
end;

Ponadto, przy wyjściu z programu mam accessy :(

Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
1

Witam.
Nie wiem dokładnie co chcesz uzyskać (przyznaję się, nie czytałem całości :(, ale żeby narysować ikonkę w wybranym węźle, zrobiłem to tak:
Do wirtualnego rekordu VST dodałem jeszcze jedno pole, np. 'NumerIkonki : Integer', teraz po kliknięciu w odpowiedniego Noda, do tego pola przypisywana jest jakaś wartość (w zależności jaką chcę ikonkę). Wszystkie ikonki (u mnie *.png) wrzuciłem do 'ImageList1' i obsłużyłem zdarzenie VST OnBeforeCellPaint:

Kopiuj
 procedure TViewTransferFrm.VSTBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
           CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
 begin
   Data := Sender.GetNodeData(Node);
   case Data.NumerIkonki of
     0 : ImageList1.Draw(TargetCanvas, CellRect.Left + 39, CellRect.Top, 0);
     1 : ImageList1.Draw(TargetCanvas, CellRect.Left + 11, CellRect.Top, 1);
     2 : ImageList1.Draw(TargetCanvas, CellRect.Left + 24, CellRect.Top, 2);
   end;
 end;

i jak na razie wszystko działa bez problemu :)

edytowany 1x, ostatnio: Młody
U3
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad rok
  • Postów:196
0

Nie wiem dokładnie co chcesz uzyskać (przyznaję się, nie czytałem całości
No a szkoda, bo nie o to chodzi.
Chodzi o to, że w bazie mam pole BLOB, które zawiera ikonkę TIcon przypisaną do danej nody i teraz chcę tą ikonkę narysować obok Nody. Problem w tym, że Bezpośrednio po narysowaniu drzewa mam dostęp do ikonki i się wyświetla, natomiast po zastosowaniu w innych miejscach

Kopiuj
var
  Ikona: TIcon;
begin
Data := VST.GetNodeData(Node);
Ikona := Data.IkonaProcesu;
end;

Nie dostaję ikony, a rekord ma jakieś śmieciowe wartości.

flowCRANE
Nie do "danej nody", tylko "do danego noda" - lepiej po prostu pisać "do danego węzła", bo "node" to węzeł ;)
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)