I just had a look at Firemonkey's grid implementation and it turns out that it is a very simple implementation (only 1800 lines which seems not much for a grid implementation). It does almost no custom painting but does instead aggregate a lot of other controls - which seems to be the Firemonkey style of doing things.
For example, each column keeps an array of controls - one for each cell. For a normal text column with 1,000,000 rows, the grid would keep 1,000,000 edit controls in memory - which seems a little crazy to me. (EDIT: not so sure now if that assumption is right. It seems to take the visibility of cells into account, which could mean it does provide something like a virtual mode, but I'm not quite sure...)
My question: Without any doubt, this component-aggregating design of Firemonkey seems simple and elegant but does it really scale well with the amount of data that has to be displayed in the grid? I cannot imagine that it does perform well with a large number of rows. What is the Firemonkey way of handling large amounts of data?
Thanks for any input.
The FireMonkey grid only has controls for the number of visible lines.
So if you have a grid with 10 visible rows and 3 columns, it will create 30 cell controls.
Filling the grid with 10.000 records is no problem: when you scroll the 30 cell controls are reused and mapped to the new visible rows.
And yes: I did some tests with this because we have TMS grids with 100.000 records :-).
If you use OnGetCellText (so not TStringgrid, which is very slow with lots of records, especially TMS grid (based in VCL stringgrid)) it is very fast (OnGetCellText only retrieves data of visible cells). We use this technique in combination with our data objects (these are already loaded, so no need to fill each cell of the grid with the string value again...) and both TMS and FMX grids are very fast with 100.000 records or more!
Related
In our application I'm moving from a TStringGrid to TVirtualStringTree component. A lot of data is being displayed (max. 50000 lines and 5 columns). One column contains on or more lines of text. I managed to implement multiline functionality using 'DrawCell' in the stringgrid with optimal performance: instant redraw of all lines (on resize) and scrolling without hitches (I have a list of row heights in memory, which will be updated when redraw is needed).
Transferring this multiline functionality to the VirtualStringTree is not as performant as the stringgrid alternative. I tried numerous implementations but have not yet succeeded. This is easily reproducable in the Demo application of the VirtualStringTree installation package:
In the 'MultilineDemo' form, set the 'rootNodeCount' of the VirtualStringTree to 10.000.
When running the demo, select 'Automatically adjust node height to node text.'
Initial redraw/repaint will take a while using lots of CPU. Ater each resize, jumping to top/bottom causes the same phenomenon, or even causing a 'stack overflow' exception (but that's another issue ...). The 'OnMeasureItem' method is called way too much, the way I see it (even on 'MouseMove' events).
Has anyone had this problem and managed to find a solution?
This is easily reproducable in the Demo application of the
VirtualStringTree installation package
At least this performance issue is easily solved by wrapping the call to ReinitNode() in a BeginUpdate() and EndUpdate():
MLTree.BeginUpdate();
try
MLTree.ReinitNode(nil, True);
finally
MLTree.EndUpdate();
end;
I slightly reworked the sample project and the Virtual Treeview today, the sample project works much smoother now. Just try the latest source code from GitHub.
Description of Application:
I have an application that allows a user to output a report to a document. The data that is written to the document is in the form of a table. The number of columns in the table and the width of the strings contained in each cell in the table are unknown until runtime (it depends on what query the user runs, what they want to see in the report etc.).
I'm using Delphi XE and Gnostice's eDocEngine to create a PDF document, and then creating a table in the document and writing the report data into it.
Problem:
The problem that I'm having is that you can only write a certain number of columns (6 or 7) into the document before they disappear off the right hand side of the document. It isn't unknown for a user to produce a report with 30 or 40 columns in the table (as they correspond to fields in a database, which they run a query over), so I need to be able to get the table to fit entirely into the document, no matter how many columns it contains.
As a PDF can be zoomed, I suppose I could shrink the font size and column widths down and fit everything in that way, as the user could then zoom in and scroll around the table using their PDF reader. What I need to know is:
Is there a better way of getting the entire table to fit onto a page?
If shrinking/zooming is the best/only way of doing this, what is the most efficient way of ensuring that everything fits without making the document look strange (i.e. the table should ideally stretch across the page, rather than be bunched up to the left hand side because of some random scaling algorithm).
Edit
I've just done some more digging around and I've found "inputXRes" and "inputYRes" properties that change the scale of the canvas in the document, which looks promising, but I can't get it to work properly at the moment. Can anyone shed any light on how those properties are used? The text itself is scaling, but the size of the table stays the same, meaning that I've now got a tiny piece of text in the middle of a huge table cell, and the table is still only displaying 7 columns in the report.
Don't mess with scaling and font size.
Your customers will use PDF Reader and there are some options that will help to read the informations e.g. 1:1. But when you change the scaling or font size you cannot read the information, because it is too small.
Get a font size that fits perfect the needs of your customers and extend the page size to fit the table size.
With PDF Reader your customers will have the choice to view and print (shrink to fit) as they like and which paper size their print can handle.
BTW:
If you change the resolution and draw a line with a length of 2 inch on the canvas it will be 2 inch long, but a text with font size 12 (pixels) will grow or shrink.
I have a TPieSeries which looks like this image when populated with data. Not very bright... Can I instruct the pie series to show the top N most significant records, and summarize the rest in another slice named "Others"? So far, the only thing I've come up with has been to set chart paging and order my data so that the top N records are shown on the first page. I'm using TeeChart Standard v2011.03.32815 VCL.
Yes, you can do it using the OtherSlice property as shown in Yeray's example here.
Although the question seems simple, I couldn't find the answer to it.
I have a DBGrid component with lots of columns, and as a result they don't fit into the page and scrollbar appears. I also have column-autofix mechanism, which makes each column have width of the longest element in the table. When I scroll DBGrid to the right-end there is an empty space after the last column. How to get rid of this space?
One solution that I see is to stretch the last column to fit the empty space. But I don't know how to find the length of this empty space! DbGrid.Width and DbGrid.ClientWidth only give length of the component part, but not the real length of the table. Any hints??
It's not always easy to get DBGrid to behave the way you want it to behave. I decided to use alternative db grids after one project with the standard implementation and I never looked back.
If you can use an alternative grid, you have many options to choose from. There's even a topic here on SO with lots of pointers. Among the free-with-source options, I've always been quite fond of the JVCL project.
Just one last tip: there are grids that offer options and customizing possibilities beyond what you can dream of. Be aware that there's a cost attached to this degree of freedom, e.g. it can make the component slow, hard to integrate in your code, or both.
I think I have found a solution (although it seems a little strange). In order to find the difference between column widths and real width of the DBgrid (that means find the width of the empty space left after last column), we need to keep track of which column is shown on the left now (what is current column that is scrolled to). We can do that using OnDrawColumnCell event, since it will draw only columns which are scrolled on now. Then we need to calculate sum of widths of all visible columns, and subtract that from DBGrid's width. P.S. Sorry for bad english
Ex code:
For i:=0 to Last do
if Vis[i] then
Begin
Sum:=Sum+DBG.Columns[i].Width;
Inc(Cnt);
End;
if dgColLines in DBG.Options then
Sum := Sum + Cnt;
//add indicator column width
if dgIndicator in DBG.Options then
Sum := Sum + IndicatorWidth;
Dif:=DBG.ClientWidth - Sum;
The below answer is quite good, but not effective at all because it is placed in the OnDrawColumnCell event, so if there are a large number of rows and/or collumns, the performance might fall.
Instead of that, place the same code not in a painting event, but int the AfterOpen (and AfterRefresh) event of the source dataset in order to execute it only once for each resultset.
I saw this picture and now wondering if/how you can do this in Delphi. The highlighted/selected text shows two forms of formatting, i.e. highlight color and hash lines.
http://img9.imageshack.us/img9/4121/easilyselecttextofonela.jpg
I've done something very similar recently in a bible application, also done in Delphi.
The user can select a single verse and single words of the selected verses. (But this feature is not released yet, so don't bother looking for it)
I used the web browser control from Microsoft and added my own kind of selection handling.
I've done the formatting by enclosing the relevant parts with span elements and changing their CSS style. When the selection gets removed, I also remove the enclosing elements.
The hard part was backing the "visual" selections with a selection data structure and handling all the selection events (clicking, shift-clicking, shift-ctrl-clicking, ...)
Embedding IE seems to be an easier way to do this as DR says, but you can also do this manually by drawing it all on a canvas, an easy way would be to create two bitmaps (one without a selection and another selected (could be as complicated as you like - dashed, colored, ... )), and you need to know the positions/rects of all your characters which would be somewhat difficult for long texts.
You basically show the unselected bitmap, and overlap the selected parts by portions of the second image.
You would also need to handle the selection manually by OnMouseDown, OnMouseMove, OnMouseUp...