Dynamiczne podstawianie klas w Delphi 7.

Dynamiczne podstawianie klas w Delphi 7.
Thunderlane
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 10 lat
  • Postów:30
0

Tak się zastanawiałem, czy istnieje w Delphi możliwość wywołania pola/metody obiektu nieokreślonej klasy, a potem w innym miejscu w kodzie określenia jaka to klasa? Załóżmy, że mamy kilka podobnych klas wykonujących te same operacje ale każda eksportuje wyniki do pliku o innym rozszerzeniu. Teraz chcę napisać funkcję wykonującą kilka operacji wspólnych dla wszystkich tych klas, a następnie eksportującą wynik do pliku. Szkoda by było dla każdego rozszerzenia pisać osobne funkcje wykorzystujące w każdym przypadku te same pola/metody różnych klas, więc zastanawiałem się czy nie byłoby możliwe napisać jedną funkcję a później w zależności od wyboru użytkownika dynamicznie określić którą klasę wykorzystuje. Przykładowo, załóżmy że mamy dwa takie same pola w różnych klasach:

ExportToBMP.Filename
ExportToPNG.Filename

Czy dałoby radę napisać funkcję która wykorzystywałaby to pole w następujący sposób:

Kopiuj
procedure Exportuj;
begin
	// (...)
	temp.Filename = Edit1.Text;
	// (...)
end;

...a później gdzieś w kodzie obiekt temp zostałby ustalony jako instancja ExportToBMP, ExportToPNG etc. w zależności od np. wartości ComboBoxa? Takie coś bardzo by uprościło kod. Można tak w Delphi zrobić? Czy raczej trzeba będzie każdą funkcję pisać z osobna?

babubabu
  • Rejestracja:około 13 lat
  • Ostatnio:2 miesiące
  • Lokalizacja:Łódź
  • Postów:648
2

Jeśli klasy ExportToPNG i ExportToPNG dziedziczą po tej samej klasie bazowej np CustomExport gdzie znajduje się pole/właściwość FileName to to swoje temp zadeklaruj jako CustomExport a w parametrze przekazuj już obiekt właściwej klasy.

Tu miałem podobny problem (link do odpowiedzi):http://4programmers.net/Forum/1068614

edytowany 2x, ostatnio: babubabu
WL
Paskudne rozwiązanie...
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12165
1
Thunderlane napisał(a)

Tak się zastanawiałem, czy istnieje w Delphi możliwość wywołania pola/metody obiektu nieokreślonej klasy, a potem w innym miejscu w kodzie określenia jaka to klasa?

Nie, taka możliwość nie istnieje - zawsze musi być wiadomo z której klasy zostaje wywołana metoda;

Thunderlane napisał(a)

Załóżmy, że mamy kilka podobnych klas wykonujących te same operacje ale każda eksportuje wyniki do pliku o innym rozszerzeniu. Teraz chcę napisać funkcję wykonującą kilka operacji wspólnych dla wszystkich tych klas, a następnie eksportującą wynik do pliku.

W najlepszym wypadku wszystkie te klasy będą spokrewnione, o czym napisał poprzednik; Jeżeli wszystkie dziedziczą z tej samej klasy bazowej, to możesz korzystać ze wszystkiego, co posiada właśnie ta klasa bazowa (z wyjątkiem metod abstrakcyjnych oraz tych, które nie posiadają definicji, ale są zadeklarowane);

Przykładem jest korzystanie np. z bazowej klasy strumieni TStream; Jeżeli zadeklarujesz sobie w jakiejś metodzie parametr tej klasy, to możesz w nim przekazać referencję do instancji klasy TStream, TFileStream, TMemoryStream czy TStringStream, czyli wszystkich klasy dziedziczących z TStream oraz nią samą; Ale to nie zmienia faktu, że cokolwiek by się nie przekazało w parametrze - dostęp będzie jedynie do składowych klasy TStream; Podobnie będzie w Twoim przypadku - będziesz mógł skorzystać jedynie ze składowych klasy bazowej, o ile taka istnieje;

Wymyślony przykład z dziedziczeniem klas do obsługi zapisu plików bmp i svg, dziedziczących z jednej klasy bazowej;

Kopiuj
type
  TPictureObject = class(TObject)
  public
    procedure SaveToFile(AFileName: TFileName); virtual;
  end;

  procedure TPictureObject.SaveToFile(AFileName: TFileName);
  begin
    raise Exception.Create('cannot save picture to file in base class');
  end;

type
  TBitmapObject = class(TPictureObject)
  public
    procedure SaveToFile(AFileName: TFileName); override;
  end;

  procedure TBitmapObject.SaveToFile(AFileName: TFileName);
  begin
    WriteLn('saving to BMP file: ', AFileName);
  end;

type
  TSVGObject = class(TPictureObject)
  public
    procedure SaveToFile(AFileName: TFileName); override;
  end;

  procedure TSVGObject.SaveToFile(AFileName: TFileName);
  begin
    WriteLn('saving to SVG file: ', AFileName);
  end;

  procedure SavePictureToFile(APicture: TPictureObject; AFileName: TFileName);
  begin
    APicture.SaveToFile(AFileName);
  end;

var
  bmpObject: TBitmapObject;
  svgObject: TSVGObject;
begin
  bmpObject := TBitmapObject.Create();
  svgObject := TSVGObject.Create();
  try
    SavePictureToFile(bmpObject, 'C:\Picture.bmp');
    SavePictureToFile(svgObject, 'C:\Picture.svg');
  finally
    bmpObject.Free();
    svgObject.Free();
  end;
end.

Na wyjściu otrzymamy:

Kopiuj
saving to BMP file: C:\Picture.bmp
saving to SVG file: C:\Picture.svg

A teraz przykład z brakiem powiązania pomiędzy tymi klasami:

Kopiuj
type
  TBitmapObject = class(TObject)
  public
    procedure SaveToFile(AFileName: TFileName);
  end;

  procedure TBitmapObject.SaveToFile(AFileName: TFileName);
  begin
    WriteLn('saving to BMP file: ', AFileName);
  end;

type
  TSVGObject = class(TObject)
  public
    procedure SaveToFile(AFileName: TFileName);
  end;

  procedure TSVGObject.SaveToFile(AFileName: TFileName);
  begin
    WriteLn('saving to SVG file: ', AFileName);
  end;

  procedure SavePictureToFile(APicture: TObject; AFileName: TFileName);
  begin
    if APicture is TBitmapObject then
      TBitmapObject(APicture).SaveToFile(AFileName)
    else
      if APicture is TSVGObject then
        TSVGObject(APicture).SaveToFile(AFileName)
      else
        raise Exception.Create('unknown object to save to file');
  end;

var
  bmpObject: TBitmapObject;
  svgObject: TSVGObject;
begin
  bmpObject := TBitmapObject.Create();
  svgObject := TSVGObject.Create();
  try
    SavePictureToFile(bmpObject, 'C:\Picture.bmp');
    SavePictureToFile(svgObject, 'C:\Picture.svg');
  finally
    bmpObject.Free();
    svgObject.Free();
  end;
end.

Wyjście będzie dokładnie takie samo jak w poprzednim przkładnie, jednak procedura SavePictureToFile musi działać inaczej - sprawdzać co zostało przekazane w parametrze APicture i wykonać rzutowanie;

Sprawdź więc jak wygląda hierarchia Twoich dwóch klas i wybierz obpowiednią metodę ich obsługi.


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 4x, ostatnio: flowCRANE
WL
  • Rejestracja:około 21 lat
  • Ostatnio:około 2 miesiące
  • Postów:1082
1
furious programming napisał(a):
Thunderlane napisał(a)

Tak się zastanawiałem, czy istnieje w Delphi możliwość wywołania pola/metody obiektu nieokreślonej klasy, a potem w innym miejscu w kodzie określenia jaka to klasa?

Nie, taka możliwość nie istnieje - zawsze musi być wiadomo z której klasy zostaje wywołana metoda;

Po pierwsze istnieje tak możliwość i nazywamy to polimorfizmem.
Ba - możemy nawet wywołać dowolną metodę dowolnego obiektu za pomocą RTTI (ok, ale to nie w Delphi7) - wtedy nie musimy znać żadnego typu klasy, wystarczy sama wiedza o nazwie metody i referencja na obiekt.
Po drugie - po co mi konkretna klasa, skoro wystarczy mi sam adapter na metody? Implementacja takiego adaptera może być np. za pomocą klasy abstrakcyjnej lub za pomocą interfejsu implementowanego przez delegację (co polecam).
Tak czy siak oba rozwiązania eliminują to co napisałeś - powiązanie klas na etapie deklaracji, co jest zawsze dobrym pomysłem, ale ma jedną wadę - trzeba ciut więcej napisać kodu, a nie tylko go na chama spinać drutem.

Thunderlane napisał(a)

Załóżmy, że mamy kilka podobnych klas wykonujących te same operacje ale każda eksportuje wyniki do pliku o innym rozszerzeniu. Teraz chcę napisać funkcję wykonującą kilka operacji wspólnych dla wszystkich tych klas, a następnie eksportującą wynik do pliku.

W najlepszym wypadku wszystkie te klasy będą spokrewnione, o czym napisał poprzednik; Jeżeli wszystkie dziedziczą z tej samej klasy bazowej, to możesz korzystać ze wszystkiego, co posiada właśnie ta klasa bazowa (z wyjątkiem metod abstrakcyjnych oraz tych, które nie posiadają definicji, ale są zadeklarowane);

Ty chyba nie rozumiesz idei klas abstrakcyjnych, bo używa się ich w dokładnie odwrotnym celu!
Właśnie chodzi o to, że posługujemy się w kodzie typem klasy abstrakcyjnej i jej metodami - również abstrakcyjnymi.
Ale w czasie wykonania, należy dostarczyć obiekt klasy skonkretyzowanej, a nie abstrakcyjnej.
Efekt jest taki, że kod używający takiej klasy nie ma pojęcia i jej szczegółach implantacyjnych - i bardzo dobrze. ponieważ to pozwala łatwo rozszerzać taki kod o kolejne konkretne implementacje - np. obsługę dodatkowych typów plików graficznych.
Zresztą tak to jest zrealizowane w samym VCL przy obsłudze typów plików graficznych - polecam przejrzenie źródeł...
/ciach/

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

Ba - możemy nawet wywołać dowolną metodę dowolnego obiektu za pomocą RTTI (ok, ale to nie w Delphi7) - wtedy nie musimy znać żadnego typu klasy, wystarczy sama wiedza o nazwie metody i referencja na obiekt.

Nie sądzę, aby pytacz wiedział czym jest RTTI, umiał się tym posługiwać i było mu to potrzebne; Czasem sam korzystam z RTTI, tyle że w przypadku typów prostych, a nie klas; Ale Ok - napisać o tym nie zaszkodziło, ale nie przeze mnie - nigdy nie łączyłem RTTI z klasami, więc trudno abym coś o tym pisał;

Po drugie - po co mi konkretna klasa, skoro wystarczy mi sam adapter na metody? Implementacja takiego adaptera może być np. za pomocą klasy abstrakcyjnej lub za pomocą interfejsu implementowanego przez delegację (co polecam).

Owszem, pod warunkiem że pytacz dopiero stworzy takie klasy, a nie korzysta z już istniejących; Ale w sumie nic nie wiemy o tych jego klasach, więc nie ma co opisywać wszystkich możliwości, bo to nie artykuł;

Ty chyba nie rozumiesz idei klas abstrakcyjnych, bo używa się ich w dokładnie odwrotnym celu!

Moment, bo nie zrozumiałeś moich słów; To zdanie:

ja napisał(a)

Jeżeli wszystkie dziedziczą z tej samej klasy bazowej, to możesz korzystać ze wszystkiego, co posiada właśnie ta klasa bazowa (z wyjątkiem metod abstrakcyjnych oraz tych, które nie posiadają definicji, ale są zadeklarowane);

jest prawdziwe, bo nie można skorzystać z metod abstrakcyjnych - trzeba je dopiero przedefiniować; Wystarczyłoby w moim pierwszym przykładzie przerobić metodę TPictureObject.SaveToFile na abstrakcyjną i już nie można by z niej skorzystać, jeśli otrzymałoby się w parametrze obiekt tej klasy; Jeżeli podany byłby do procedury obiekt klasy TBitmapObject lub TSVGObject, to wszystko by działało prawidłowo, tak jak to wygląda właśnie w tym przykładzie;

W klasach bazowych używa się też metod nieabstrakcyjnych, ale pustych, bez kodu ich definicji - trudno więc z takich metod korzystać, bez ich przedefiniowania; To są jakieś marginalne przypadki, rzadko ale można i takie spotkać - np. TStrings.PutObject czy TStrings.SetCapacity, które co prawda są wirtualne i posiadają swoje definicje, ale puste; Rozumiem ideę klas abstrakcyjnych, korzystam z nich, a Ty po prostu nie zrozumiałeś moich słów;

Zresztą tak to jest zrealizowane w samym VCL przy obsłudze typów plików graficznych - polecam przejrzenie źródeł...

Nie mam możliwości przeglądnięcia źródeł VCL, bo nie posiadam wersji Enterprise.


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 10x, ostatnio: flowCRANE
WL
  • Rejestracja:około 21 lat
  • Ostatnio:około 2 miesiące
  • Postów:1082
0
furious programming napisał(a):

Ba - możemy nawet wywołać dowolną metodę dowolnego obiektu za pomocą RTTI (ok, ale to nie w Delphi7) - wtedy nie musimy znać żadnego typu klasy, wystarczy sama wiedza o nazwie metody i referencja na obiekt.

Nie sądzę, aby pytacz wiedział czym jest RTTI, umiał się tym posługiwać i było mu to potrzebne; Czasem sam korzystam z RTTI, tyle że w przypadku typów prostych, a nie klas; Ale Ok - napisać o tym nie zaszkodziło, ale nie przeze mnie - nigdy nie łączyłem RTTI z klasami, więc trudno abym coś o tym pisał;

Ja niczego nie zakładam, czy ktoś coś wie czy nie. Napisałem o możliwościach, a co kto z tym zrobi - to jego sprawa.

Po drugie - po co mi konkretna klasa, skoro wystarczy mi sam adapter na metody? Implementacja takiego adaptera może być np. za pomocą klasy abstrakcyjnej lub za pomocą interfejsu implementowanego przez delegację (co polecam).

Owszem, pod warunkiem że pytacz dopiero stworzy takie klasy, a nie korzysta z już istniejących; Ale w sumie nic nie wiemy o tych jego klasach, więc nie ma co opisywać wszystkich możliwości, bo to nie artykuł;

To nie jest konieczne, ale to naprawdę nie ten temat. Ale jak kogoś to naprawdę interesuje, to niech sobie sprawdzi np. jak we frameorku mORMomt zrealizowano implementację interfejsu serwera w kliencie - genialne!

Ty chyba nie rozumiesz idei klas abstrakcyjnych, bo używa się ich w dokładnie odwrotnym celu!

Moment, bo nie zrozumiałeś moich słów; To zdanie:

ja napisał(a)

Jeżeli wszystkie dziedziczą z tej samej klasy bazowej, to możesz korzystać ze wszystkiego, co posiada właśnie ta klasa bazowa (z wyjątkiem metod abstrakcyjnych oraz tych, które nie posiadają definicji, ale są zadeklarowane);

jest prawdziwe, bo nie można skorzystać z metod abstrakcyjnych - trzeba je dopiero przedefiniować; Wystarczyłoby w moim pierwszym przykładzie przerobić metodę TPictureObject.SaveToFile na abstrakcyjną i już nie można by z niej skorzystać, jeśli otrzymałoby się w parametrze obiekt tej klasy; Jeżeli podany byłby do procedury obiekt klasy TBitmapObject lub TSVGObject, to wszystko by działało prawidłowo, tak jak to wygląda właśnie w tym przykładzie;

Naprawdę, czytaj uważnie wypowiedzi innych - szkoda mi czasu na tłumaczenie że mówimy to samo używając innych pojęć.
I tak - klasy abstrakcyjnej się nie przedefiniuje, tylko konkretyzuje.
Metody pustej też się nie "przedefiniuje" (bo jej definicja jest identyczna, ale implementacja już nie), tylko nadpisuje lub przesłania (override).
OK, zostawmy tę semantykę.

W klasach bazowych używa się też metod nieabstrakcyjnych, ale pustych, bez kodu ich definicji - trudno więc z takich metod korzystać, bez ich przedefiniowania;

Nadpisania ;-)

To są jakieś marginalne przypadki, rzadko ale można i takie spotkać - np. TStrings.PutObject czy TStrings.SetCapacity, które co prawda są wirtualne i posiadają swoje definicje, ale puste;

OK, ale wiesz dlaczego są zadeklarowane (i zaimplmentowane) jako puste i wirtualne, a nie abstrakcyjne i wirtualne?

Rozumiem ideę klas abstrakcyjnych, korzystam z nich, a Ty po prostu nie zrozumiałeś moich słów;

Nie, ja się po prostu czepiłem Twojej nieprecyzyjnej wypowiedzi.

Zresztą tak to jest zrealizowane w samym VCL przy obsłudze typów plików graficznych - polecam przejrzenie źródeł...

Nie mam możliwości przeglądnięcia źródeł VCL, bo nie posiadam wersji Enterprise.

No popatrz, a ja to widzę w wersji Pro.

edytowany 2x, ostatnio: flowCRANE
flowCRANE
Popsuły Ci się znaczniki <quote>
WL
True, jak już pisałem kiedyś do Ciebie - to jest za skomplikowane przy wielokrotnym cytowaniu. A przynajmniej dla mnie za skomplikowane...
flowCRANE
No dobrze - poprawię więc za Ciebie;
flowCRANE
Powinno już być dobrze - ewentualnie wołaj, to jeszcze się poprawi;
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12165
0

Naprawdę, czytaj uważnie wypowiedzi innych - szkoda mi czasu na tłumaczenie że mówimy to samo używając innych pojęć.
I tak - klasy abstrakcyjnej się nie przedefiniuje, tylko konkretyzuje.

No właśnie - czytaj uważnie wypowiedzi innych; Ja napisałem o metodzie abstrakcyjnej, a Ty komentujesz moje słowa pisząc o klasach abstrakcyjnych;

OK, zostawmy tę semantykę.

Zostawmy, bo nadpisywanie i przedefiniowywanie oznacza to samo; Przynajmniej w materiałach z których się uczyłem programowania w Delphi; Ale niech będzie, że nadpisywanie - to w sumie tłumaczenie słowa Override;

OK, ale wiesz dlaczego są zadeklarowane (i zaimplmentowane) jako puste i wirtualne, a nie abstrakcyjne i wirtualne?

Nie zastanawiałem się nad tym, ale mile widziane wytłumaczenie;

Nie, ja się po prostu czepiłem Twojej nieprecyzyjnej wypowiedzi.

Skup się raczej na pomocy pytaczom, a nie czepianiu się wypowiedzi odpowiadających;

No popatrz, a ja to widzę w wersji Pro.

No popatrz, a ja nie widzę tego w wersji Personal; Nie mam źródeł i już, więc obojętne jaką bym wersję ze źródłami nie podał, to i tak takiej nie posiadam.


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
WL
  • Rejestracja:około 21 lat
  • Ostatnio:około 2 miesiące
  • Postów:1082
0
furious programming napisał(a):

Naprawdę, czytaj uważnie wypowiedzi innych - szkoda mi czasu na tłumaczenie że mówimy to samo używając innych pojęć.
I tak - klasy abstrakcyjnej się nie przedefiniuje, tylko konkretyzuje.

No właśnie - czytaj uważnie wypowiedzi innych; Ja napisałem o metodzie abstrakcyjnej, a Ty komentujesz moje słowa pisząc o klasach abstrakcyjnych;

Zgoda, trafiony.

OK, zostawmy tę semantykę.

Zostawmy, bo nadpisywanie i przedefiniowywanie oznacza to samo; Przynajmniej w materiałach z których się uczyłem programowania w Delphi; Ale niech będzie, że nadpisywanie - to w sumie tłumaczenie słowa Override;

A co to za materiały, jeśli można wiedzieć? Bo jeśli to dostępne tu poradniki i książka założyciela portalu, to... są zdecydowanie lepsze, a na pewno bardziej aktualne, źródła ;-)
Zapytam inaczej - książkę Nicka Hodegesa "Coding in Delphi" ktoś czytał?

OK, ale wiesz dlaczego są zadeklarowane (i zaimplmentowane) jako puste i wirtualne, a nie abstrakcyjne i wirtualne?

Nie zastanawiałem się nad tym, ale mile widziane wytłumaczenie;

Żeby to zrozumieć, to trzeba podać rozbudowany przykład, z którego i tak 3/5 nic nie zrozumie, bo nie ma tam komponentów do klikania...
Nie chce mi się.
Natomiast kuriozalne jest to, że wyjaśniasz cokolwiek ale sam nie wiesz po co tak i dlaczego tak.
Ale żeby nie było, to jednym zdaniem; po to, aby zachować ciągłość logiki w danej klasie, czyli wywołać konkretną metodę (nawet abstrakcyjną), która jest konkretyzowana w klasach potomnych.
I np. dlatego RTL posługuje się często klasą TStrings, która jest konkretyzowana przez TStringList - bezpośrednie utworzenie obiektu klasy TStrings skończyłoby się wyjątkiem.

Nie, ja się po prostu czepiłem Twojej nieprecyzyjnej wypowiedzi.

Skup się raczej na pomocy pytaczom, a nie czepianiu się wypowiedzi odpowiadających;

Nawet jeśli odpowiedzi odpowiadających są od czapy?
Odpowiem za Ciebie - oczywiście że tak!
A przynajmniej ja to tak rozumiem, co zabija wszelką dyskusję, która mogłaby się ciekawie rozwinąć.

No popatrz, a ja to widzę w wersji Pro.

No popatrz, a ja nie widzę tego w wersji Personal; Nie mam źródeł i już, więc obojętne jaką bym wersję ze źródłami nie podał, to i tak takiej nie posiadam.

To po kiego grzyba pisałeś o Enterpirse? ;-)

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

Tak, to te materiały, ale skoro uważasz je za słabe - popraw je, każdy zarejestrowany użytkownik może to zrobić; Co do przykładu - nie to nie, skoro Ci "się nie chce"... Jeśli chodzi o źródła - mam wersję Personal bez źródeł - zadowolony? Czy jeszcze dokładniej wyjaśnić, aby nie dawać Ci kolejnego powodu do czepiania się?


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
WL
  • Rejestracja:około 21 lat
  • Ostatnio:około 2 miesiące
  • Postów:1082
0
furious programming napisał(a):

Tak, to te materiały, ale skoro uważasz je za słabe - popraw je, każdy zarejestrowany użytkownik może to zrobić;

To że mogę, nie znaczy że chcę, czytaj: nie mam tyle czasu.
I tak - są słabe. Nie tyle błędne, bo przecież działają, ale niektóre patenty są... kuriozalne.

Dam przykład, "Rozdział 17. Bazy danych dbExpress".
Autor całkowicie pominął obsługę parametrów (sparametryzowanych zapytań) i z uporem maniaka wszędzie skleja stringi.
To jest ZŁE! Jest nieoptymalne (brak preparacji zapytań), pozwala na SQLInjection (wszystko leci jako string) itd.

Ładowanie danych do ListView będzie działać poprawnie, pod warunkiem że w tej przykładowej bazie danych nie będzie wartości null. Tylko widzisz, autor na etapie deklaracji tabeli towary nie dopuszcza wartości null dla żadnego pola (ale nie ma ani słowa o tym dlaczego tak), taki sprytny zabieg ;-) Ale gdyby null pojawił się chociaż raz i aplikacja pada na twarz.

Samo ładowanie jest absolutnie nieoptymalne (brak begin/end update dla ListView - załaduj tam 1000 rekordów to sam zobaczysz o czym mowa) i błędne, ponieważ opiera się na pętli for i odczytuje RecordCount, który dla baz SQL (a tylko z takimi dbExpress działa) nie zwraca poprawnej wartości; czasem może być tam i -1 - i co taki biedny newbie ma z tym zrobić?

Za coś takiego powinno się lać linijką po łapach.
Rozumiem, że to jest przykład - ale ten przykład uczy złych nawyków i nie tłumaczy dobrych.

Itd. itp.

Co do przykładu - nie to nie, skoro Ci "się nie chce"... Jeśli chodzi o źródła - mam wersję Personal bez źródeł - zadowolony? Czy jeszcze dokładniej wyjaśnić, aby nie dawać Ci kolejnego powodu do czepiania się?

Nie wiem, zobaczymy ;-)

0

A jak inaczej iterować jak nie w pętli z użyciem RecordCount, pytam z ciekawości :)?

flowCRANE
Obawiam się, że w tym wątku raczej nie powinno się tego poruszać - pytanie jest zupełnie inne; Załóż nowy wątek w odpowiednim dziale i tam pytaj, żeby tutaj nie ciągnąć OT;
WL
while not DataSet.Eof do DataSet.Next;
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)