TMaskEdit LookUpComboBox Behaviour - delphi

I have a dev express grid dbtableview where I defined a column as maskedit.
On InitEdit I populate the LookItems list for a specific record (item).
The question is if I can restrict the user to introduce only the values that match the LookItems for the specific record, instead of changing the whole column property to LookUpComboBox ?

You will need a component called cxEditRepository, add LookupComboBox to Repository
on your cxDBColumn use the event OnGetProperties
In this example, my column is called 'text'
procedure TForm2.cxGrid1DBTableView1TextGetProperties(
Sender: TcxCustomGridTableItem; ARecord: TcxCustomGridRecord;
var AProperties: TcxCustomEditProperties);
begin
if ARecord.Values[cxGrid1DBTableView1Text.Index] = 'value2' then
AProperties:= cxEditRepository1LookupComboBoxItem1.Properties;
end;
I hope this has helped

Related

Change the Dev Express MaskEdit Column property from code

Inside of Dev Express grid table view I have a bounded column (string type) defined as maskedit (property) from visual form. (Design, DeveloperExpressGrid).
If I define the editmask from visual form, it works as it should.
What I want is to define the editmask specific for each record, not for the entire column.
That is why I try to access the editmask property from code side on columnPropertiesChange event.
The problem is that when I call from code the column.property is CustomEdit, and therefore without any editmask property.
There is a way to access the editmask property from behind code?
You can use the InitEdit event of your view to change the mask for AEdit given as parameter since the default editor is TcxCustomMaskEdit. The needed column might be resolved from AItem.Index the Row can be found through Sender.DataController, depending of your databinding.
procedure TForm3.cxGrid1DBTableView1InitEdit(
Sender: TcxCustomGridTableView; AItem: TcxCustomGridTableItem;
AEdit: TcxCustomEdit);
begin
if AEdit is TcxCustomMaskEdit then // default editor if no other editor defined
begin
// your condition for row and column (here just toggeling)
if ( Sender.DataController.FocusedRecordIndex AND 1) = 1 then
TcxCustomMaskEdit(AEdit).Properties.EditMask := '###..####'
else
TcxCustomMaskEdit(AEdit).Properties.EditMask := '******';
end;
end;

Refresh colors in cxGrid

I have a cxGrid where I change the background color of some fields based on values in some of the fields.
This is all working very fine. But if I cahnge something in the grids data, the colors aren't updated before I close an reopen my form.
What procedure to call to get this updated if the record is changing?
To my experience it does update when you switch the row. But i used it in DB-mode with TClientDataSet.
Check methods like
TcxControl.InvalidateRect
TcxControl.InvalidateRgn
TcxControl.InvalidateWithChildren
You can also invalidate node:
TcxGrid.ActiveView.Invalidate;
TcxGrid.ViewData.Records[0].Invalidate;
TcxGridViewData.Rows[0].Invalidate
TcxCustomGridTableController.FocusedRecord.Invalidate;
Events like
TcxCustomGridTableViewStyles.OnGetContentStyle
TcxCustomGridTableItem.OnCustomDrawCell
also exposes those items (with their Invalidate methods) among or inside parameters, like
ARecord: TcxCustomGridRecord;
ViewInfo -> TcxGridTableCellViewInfo.GridRecord
In other words - open the cxTL unit and grep for "invalidate" word and note every match.
If your grid is attached to a data set, and the data in the dataset changes, the OnGetContentStyle events are called automatically. Make sure that your dataset knows that the data is updated. It sounds like your editing form isn't telling the grid dataset to refresh itself. You can do that either with a callback procedure or implementing the Observer Pattern.
The following code demonstrates how to implement an OnGetContentStyle event for a grid column.
procedure TFormWithGrid.cxGrid1DBTableView1LASTNAMEStylesGetContentStyle(
Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
AItem: TcxCustomGridTableItem; var AStyle: TcxStyle);
begin
if ARecord.Values[cxGrid1DBTableView1FIRSTNAME.Index] = 'test' then
begin
AStyle := TcxStyle.Create(nil);
AStyle.Color := clRed;
AStyle.Font.Style := [fsBold];
end;
end;
in my situation, this will works
cxGridDBTblVwContenido.DataController.Refresh;

it's possible to create a fake data field in a delphi dataset?

I want to create a 'fake' data field in a DataSet (not ClientDataSet):
the field should not be stored in the db
it's not a calculated field (the user should be allowed to enter input data)
the field has business logic meaning, so after the user updates its value it should update other fields (with the OnFieldChange event)
I know I can have a simple no-dbaware control, capture it's OnChange event and perform the calculations there (or call a DataModule function, where the DataSet resides) but I think it's more clean if I can reutilize the dataset automatic binding with db-ware controls and dataset events..
Also this way the unique connection between the Form (Presentation) and the DataModule (Model) it's the DataSet (less coupling)..
PD: I'm using fibplus, with I think the solution (if any) will be at the VCL level..
Thanks!
Have you tried using an InternalCalc field? Your data aware controls will let you edit an InternalCalc field's value, and the value is stored in the dataset.
If you create an InternalCalc field in the dataset (TClientDataSet, TQuery, etc.) at design time, it's almost exactly what you're asking for.
You could create an updatable view (with before insert/update/delete triggers) in your Interbase/Firebird database. This would look like a "virtual table" to the client (the select statement of the view's declaration can also contain "virtual fields") and it's totally up to you how you implement the triggers.
You can make a Calcfield writeable:
type
TCalcStringField = class(TWideStringField)
function GetCanModify: Boolean; override;
end;
function TCalcStringField.GetCanModify: Boolean;
begin
// Makes Calcfield editable
//if FieldNo > 0 then
if DataSet.State <> dsSetKey then
Result := not ReadOnly and DataSet.CanModify
else
Result := IsIndexField
//else
// Result := False;
end;
Set Calculated to true, and in OnSetText of this Field you can then write the Text to any other place
procedure TformXX.XXOnSetText(Sender: TField; const Text: string);
begin
...
end;

DBGrid showing "(MEMO)" as the value of string fields

I'm trying to write a simple SQLite application using Lazarus and the SQLdb components.
I connect to the database and populate a TDBGrid. Problem is that all columns that are text fields display the value "(MEMO)" rather then the string in database.
I have found a simple solution:
The property dgDisplayMemoText from the DBGrid must be enabled.
I forgot the source of this but this is what I am doing with memo fields in tdbgrid.
bluish is right about the gettext event, this is how to implement it in the code:
Create a class called MemoDifier:
MemoDifier = class
public
procedure DBGridOnGetText(Sender: TField; var aText: string;
DisplayText: boolean);
end;
At the implementation section of your code, put this:
procedure MemoDifier.DBGridOnGetText(Sender: TField; var aText: string;
DisplayText: boolean);
begin
if (DisplayText) then
aText := Sender.AsString;
end;
Then click the tdbgrid control in your form and at the Object Inspector(Lazarus IDE), click the Events tab, scroll below to find the OnPrepareCanvas event. Double click it to generate the code. Then modify the code to suit to your needs such as the name of your tdbgrid control:
procedure Tmainui.TDBGrid1PrepareCanvas(sender: TObject;
DataCol: Integer; Column: TColumn; AState: TGridDrawState);
var
MemoFieldReveal: MemoDifier;
begin
if (DataCol = 1) then
begin
try
TDBGrid1.Columns.Items[0].Field.OnGetText := #MemoFieldReveal.DBGridOnGetText;
TDBGrid1.Columns.Items[1].Field.OnGetText := #MemoFieldReveal.DBGridOnGetText;
TDBGrid1.Columns.Items[2].Field.OnGetText := #MemoFieldReveal.DBGridOnGetText;
except
On E: Exception do
begin
ShowMessage('Exception caught : ' + E.Message);
end;
end;
end;
end;
The variable MemoFieldReveal points to the class MemoDifier. Don't forget to modify the index (Items[x]) to point to your index number of the tdbgrid items/fields which shows the (MEMO) text.
Another option
If you are using TZConection add this line to you code when you Connect you database
TZConnection).Properties.Add('Undefined_Varchar_AsString_Length=100');
As said on IRC, you probably need to add the fields of your query to the form, (so that "field" components are generated for them) and then implement the TMemoField.GetText event.
See if entering the "fields" field in the object inspector brings up an editor to generate the components (it does so in Zeos iirc).
Memo fields cannot be shown in the TDBGrid. Add TDBMemo to the form and connect it to the same TDataSource. You will see the text in your memo in this case.
I have the same in MySQL and Tgrid so I'm hoping the answer is the same as it is quite simple :-)
Say if s is the field causing the problem then Instead of writing
SELECT s
write
SELECT LEFT(s,200) AS s
An apparently simple solution is to limit the length of the TEXT in the field using something like VARCHAR(n) in the column type where n is the maximum number of allowed characters.
Old question but I came across it while looking for a similar issue, but on the data retrieved by code rather than with a DBGrid; When I retrieved a string fields with the methods DisplayText or Text, I got "(memo)" instead of the correct value.
The answer is actually simple… The TSQLQuery class owns a set of methods called AsXxx to get the data according to a type of data. Here use AsString to assign a variable inline.
SQLQuery1.Open;
//some check to make sure there are fields
name:=SQLQuery1.Fields[1].AsString; //gives "English" for example
code:=SQLQuery1.Fields[2].DisplayText; //gives "(Memo) instead of "en"
More, if you don't know at design time of which type the variable is (for example, you want to design a generical function for any kind of table) with its FieldDefs property of your TSqlQuery object can help you.
It owns a DataType property that allows to choose which AsXxx function to use. Here for example.
SQLQuery1.Open;
//some check to make sure there are fields
with SQLQuery1.FieldDefs[1].DataType of
ftMemo: SQLQuery1.Fields[1].DisplayText; //gives "(Memo)"
ftString: name:=SQLQuery1.Fields[1].AsString; //gives "English" for example
...
end;
And if you look at the datatype while debugging, you will notice that with SQLite, any text is seen as a ftMemo, not a ftString for there is only one type of text there.
after some tests, I could see that although the fields are treated as "MEMO", for "string" fields, just keep the "VARCHAR" option instead of "TEXT" when creating the table.
This article gives a solution: Displaying and editing MEMO fiels in Delphi's TDBGrid.
Here I summarize what you have to do:
in the .dfm add OnGetText = MyDataSetMyFieldGetText to the TMemoField (here named MyField) belonging to your data set (for example a TTable, here named MyDataSet)
in the .pas > interface > type > inside your form definition, add
procedure MyDataSetMyFieldGetText(Sender: TField; var Text: string; DisplayText: Boolean);
in the .pas > implementation > add this method
procedure TDM.WorkVisiteNoteGetText(Sender: TField; var Text: string; DisplayText: Boolean);
begin
Text := Copy(WorkVisiteNote.AsString, 1, 100);
end;

How in a Delphi dxDBGrid can I change the color of a single row?

Basically a client wants to change the color of a single row in a Delphi dxDBGrid. There isn't a rows property like there is columns.
Any ideas?
You can use styles.
The DevExpres Grid in DBTableView has a event named: OnGetContentStyle in Styles part.
You can create at design two styles and apply the desired style at runtime.
procedure TFormBrBase.DBTableViewStylesGetContentStyle(
Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
AItem: TcxCustomGridTableItem; out AStyle: TcxStyle);
With ARecord you can access to the actual record values. With this values you decide and change the value of the AStyle(out) param. This line is painted with this style.
Greetings.
Neftalí
Germán Estévez
Sorry, simply use the OnCustomDraw event. argh Friday mornings.
I use on the grid's OnCustomDrawCell event, eg:
If ANode.Values[SomeColumnName.Index] = SomeValue then
AFont.Color := clRed;
This is assuming it is the QuantumGrid v3 you're referring to. If it's v4 or later then the answer pointing you at cxStyles is correct.

Resources