What can you do if you want different cell controls in the same column of a grid in FireMonkey.
The cell control seems to belong to the column, but there are situations (like the property editor), where some rows need a checkbox while other rows need a combobox or an edit control.
Thanks in advance.
The following steps should get you up and running:
Create a style, add to it the controls you want to show (i.e. a TCheckbox, a TCombobox and a TEdit). Add these within a TLayout, and set each controls StyleName to something memorable.
In your cells ApplyStyle use FindStyleResource to extract the controls you added above using their StyleNames.
When the grid calls your cell's SetData method, you need to set the Visible property for each control so only the appropriate one is shown. If you can't determine this from the data passed in, add an event handler to the cell to get the data.
You'll need to sort out the keyboard handling, which gets pretty messy. If memory serves, you need to pass keys from the grid/cell to the control (or or is it trap movement keys from the controls and pass them to the grid? Sorry if I forget exact detail).
Sorry I can't give a more detailed answer, but covering this completely would take a whole series of blog posts.
Use a style - set the cell style when you set the cell data - then us the onapplystyle event to do anything clever you require with the newly styled cell.
This way you can add what controls you need to the style and then access the controls (to set events etc) with the onapplystyle.
Hint - FindStyleResource is your friend here :-)
I have also needed a property editor and looked for a way hosting different cell types in one column. Using different styles for each row may be a solution as suggested above, but since Firemonkey grid doesnt reserve any cell control for a specific row, each time the cell control would be shown on the row, the true style would be applied to it. This is not a big problem for a static property editor, however for a real grid which has got may rows and different cell types in each row a diferent strategy is needed. So I came up with a different solution, I considered cell type proxies between TColumn and cell controls, so that each cell proxy will reserve the cell controls that is responsible for. First of all, I have a new TColumn (TvariantColumn) which is responsible for the top strategy.
vColumn := TVariantColumn.Create(Self);
vColumn.Header := 'Variant Column';
vColumn.OnGetCellProxyIndex := GetCellProxyIndex;
Grid1.AddObject(vColumn);
Then create any proxies like
vColumn.NewCellProxy(TTextProxy);
vColumn.NewCellProxy(TColorComboProxy);
vColumn.NewCellProxy(TComboColorProxy);
You can also handle Proxy specific jobs after you create it, like
with TProgressProxy(vColumn.NewCellProxy(TProgressProxy)) do //4
begin
Min := 0;
Max := 100;
end;
with TPopUpProxy(vColumn.NewCellProxy(TPopupProxy)) do //5
begin
Items.Add('Istanbul');
Items.Add('Paris');
Items.Add('NewYork');
end;
I have blogged my method in my website and published a detailed article where you can find more about the subject.
Related
I've customised the style of a Firmeonkey list box item in such a way that now it can consist of 4 TLables in it. Each of the lable has Alignment as alNone.
I'm setting position of each of them in my code whenever i need to add any item. I've observed that when my list has scroll bar and if first component is not visible (i.e. i've scrolled down enough) at that time if i re-add all the items again in list box, then the position of TLabels in first items (or items which are not shown) get distorted.
For setting positions I am using below code :
(tmpListBoxItem.FindStyleResource('txtCol2') As TLabel).Position.X :=
(tmpListBoxItem.FindStyleResource('txtCol2') As TLabel).Position.X + (tmpListBoxItem.FindStyleResource('txtCol2') As TLabel).Width;
Any suggesstions, how can i overcome this issue.
Regards,
Padam Jain
Firemonkey styles are repeatedly 'applied' and 'freed' as components appear and disappear from screen.
It is not enough to simply set properties of style objects once and expect those values to be remembered. What you need to do is either listen to the OnApplyStyleLookup event or override the ApplyStyle method of a custom component and use the same you have above to set the properties again.
This means you'll need somewhere to store the values you are going to set.
I would suggest for your situation that you subclass TListBoxItem so you can add suitable properties or fields and put your code in ApplyStyle.
I am running Lazarus 0.9.30.2.
I have a TForm on which there is a TPageControl. Within the TPageControl there is a series of TTabSheets. At runtime the order of the TTabSheets differs from design time (see picture).
The order in design time is what I want to see at runtime, at least for the very first time the form is displayed. Why does the order change at run time and is there a way to control this?
#TLama is correct that this is related to way the Windows tab control behaves when in multi-line view. The behaviour you are observing is related to the way selection is handled for multi-line tabs. When you select a tab it is always shown in the bottom row because the visual cue to indicate which tab is selected can only really work for tabs in the bottom row.
Given that constraint the control simply has to rearrange rows of tabs as you modify the selected tab. It's astoundingly confusing for the user. Good UI design never has UI elements changing position like this.
Clearly what is happening here is that the rearrangement is happening at runtime when the form is first shown and for whatever reason this is resulting in a different arrangement from the design time arrangement. Given that the user can arrange the rows in any order just by selecting them I'm not sure you should worry about what order the rows appear in.
If you are dead set on forcing a particular arrangement when the form first shows you can add code like this to a OnCreate handler for the form:
PageControl1.ActivePage := TabSheet9;
PageControl1.ActivePage := TabSheet5;
PageControl1.ActivePage := TabSheet1;
Best practise for UI design is to avoid multi-line tab controls and I urge you to attempt to re-design your UI that way.
I am struggling to assign a style to a TGrid within Delphi Firemonkey. Styling required is quite basic (ie. Align the text in a column and colour per value).
For background, I have created a TGrid, set the rows (eg 200), and added the number of columns (3 in this case). The columns have been labeled as "Code", "Company" and "Balance". As the grid does not contain values (like a TStringGrid), I am able to set the display value via the "GetValue" method (where I retrieve data from an external source). - The result is a list that is fast, and able to cope with a lot of data, the downside is I can not format the design at run time...
I am thinking that I may have to use "Styles"; that are new in FM. If this is the case however, I am not sure how I can reference the cell as it does not really exist as it is painted via the GetValue method when it needs to be drawn?
Any help appreciated,
Regards
Ian.
Ray Konopka's blog might help you here:
http://www.raize.com/Articles/FmxStringGridCellFonts.asp
You can apply a style to a Column by creating the OnApplyStyleLookup event to the column, but to set the font style and color etc you would still need to implement a OnApplyStyleLookup for the TTextCell's themselves too.
I posted a very similar query on Stackoverflow and then found a workable solution which I added here
firemonkey mobile grid with livebindings - changing TextCell text color at runtime XE5
I'm trying to create my first app based on FireMonkey, and I hit a wall.
The only virtual list control I can find is tGrid.
This component is pretty good, but I can not figure out how to extend or customize it.
I get that there is tCheckbox column, tImage column etc, but what if I need a ButtonColumn or something like this?
Also I would like to style a row, based on the state of the data it represents.
An Example: if the data that is represented in the row has "Error=True" it should be displayed in red.
Has anyone got a similar problem? Or found alternate virtual list/grid components? Or even just some tips on use of the tGrid component.
These components are pretty essential in all database apps so it should be a pretty common request.
Also just as a note, I don't think the TGrid supports Drag & Drop of rows?
I have looked at
Firemonkey version of VirtualTreeView
and
Firemonkey and large amounts of data
If you look at the sources, TCheckColumn is only 15 code lines. If you need to create your own column descendant class it's quite straightforward.
This is one solution, otherwise you can dynamically create some components in your cells and then cast the children when checking the props (TColumn.CellControlByRow() return a TControl and the children would be what you have put in there).
As you want to 'style' your row I would suggest you to write your own TColumn class, even if you can do painting in the OnPaint Event.
I have a TListView (actually, a custom descendant) display in ViewStyle vsReport. One row is selected. I would like to get the screen coordinates of that row (or a cell within that row). Is there any way for me to do this?
(My goal is to display a small form over the list view giving the effect that it dropped down from the selected row).
I am using Delphi 2010 for this particular application.
For a list view in vsReport style I believe the best approach is to use the LVM_GETITEMRECT and LVM_GETSUBITEMRECT messages.
The VCL does not wrap this functionality up for you but it should not be too difficult to work it out from the MSDN docs.
Whilst it is very simple to use the TListItem.Position property exposed by the VCL, as far as I can tell this does not help you obtain the row height or indeed the coordinates of sub items.
Update
As NGLN very helpfully points out, the CommCtrl unit does expose ListView_GetItemRect and ListView_GetSubItemRect which are more convenient to use than the equivalent Windows messages above.
var
sel: TListItem;
pnt: TPoint;
begin
sel := ListView1.Selected;
if not Assigned(sel) then Exit;
pnt := ListView1.ClientToScreen(Sel.Position);