Пример проекта ниже делает то, что вам нужно.
Обновление Приведенный ниже код заменяет код, который я первоначально разместил, и избегает использования типа набора данных (TClientDataSet), который поддерживает fkInternalCalcполя.Он будет работать с TAdoQuery.
Хотя в принципе нет ничего сложного в разборе строкового поля на два подполя и наложении их в графическом интерфейсе для редактирования, проблема заключается в простых способах выполнения.это с TAdoQuery заключается в том, что он поддерживает только вычисленные поля fkCalculated, а элементы управления графическим интерфейсом с учетом db обрабатывают их как не изменяемые пользователем.
Я не уверен, почему существует это ограничение, но я предполагаю, что оно связанок тому факту, что элементы управления Delphi с поддержкой db изначально были разработаны для BDE (и в любом случае до того, как был добавлен fkInternalCalc для поддержки TClientDataSet).Код в DB.Pas, который применяет ограничение, находится в DB.Pas:
function TField.GetCanModify: Boolean;
begin
if FieldNo > 0 then
if DataSet.State <> dsSetKey then
Result := not ReadOnly and DataSet.CanModify else
Result := IsIndexField
else
Result := False;
end;
Приведенный ниже код работает путем добавления промежуточного класса для TStringField, который снимает ограничение для строковых полей, FieldKind которых является fkCalculated, которые не являются ReadOnlyи принадлежат к набору данных, который можно изменить (хотя это последнее ограничение может быть снято, я думаю).Средство вставки TStringField переопределяет GetCanModify
примерно так:
function TStringField.GetCanModify: Boolean;
begin
if (FieldKind = fkCalculated) and DataSet.CanModify and not ReadOnly then
Result := True
else
if DataSet.State <> dsSetKey then
Result := not ReadOnly and DataSet.CanModify else
Result := IsIndexField
end;
Полный код примера проекта приведен ниже.Обратите внимание, что я использовал обычные TDBEdits, потому что у меня проблема с моей текущей настройкой Devex, но код также должен нормально работать с TcxDBEdit.
Код:
type
TStringField = class(db.TStringField)
protected
function GetCanModify : Boolean; override;
end;
type
TForm1 = class(TForm)
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
DataSource1: TDataSource;
DBEdit1: TDBEdit;
DBEdit2: TDBEdit;
ADOQuery1: TADOQuery;
cxDBMaskEdit1: TcxDBMaskEdit;
DBEdit3: TDBEdit;
btnDataLinks: TButton;
ADOConnection1: TADOConnection;
ADOQuery1ID: TIntegerField;
ADOQuery1Field1: TWideStringField;
ADOQuery1Field2: TWideStringField;
ADOQuery1SubField1: TStringField;
ADOQuery1SubField2: TStringField;
procedure FormCreate(Sender: TObject);
procedure ADOQuery1BeforePost(DataSet: TDataSet);
procedure ADOQuery1CalcFields(DataSet: TDataSet);
private
procedure UpdateSubFields(DataSet : TDataSet);
procedure UpdateField1(DataSet: TDataSet);
end;
[...]
const
scSeparator = '#4'; // could be a literal #4 instead
procedure TForm1.UpdateField1(DataSet : TDataSet);
var
S : String;
begin
if DataSet.FieldByName('SubField1').IsNull or DataSet.FieldByName('SubField2').IsNull then exit;
S := DataSet.FieldByName('SubField1').AsString + scSeparator +
DataSet.FieldByName('SubField2').AsString;
S := Trim(S);
if Length(S) > DataSet.FieldByName('Field1').Size then
raise exception.Create('tthe combined size of the subfields is too long');
DataSet.FieldByName('Field1').AsString := S;
end;
procedure TForm1.UpdateSubFields(DataSet : TDataSet);
var
S,
SF1,
SF2 : String;
P,
SF2Start : Integer;
begin
S := DataSet.FieldByName('Field1').AsString;
P := Pos(scSeparator, S);
SF1 := Copy(S, 1, P-1);
SF1 := Trim(SF1);
SF2Start := P + Length(scSeparator);
SF2 := Copy(S, Sf2Start, Length(S));
SF2 := Trim(SF2);
DataSet.FieldByName('SubField1').AsString := SF1;
DataSet.FieldByName('SubField2').AsString := SF2;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
AdoQuery1.Open;
end;
procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
begin
UpdateSubFields(DataSet);
end;
function TStringField.GetCanModify: Boolean;
begin
if (FieldKind = fkCalculated) and DataSet.CanModify and not ReadOnly then
Result := True
else
if DataSet.State <> dsSetKey then
Result := not ReadOnly and DataSet.CanModify else
Result := IsIndexField
end;
procedure TForm1.ADOQuery1BeforePost(DataSet: TDataSet);
begin
UpdateField1(AdoQuery1);
end;
procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
UpdateSubFields(DataSet);
end;