🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.delphi
7 messages
7 total messages Started by Robert Sun, 10 Sep 2017 20:48
Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346044
Author: Robert
Date: Sun, 10 Sep 2017 20:48
299 lines
9669 bytes
Witam Szanownych. 
To mój pierwszy raz tutaj a z Delphi (XE) zaczynam przygodę i mam problem chyba związany z nieznajomością OOP bo nie wierzę, że komponent TImage jest wadliwy.
Tak więc z góry przepraszam za trywialne pytanie ale walczę z problemem już na tyle długo, że musiałem sięgnąć po pomoc. 

Poniżej zamieściłem obcięte do minimum dwa moduły, z których wyrzuciłem wszystko co niezbędne i zostawiłem sama obsługę tworzenia obiektów i inicjacji obrazka. Funkcją tych modułów jest odczytanie i wyświetlenie danych z pliku w komponencie TVirtualStringTree. Z pliku odczytuję również pliki .jpg, które chcę wyświetlić w TImage w zależności od tego którą nodę kliknie się w Tree. 
Odczyt i prezentacja danych tekstowych przebiegają właściwe. Problemem jest pokazanie tych obrazków. Gdy tworzę i inicjuję obiekt TFilm, to tworzę również pole fPoster do którego chcę na starcie wczytać plik, nazwijmy go - początkowy. Później w trakcie czytania danych z pliku obrazek początkowy zastępowany jest tym odczytanym z pliku i ten drugi ma być prezentowany w TImage. Niestety, drugi obrazek jest pokazywany tylko wtedy, gdy przy tworzeniu obiektu TFilm NIE przypiszę nic do pola fPoster. Gdy dokonam przypisania to widoczny jest wyłącznie ten pierwszy obrazek.

Jestem pewien, że czytam obrazki z pliku w sposób właściwy. Gdy w vsTreeNodeClick dla testu zapisuję obrazek do pliku to pojawia się ten właściwy: (Filmy.FilmInd[Data.NrF].Poster.SaveToFile();)
Co więcej, gdy w tej samej procedurze zapisuję do pliku zawartość ImgPoster.Picture. to również zapisuje się właściwy obraz, lecz równocześnie na formie wyświetlany jest zły. Gdzie się przewróciłem? Proszę o pomoc.


type
  TRekordNody = record
                  NrF:         Integer;
                  R:           RFilm;
                  Wartosc:     AnsiString;
                  Zmieniony:   Boolean;
                end;

  PRekordNody = ^TRekordNody;


  TForm1 = class(TForm)
    vsTree: TVirtualStringTree;
    PopM: TPopupMenu;
    OpenD: TOpenDialog;
    ImgPoster: TImage;
    PMczytaj1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure PMCzytajClick(Sender: TObject);
    procedure vsTreeInitNode(Sender: TBaseVirtualTree; ParentNode,
      Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure vsTreeNodeClick(Sender: TBaseVirtualTree;
      const HitInfo: THitInfo);
  private
    { Private declarations }
  public
    { Public declarations }
    Filmy :TFilmy;
  end;

var
  Form1: TForm1;

implementation
uses EdytorVSTree;
{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Filmy.Destroy;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  try
    Filmy := TFilmy.Create;
  finally
    vsTree.RootNodeCount := Filmy.LiczbaFilmow;
    vsTree.NodeDataSize  := SizeOf(TRekordNody);
  end; {of finally}
end;

procedure TForm1.PMCzytajClick(Sender: TObject);
begin
 if OpenD.Execute = True then
   begin
     Filmy.Czytaj(OpenD.FileName);

     vsTree.RootNodeCount := Filmy.LiczbaFilmow;
     vsTree.NodeDataSize  := SizeOf(TRekordNody);
   end;
end;

procedure TForm1.vsTreeInitNode(Sender: TBaseVirtualTree; ParentNode,
  Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var Data :PRekordNody;
    i :Integer;
begin
  with Sender do begin
    Data := GetNodeData(Node);
    i := Node.Index+1;
    Data.R := Filmy.FilmInd[i].KompletneInfo;
    Data.NrF := i;
  end;
end;

procedure TForm1.vsTreeNodeClick(Sender: TBaseVirtualTree;
  const HitInfo: THitInfo);
var hit :THitInfo;
    P   :TPoint;
    Data:PRekordNody;
begin
 with Sender do
  begin
   P := ScreenToClient(Mouse.CursorPos);
   GetHitTestInfoAt(P.X, P.Y,True,hit);

   Data := GetNodeData(hit.HitNode);

{!!!!!!!!!!!!!!!!!!!!!!!}
{!!!!!!!!!!!!!!!!!!!!!!!}
{ TU POWINIEN WYŚWIETLIĆ ZAWARTOŚĆ A POKAZUJE CO INNEGO }
   ImgPoster.Picture.Assign(Filmy.FilmInd[Data.NrF].Poster);

  end;
end;



type
Gatunki = (___,akcja,biograficzny,czarna_komedia,dramat,familijny,fantasy,horror,komedia,na_faktach,metafizyka,obyczajowy,paradokument,przygodowy,sci_fi,społeczny,thriller,wojenny);

RFilm = record
   Poster    : TJPEGImage;
 end;

TFilm = class(TObject)
 private
   fPoster    : TJPEGImage;

   function  GetPoster: TJPEGImage;
   procedure SetPoster(const Value: TJPEGImage);
   function  GetDane: RFilm;
   procedure SetDane(const Value: RFilm);

 public
   constructor Create;
   destructor Destroy; override;

   property Poster   :TJPEGImage read GetPoster   write SetPoster;
   property KompletneInfo :RFilm read GetDane     write SetDane;

 end;

 TFlmArr = array of TFilm;  {tablica z obiektami opisu filmów}
 TIntArr = array of Integer;

 TFilmy = class(TObject)  {klasa obsługi katalogu filmów}
  private
    fTbFlm :TFlmArr;
    function  GetFilmInd(ind: Integer): TFilm;
    procedure SetFilmInd(ind: Integer; const Value: TFilm);
  public
   constructor Create;
   destructor  Destroy; override;
   procedure CzyscWszystko;
   procedure DodajNowy;
   procedure Czytaj(FileName:String);
   function LiczbaFilmow: Integer;

   property FilmInd[ind:Integer] :TFilm  read GetFilmInd write SetFilmInd;
  end;



implementation
uses BazaFilmowGlowny;
{TFilm}

constructor TFilm.Create;
var tmpBt :TBitmap;
begin
  try
    inherited;
    fPoster   := TJPEGImage.Create;

    tmpBt := TBitmap.Create;
    tmpBt.LoadFromResourceName(HInstance, 'PustyPoster');

{!!!!!!!!!!!!!!!!!!!}
{!!!!!!!!!!!!!!!!!!!}
{Gdy linia poniżej jest odkomentowana to pojawia się opisany problem}
{!!!!!!!!!!!!!!!!!!!}
  //  fPoster.Assign(tmpBt); 

  finally
    tmpBt.Free;
  end;
end;

destructor TFilm.Destroy;
begin
  fPoster.Free;
  inherited Destroy;
end;

function  TFilm.GetPoster: TJPEGImage;
begin
  Result := fPoster;
end;

procedure TFilm.SetPoster(const Value: TJPEGImage);
begin
  if Value <> fPoster then fPoster.Assign(Value);
end;

function  TFilm.GetDane: RFilm;
begin
  Result.Poster   := Poster;
end;

procedure TFilm.SetDane(const Value: RFilm);
begin
  if Value.Poster <> Poster then Poster.Assign(Value.Poster);
end;

{------------------------------------------------------------------------------}
{------------------------------------------------------------------------------}
{------------------------------------------------------------------------------}
{ TFilmy }

constructor TFilmy.Create;
begin
  inherited Create;
  SetLength(fTbFlm,1);
  fTbFlm[0] := TFilm.Create;
 end;

destructor TFilmy.Destroy;
var i:Integer;
begin
  for i := High(fTbFlm) downto 0 do
    fTbFlm[i].Free;

  SetLength(fTbFlm,0);
  inherited Destroy;
end;

procedure TFilmy.CzyscWszystko;
var i:Integer;
begin
  for i := High(fTbFlm) downto 0 do
    fTbFlm[i].Free;

  SetLength(fTbFlm,1);
  fTbFlm[0] := TFilm.Create;
end;


procedure TFilmy.DodajNowy;
begin
  SetLength(fTbFlm, Length(fTbFlm)+1);
  fTbFlm[High(fTbFlm)] := TFilm.Create;
end;

function TFilmy.LiczbaFilmow: Integer;
begin
  Result := High(fTbFlm);
end;

function TFilmy.GetFilmInd(ind: Integer): TFilm;
begin
  Result := fTbFlm[ind]
end;

procedure TFilmy.SetFilmInd(ind: Integer; const Value: TFilm);
begin
  fTbFlm[ind] := Value;
end;

procedure TFilmy.Czytaj(FileName: String);
var FS :TFileStream;
    MS :TMemoryStream;
    i, tmpI, LiczFilmy :Integer;
    D :TFilm;

begin
  try
    FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    MS := TMemoryStream.Create;

    CzyscWszystko;
    D := TFilm.Create;

    FS.ReadBuffer(LiczFilmy, SizeOf(LiczFilmy));

    for i := 1 to LiczFilmy do
      begin
        {tu czytam cały rekord i przepisuję dane do obiektu D}

        DodajNowy;

        FS.ReadBuffer(tmpI, SizeOf(tmpI));
        MS.CopyFrom(FS,tmpI);
        MS.Position := 0;
        D.Poster.LoadFromStream(MS);
        MS.Clear ;

        FilmInd[i].KompletneInfo := D.KompletneInfo;
      end;

  finally
    D.Free;
    FS.Free;
    MS.Free;
  end;
end;
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346045
Author: konsul41
Date: Mon, 11 Sep 2017 07:17
1 lines
993 bytes
Spakuj cały projekt i udostępnij do pobrania.
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346046
Author: Robert
Date: Mon, 11 Sep 2017 08:20
6 lines
1848 bytes
Projekt pod Delphi XE do pobrania spod adresu: https://drive.google.com/file/d/0B9Ezx1U_zNBUQmQ4NWdTVDdoRU0/view?usp=sharing

Jest tam również testowy plik z danymi, który zawiera pięć rekordów z tekstem i obrazkami. Obrazki są dwa różne, przeplatane co drugi. 
Aby wczytać plik trzeba prawoklikiem na Tree wywołać PopUpa a dalej już będzie jasne. 

Dziękuję za zainteresowanie
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346047
Author: Roman Tyczka
Date: Mon, 11 Sep 2017 12:02
45 lines
4256 bytes
On Sun, 10 Sep 2017 13:48:30 -0700 (PDT), Robert wrote:

> Witam Szanownych. 
> To mój pierwszy raz tutaj a z Delphi (XE) zaczynam przygodę i mam problem chyba związany z nieznajomością OOP bo nie wierzę, że komponent TImage jest wadliwy.
> Tak więc z góry przepraszam za trywialne pytanie ale walczę z problemem już na tyle długo, że musiałem sięgnąć po pomoc. 
> 
> Poniżej zamieściłem obcięte do minimum dwa moduły, z których wyrzuciłem wszystko co niezbędne i zostawiłem sama obsługę tworzenia obiektów i inicjacji obrazka. Funkcją tych modułów jest odczytanie i wyświetlenie danych z pliku w komponencie TVirtualStringTree. Z pliku odczytuję również pliki .jpg, które chcę wyświetlić w TImage w zależności od tego którą nodę kliknie się w Tree. 
> Odczyt i prezentacja danych tekstowych przebiegają właściwe. Problemem jest pokazanie tych obrazków. Gdy tworzę i inicjuję obiekt TFilm, to tworzę również pole fPoster do którego chcę na starcie wczytać plik, nazwijmy go - początkowy. Później w trakcie czytania danych z pliku obrazek początkowy zastępowany jest tym odczytanym z pliku i ten drugi ma być prezentowany w TImage. Niestety, drugi obrazek jest pokazywany tylko wtedy, gdy przy tworzeniu obiektu TFilm NIE przypiszę nic do pola fPoster. Gdy dokonam przypisania to widoczny jest wyłącznie ten pierwszy obrazek.
> 
> Jestem pewien, że czytam obrazki z pliku w sposób właściwy. Gdy w vsTreeNodeClick dla testu zapisuję obrazek do pliku to pojawia się ten właściwy: (Filmy.FilmInd[Data.NrF].Poster.SaveToFile();)
> Co więcej, gdy w tej samej procedurze zapisuję do pliku zawartość ImgPoster.Picture. to również zapisuje się właściwy obraz, lecz równocześnie na formie wyświetlany jest zły. Gdzie się przewróciłem? Proszę o pomoc.

Czytałem trzy razy i nie do końca potrafię wyczytać w czym masz problem.
Otworzyłem aplikację w Berlinie, usunąłem błędy kompilacji, odpaliłem i po
usunięciu jeszcze AV, bo dziwnie jakoś naokoło pobierałeś klikniętego noda
zamiast po prostu:

procedure TForm1.vsTreeNodeClick(Sender: TBaseVirtualTree; const HitInfo:
THitInfo);
var
    Data:PRekordNody;
begin
 with Sender do
  begin
   Data := GetNodeData(HitInfo.HitNode);
   ImgPoster.Picture.Assign(Filmy.FilmInd[Data.NrF].Poster);
  end;
end;

...aplikacja zadziałała tak, że tree jest po wczytaniu pliku puste (brak
jakichkolwiek tekstów) ale ma 5 wierszy i gdy po nich klikam to na przemian
w TImage pokazują się dwa obrazki.
Czy tak miało być czy inaczej?

Mam za to uwagi następujące. Nie polecam używać w takim wypadku rekordów,
bo rekord przy przypisaniu jest kopiowany, przez co trudno jest przenosić
nim dane w te i z powrotem. Używaj obiektów, a najlepiej interfejsów, bo w
kodzie masz możliwość pobrania kompletnego info o filmie i interfejs byłby
tu idealny, gdyż po pierwsze nie musisz się martwić o odpowiedzialność za
zwalnianie, po drugie możesz mieć kilka interfejsów do tego samego obiektu
i jeden z nich może być read only.

-- 
pozdrawiam
Roman Tyczka
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346048
Author: officedrr
Date: Mon, 11 Sep 2017 12:59
3 lines
2109 bytes
Spójrz, proszę na konstruktor TFilm. Jest tam zakomentowania linia 
// fPoster.Assign(tmpBt);
która winna odpowiadać za przypisanie obrazka "startowego" typu "nic-tu-jeszcze-nie-ma". Gdy użytkownik czyta dane z pliku, to w to miejsce doczytywany jest właściwy obrazek. Jeśli usunę tą linię z konstruktora to wszystko działa tak jak piszesz ale nie mam w pełni zainicjowanego obiektu. Jeśli jednak w konstruktorze przypiszę do fPoster jakiś obrazek to już po kliknięciu na dowolny wiersz w Tree nie zmieniają się obrazki tak jak wcześniej. Tu mam problem. Powinienem w pełni utworzyć obiekt ale wtedy nie działa. Gdy obiektu nie stworzę tak jak chcę - to działa.
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346050
Author: Roman Tyczka
Date: Mon, 11 Sep 2017 13:13
12 lines
2093 bytes
On Mon, 11 Sep 2017 05:59:29 -0700 (PDT), officedrr@gmail.com wrote:

> Spójrz, proszę na konstruktor TFilm. Jest tam zakomentowania linia 
> // fPoster.Assign(tmpBt);
> która winna odpowiadać za przypisanie obrazka "startowego" typu "nic-tu-jeszcze-nie-ma". Gdy użytkownik czyta dane z pliku, to w to miejsce doczytywany jest właściwy obrazek. Jeśli usunę tą linię z konstruktora to wszystko działa tak jak piszesz ale nie mam w pełni zainicjowanego obiektu. Jeśli jednak w konstruktorze przypiszę do fPoster jakiś obrazek to już po kliknięciu na dowolny wiersz w Tree nie zmieniają się obrazki tak jak wcześniej. Tu mam problem. Powinienem w pełni utworzyć obiekt ale wtedy nie działa. Gdy obiektu nie stworzę tak jak chcę - to działa.

Po odkomentowaniu tej linii wszystko dzsiała tak samo, w co drugim wierszu
są te same obrazki.

-- 
pozdrawiam
Roman Tyczka
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
#346051
Author: officedrr
Date: Mon, 11 Sep 2017 14:00
1 lines
2059 bytes
Szukałem rozwiązania dookoła i zauważyłem, że błędne działanie jest wtedy gdy w konstruktorze czytam bitmapę z zasobów a później przypisuję ją do fPoster, który jest typu TJPEGImage. Zakładałem, że konwersja z bitmapy na jpg przebiega prawidłowo bo w innej części kodu tak się dzieje. Gdy dla testu zamiast bitmapy z zasobów wczytałem jpg z pliku to problem zniknął... Trudno, nie wiem gdzie leży problem, wiem jak go obejść. Tyle musi mi wystarczyć. I dziękuję za wskazówki jak poprawić kod na bardziej pro :)
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads