
Internal types and scoping
The code below shows something that is a bit of a mystery to me.
TQuerySetToGrid = class(TQuerySet); // simplified
TQuerySetXML = class(TQuerySetToGrid)
public
Id: TQuerySet.TFieldInteger;
TimeStamp: TQuerySet.TFieldDateTime;
PID: TQuerySet.TFieldInteger;
TID: TQuerySet.TFieldInteger;
Level: TQuerySet.TFieldEnum;
Category: TQuerySet.TFieldEnum;
App: TQuerySet.TFieldString;
Client: TQuerySet.TFieldString;
Title: TQuerySet.TFieldString;
constructor Create; override;
end;
Apart from “it works that way” – is there a reasonable explanation of why I have to qualify the TFieldxxxx types which all are public types declared inside TQuerySet, when referring the types inside a descendant class? I wonder!
/off-topic
FYI, this is actual code and part of a log viewer in our monitoring and maintenance tool, and to give you an idea of what I am trying to achieve…
This is the scaffolding code needed for link a grid and a query to display the results from a TDataSet.
Initialize and set up the look of the grid:
XMLQueryLog := TQuerySetXML.Create;
XMLQueryLog.Grid := sgLog;
sgLog is a TAdvStringGrid dropped on a frame, and there is some grid specific code to get the desired look, and ofcourse code to handle grid operations – but for the content, this is the only scaffolding needed.
Execute the query and fill the grid:
XMLQueryLog.Refresh(SQLStatement);
The “real” scaffolding happens in that Create you saw in the initial class.
constructor TQuerySetXML.Create;
begin
inherited;
Id := Add(‘Id’, 64);
TimeStamp := Add(‘TimeStamp’, ‘Dato og tid’, 120);
PID := Add(‘ProcessId’, ‘PID’, 64);
TID := Add(‘ThreadId’, ‘TID’, 64);
Level := Add<TFieldEnum>(‘XLevel’, ‘Nivå’, 70);
Level.Formatter :=
function (const Lvl: TLogEventLevel):String
begin
Result := LogEventLevelToString(Lvl);
end;
Category := Add<TFieldEnum>(‘XCategory’, ‘Kategori’, 70);
Category.Formatter :=
function (const Cat: TLogEventCategory):String
begin
Result := LogEventCategoryToString(Cat);
end;
App := Add(‘AppShortName’, ‘App’, 30);
Client := Add(‘ClientName’, ‘Client’, 140);
Client.HAlighment := taRightJustify;
Title := Add(‘Title’, ‘Beskrivelse’, 800);
end;
which is a lot less code than I needed before.
Basically, I Add(‘sqlcolumn’, ‘Grid Col Title’, width in px);
If I don’t add any field specifications to the QuerySet, they will be generated based on the query results and the name/TFieldType of each column.
The old code also read individual log objects from the database and then moved them to the grid – while this uses SQL -> Grid – so it is quite a bit faster.
I could also use owner draw and a virtual grid to avoid duplicating the query results as strings in the grid – but that would rob me of some of the nice features of TAdvStringGrid.
Right now, there are only two conversions for each cell – first DB result to native, and then native to string – and there are no case statements 😉
Still work in progress, but I am reasonably happy so far – except from that internal type scope thing?
Benchmarked: 1000 rows
Old object read + ownerdraw TStringGrid: 4.5 seconds
New SQL read + stuff to TAdvStringGrid: 89 ms
So, approx 50 times faster.
You need try the TDrawGrid instead TStringGrid because TStringGrid is the collection of rows with columns but you need the virtual grid (TDrawGrid)