Change the Dev Express MaskEdit Column property from code - delphi

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;

Related

Delphi 10.4 - Sort Memtable by clicking Stringgrid Header

I feel like an idiot because my question seams so simple but I don't get it done :D
My Settings is that:
One Dataset (Memtable), One Stringgrid. The Grid is bind via live Bindungs.
I would like to sort my Columns by clicking on the GridHeader. In the OnHeaderClick Event I get an tColumn Object. I only can read the Column.Header String, but I changed the Text from the Header to a more speakable Text. When I put Column.header into Memtable.Indexfieldsname Memtable says that field does not exist, what is right, but I don't know how to get the right Fieldname from the column.
What you want is quite straightforward to do. In the example below, which uses the demo data from
the Biolife demo, I've linked the StringgRid to the FDMemTable entirely by binding objects
created in code so that there is no doubt about any of the binding steps or binding properties,
nor the method used to establish the bindings.
procedure TForm2.FormCreate(Sender: TObject);
var
BindSourceDB1 : TBindSourceDB;
LinkGridToDataSourceBindSourceDB1 : TLinkGridToDataSource;
begin
// Note : You need to load FDMemTable1 at design time from the sample Biolife.Fds datafile
// The following code creates a TBindSourceDB which Live-Binds FDMemTable1
// to StringGrid1
//
// As a result, the column header texts will be the fieldnames of FDMemTable1's fields
// However, the code that determines the column on which to sort the StringGrid does not depend
// on this
BindSourceDB1 := TBindSourceDB.Create(Self);
BindSourceDB1.DataSet := FDMemTable1;
LinkGridToDataSourceBindSourceDB1 := TLinkGridToDataSource.Create(Self);
LinkGridToDataSourceBindSourceDB1.DataSource := BindSourceDB1;
LinkGridToDataSourceBindSourceDB1.GridControl := StringGrid1;
end;
procedure TForm2.StringGrid1HeaderClick(Column: TColumn);
// Sorts the STringGrid on the column whose header has been clicked
var
ColIndex,
FieldIndex : Integer;
AFieldName : String;
begin
ColIndex := Column.Index;
FieldIndex := ColIndex;
AFieldName := FDMemTable1.Fields[FieldIndex].FieldName;
Caption := AFieldName;
// Should check here that the the field is a sortable one and not a blob like a graphic field
FDMemTable1.IndexFieldNames := AFieldName;
end;
Note that this answer assumes that there is a one-for-one correspondence between grid columns and fields of the bound dataset, which will usually be the case for bindings created using the default methods in the IDE. However, Live Binding is sophisticated enough to support situations where this correspondence does not exist, and in those circumstances it should not be assumed that the method in this answer will work.

How to find out which field was changed in a delphi 6 TZTable via ZeosLib

I have a TZTable (ZEOSlib) bound to a DBGrid now I need to know which particular TField was changed by the user.
I tried with
if NOT (taPositionenArtNrGH.NewValue = taPositionenArtNrGH.OldValue) then
ShowMessage('ArticleNumber changed');
I placed the code in
BeforePost, OnUpdateRecord, AfterPost
But in the Debugger OldValue is always NewValue. How do I check which field was changed?
You can use UpdateStatus : TUpdateStatus for this. For example:
Set ZTable.CachedUpdates to true;
Create new calculated field named "Status".
To show old value for example of field "FNAME" create new calculate field named "FNameOldValue"
In OnCalcFields event use:
procedure TDM1.ZTable1CalcFields(DataSet: TDataSet);
begin
if ZTable1.UpdateStatus in [usModified] then
begin
ZTable1Status.value := 'Modified';
ZTable1FNameOldValue.value := ZTable1FNAME.OldValue;
end
else
ZTable1Status.value := 'UnModified'
end;
Result :
Edit:
You can detect field level changes like:
if ZTable1.UpdateStatus in [usModified] then
begin
for I := 0 to ZTable1.Fields.Count - 1 do
begin
if ZTable1.Fields[i].OldValue <> ZTable1.Fields[i].NewValue then
-- do something with this field
end;
end;
As per documentation:
The NewValue property is only usable when the data is accessed using
a TClientDataSet component or cached updates is enabled.
If you just want to know what fields have been changed, why not use TField.OnChange event? You could fill a list of field names in this event and clear it in OnAfterPost. But the Modified property would be very useful indeed; it's odd that it haven't been implemented yet.

How to get value of TDBLookupComboBox?

I have tables on my database Tb_barang and Tb_jenis. Tb_jenis the following columns kd_jenis (primary key) and jenis. I use TDBLookupComboBox to show the items from the Tb_jenis table. There are 6 items (Mie, Susu, etc). I want to save item selected as kd_jenis not jenis.
How to I save jenis in table to kd_jenis?
Sample data: Tb_jenis
jenis kd_jenis
Mie J1
Susu J2
Here it the code I've tried.
if (kd.Text='') or (jenis.Text='Pilih') then
ShowMessage('Data Tidak Lengkap, Silakkan Dilengkapi !')
else
begin
with dm.Qbarang do
begin
sql.Clear;
SQL.Add('select * from Tb_barang where kd_barang='+quotedstr(kd.text)+'');
open;
end;
if DM.Qbarang.Recordset.RecordCount > 0 then
ShowMessage('Data Sudah Ada, Silakkan Isi Yang Lain!')
else
begin
try
DM.koneksi.BeginTrans;
with DM.QU do
begin
close;
SQL.Clear;
SQL.Add('insert into Tb_barang values('+QuotedStr(kd.Text)+','
+QuotedStr(jenis.Text)+')');
ExecSQL;
end;
DM.koneksi.CommitTrans;
ShowMessage('Data Berhasil Disimpan');
except
DM.Qbarang.Close;
DM.Qbarang.Open;
FormShow(sender);
end;
end;
end;
As i understand you want to get Key Value of table from DBLookupComboBox.
so in it is 2 important property in DBLookupComboBox ListField and KeyField
if you set them correctly For Example KeyField set as kd_jenis and List Field Set as jenis then you will see Jenis on List and you can access to jenis in DBLookupCombobox.text and also you can access to KeyField (in this case kd_jenis) by DBLookupCombobox.KeyValue
you should fallow this steps.
Put a TADOConnection to your form for connecting to a database.
build connection string for connecting to Database.
add a ADO table to your form.
Set Connection property to AdoConnection1(Default Name Of ADOCOnnection).
On ADOTable open the Table name Property and select One of your database table and then set active property as true.
Add a DataSource to your form and set Dataset Property as ADOTable1(Default Name of ADOTable)
Add DBLookupCombobox to your form and Set ListSource as DataSource1(the default name of datasource)
Open ListField Property and Select witch field do you want to show in Combobox.
Open the keyField Property and Select witch field is Key field.
All of above Steps should done at Design time. for testing your application add to edit box on your form as edit1 and edit2 then write a small code for OnCloseUp Evwnt of DBLookupCombobox like this
Edit1.Text:=DBLookUpCombobox1.KeyValue;
Edit2.Text:=DBLookupCombobox1.Text;
If you have problems with DBLookupComboBox you may use normal combobox and fill it like the example here.
After someone selects something in your DBLookupComboBox...The cursor to the table is moved.
You can access the value directly:
jenis.ListSource.DataSet.FieldByName('kd_jenis').AsString
This assumes that jenis is a TDBLookupComboBox.
That ListSource.DataSet points to Tb_jenis.
As Craig stated...you have a serious bug in your code...you need a RollbackTrans on exception...other wise you will never release the lock...
DM.koneksi.CommitTrans;
ShowMessage('Data Berhasil Disimpan');
except
DM.koneksi.RollbackTrans;
DM.Qbarang.Close;
DM.Qbarang.Open;
FormShow(sender);
end;
I do something like this...if I need to guarantee saving info and rolling back if fails.
procedure TForm8.SaveData;
begin
Assert(not ADOQuery1.Connection.InTransaction, 'Code problem-We should not be in a Transaction');
ADOQuery1.Connection.BeginTrans;
try
ADOQuery1.ExecSQL;
ADOQuery1.Connection.CommitTrans;
finally
if ADOQuery1.Connection.InTransaction then
begin
{If you are here...your in an ErrorState...and didn't Commit your Transaction}
ADOQuery1.Connection.RollbackTrans;
HandleError(ADOQuery1);
end;
end;
end;

TMaskEdit LookUpComboBox Behaviour

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

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;

Resources