Witajcie,
Jak to zwykle bywa po skończeniu projektu i pokazaniu go użytkownikowi przypomniał on sobie, że chciałby zapamiętywanie ustawień grida (DBGrid). Wyjść jest kilka:
- stworzenie własnej klasy dziedziczącej po DBGrid - wymaga przerobienia wszystkich form - nie podoba mi się takie rozwiązanie
- pętla po wszystkich komponentach w poszukiwaniu klasy DBGrid i jakiś helper dla TDBGrid zapisujący ustawienia - też mi się nie podoba bo mało wydajne
- podmian adresów poszczególnych procedur klasy TDBGrid - a dokładnie construktora i np destruktora - tak to mi się podoba wybieramy bramkę nr 3.
Zapis do pliku poszedł bezproblemowo bo podmieniam adres destruktora klasy TDBGrid na adres destruktora klasy TMyDBGrid. Schody zaczęły się przy odczycie.
Ten sam myk na konstruktorze nie wypalił ponieważ konstruktor uruchamiany jest za wcześnie. Problem pojawił się przy nazwie pliku. Ponieważ niektóre dbgridy są na TFrame, niektóre są dynamiczne itd więc aby uniknąć przypisania ustawień z nieprawidłowego pliku do grida nazwa pliku ini (w którym się to trzyma) lub klucz w rejestrze (w zależności od tego co user sobie ustawi) składa się mniej więcej tak:
"NazwaFormy""NazwaFrame1""...."_"NazwaFrameN"_NazwaGrida
Sęk w tym, że w konstruktorze NAME poszczególnych elementów jest pusty (bo odczytanie przez VCL właściwości z DFM odbywa się później).
No i utknąłem. Zapis bomba odczyt ... zonk. Po kilku nieudanych próbach zrealizowałem to nadpisując konstruktor (i całą klasę) TDBGrid i podpinając pod to TMyDBGrid i dopisując mu własną metodę Paint.
type
TDBGridFix = class(TDBGrid)
strict private
FRead: boolean;
private
procedure Paint; override;
public
constructor NewCreate(AOwner: TComponent);
procedure ReadConfig;
end;
constructor TDBGridFix .NewCreate(AOwner: TComponent);
type
PClass = ^TClass;
begin
inherited Create(AOwner);
PClass(Self)^ := TDBGridFix;
FRead := True;
end;
procedure TDBGridFix.Paint;
begin
inherited Paint;
if not FRead then
exit;
ReadConfig;
FRead := False;
end;
Na aplikacji demo (1 formatka i 2 różne dbgridy) śmiga bez problemów. W aplikacji docelowej natomiast odczyt i uruchomienie odbywa się bez przeszkód ale przy zamykaniu aplikacji wywala mi AccessViolation (AV) na rtl.bpl.
Jak zrobiłem:
initialization
// InitTDBGridFix;
finalization
// FInitTDBGridFix;
to AV się nie pojawia ale również czytanie nie działa bo w powyższych funkcjach jest podmiana adresu konstruktora. Co ciekawe to destruktor zrobiony w tej sam sposób AV nie generuje.
Pytanie zatem moje jest następujące. Jak inaczej to zrealizować niezależnie od metody OnPaint. Chodzi mi o moment gdy z kodu ustawienia formy i wszystkich komponentów są zrealizowane, odczytany dfm i odpalony show/showmodal formy. W tym momencie odpala się OnPaint mojego grida ale chciałbym mieć zdarzenie OnShow tego grida.
PS.
TDBGrid podałem aby łatwiej wam było ogarnąć o co chodzi produkcyjnie jest to grid dziedziczący po TControl. Ma on co prawda (TControl)
procedure VisibleChanging; dynamic;
ale dla mojego komponentu TDBGrid odpala się dopiero gdy z kodu zrobię Visible := True/False, a mi chodzi o moment pierwszego wyświetlenia komponentu.