Czy istnieje zdarzenie pomiędzy konstruktorem a Paint?

0

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.

0

W onPaint chcesz wczytywać ustawienia Grida? Jeśli tak to robisz to po dziadowsku.
Są Gridy któe potrafią zapisać konfigurację np XDBGrid.
Ja osobiście używam swojego zapisu konfiguracji (widoczność i szerokość kolumn do pliku) - obiektowo.
Podsumowując rozumiem, że być może Klient coś sobie zażyczył i nie zapłaci za to, ale drutówki bym nie robił, żeby 'tylko było'. Przemyśl sprawę.

0

Twój post uważam, ża totalnie bez sensu. Po pierwsze grid, którego używam, również ma możliwość zapisu dlatego procedura ReadConfig odpala wbudowaną metodę grida. Co do do reszty to tak jak pisałem nie ma opcji abym przerabiał całą aplikację. Co do rzeczy biznesowych to już inna kwestia. Nie chcę tego robić na OnPaint ale innego wyjścia nie widzę.

PS. 2

Póki co zrobiłem to na zdarzeniu OnResize (bo w aplikacji Grid zawsze leży na TFrame lub TForm i na nich jest zdarzenie onResize oprogramowanie - jak już - i na samym Grid nigdzie nie ma zdarzenia onResize):

type
  TDBGridFix = class(TDBGrid)
  public
    constructor NewCreate(AOwner: TComponent);
    procedure NewResize(Sender: TOBject);
    procedure ReadConfig;
  end;

constructor TDBGridFix .NewCreate(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Self.OnResize := NewResize;
end;

procedure TDBGridFix.ReadConfig;
begin
  //tutaj jest odczyt danych a potem:
   Self.OnResize := nil;
end;

póki co temat rozwiązałem ale pytanie czy macie inne pomysły?

AV powodował ten zapis: PClass(Self)^ := TDBGridFix;

0

Ja jakoś nie rozumiem, do czego dążysz (taki inaczej myślący jestem chyba), ale może to Cię zainteresuje

 unit DBGridFix;

interface

uses
  SysUtils, Classes, Controls, Grids, DBGrids;

type
  TDBGridFix = class(TDBGrid)
  strict private
    FRead: boolean;
  private
    procedure Paint; override;
  protected
    procedure ReadState(Reader: TReader); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure ReadConfig;
  end;

implementation

{ TDBGridFix }

constructor TDBGridFix.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FRead := True;
end;

procedure TDBGridFix.Paint;
begin
// zmień sobie, jeśli potrzebujesz
  inherited Paint;
end;

procedure TDBGridFix.ReadConfig;
begin
  // to, co chcesz
end;

procedure TDBGridFix.ReadState(Reader: TReader);
begin
  inherited ReadState(Reader);
  // skoro już odczytaliśmy z dfm'a, to:
  ReadConfig;
  FRead := false;
end;

end.
2

Ja to bym jakoś tak kombinował:

type
  TDBGrid = class(DbGrids.TDBGrid) //nadpisac klase dla wszyskich DBGrid
  private
    fSettingsReaded: Boolean;
    procedure WMNCCalcSize(var Msg: TMessage); message WM_NCCALCSIZE;
    procedure SaveConfig;
    procedure ReadConfig;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

//...

procedure TDBGrid.WMNCCalcSize(var Msg: TMessage);
begin
  inherited;
  if not fSettingsReaded then
  begin
    //jezeli tu wywolasz odczyt to o ktory DBGrid chodzi możesz rozpoznac nawet po name
    ReadConfig;
    fSettingsReaded:= True;
  end;
end;

procedure TDBGrid.SaveConfig;
begin
  //kod zapisu ustawien
end;

procedure TDBGrid.ReadConfig;
begin
  //kod odczytu
end;

constructor TDBGrid.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fSettingsReaded:= False;
  //jezeli tu wywolasz odczyt to o ktory DBGrid chodzi możesz rozpoznac np. ustawiajac Tag i po tej wlasciwosci (name w konstruktorze jest niedostepne)
  //ReadConfig;
end;

destructor TDBGrid.Destroy;
begin
  SaveConfig;
  inherited;
end;
0

@kAzek ja właśnie o czymś takim myślałem ale pytanie mam jak się dostać do "jakiegoś" zdarzenia (innego niż RESIZE) po CREATE ale przed ONPaint.

0

Mo przecież podałem w przykładzie obsługę komunikatu WMNCCalcSize który jest przed OnPaint dlaczego to nie może być?

0

@kAzek masz rację, źle przeczytałem WM... dzięki za pomoc.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.