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?
Author: Robert
Date: Sun, 10 Sep 2017 20:48
Date: Sun, 10 Sep 2017 20:48
299 lines
9669 bytes
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?
Author: konsul41
Date: Mon, 11 Sep 2017 07:17
Date: Mon, 11 Sep 2017 07:17
1 lines
993 bytes
993 bytes
Spakuj cały projekt i udostępnij do pobrania.
Re: Nie działa mi TImage tak jak powinien - moja indolencja z OOP?
Author: Robert
Date: Mon, 11 Sep 2017 08:20
Date: Mon, 11 Sep 2017 08:20
6 lines
1848 bytes
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?
Author: Roman Tyczka
Date: Mon, 11 Sep 2017 12:02
Date: Mon, 11 Sep 2017 12:02
45 lines
4256 bytes
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?
Author: officedrr
Date: Mon, 11 Sep 2017 12:59
Date: Mon, 11 Sep 2017 12:59
3 lines
2109 bytes
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?
Author: Roman Tyczka
Date: Mon, 11 Sep 2017 13:13
Date: Mon, 11 Sep 2017 13:13
12 lines
2093 bytes
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?
Author: officedrr
Date: Mon, 11 Sep 2017 14:00
Date: Mon, 11 Sep 2017 14:00
1 lines
2059 bytes
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