Well... after some days of frustration... I did it. Here´s how, in case someone had the same problem:
I got a very basic personalized ComboBox component I made some years ago, that has just another published TStringList property named "values". So in the combo we have 2 stringlists: Items and Values. I use these 2 lists to put the primary key field values in the "Values" property and corresponding text or whatever field in the "Items" property. As we load the whole table to this combo this method should, of course, be used only for small tables. Anyway I don´t think anyone would be so silly to use a lookup field for a 100000 lines table.
So to start we load the data of the secondary table to the combo and set it´s visible property to false.
Then we create the lookup field in the dataset as usual, and Zeos components goes as far as initialy showing the right value for the field in the dbgrid. It´s nice to create some test values in the database first so we can see it is working as we progress.
After that, we should be able to see the dbgrid with the right values in the lookup field, but when we try to edit it, we come up with an empty column.
So now the not-so-tricky part:
Create a TRect variable in your form (better make it private) and name it anything you like (we´ll use FRect for this example).
Then in the OnDrawColumnCell for your DBGrid put the following code:
if (gdFocused in State) then
FRect := Rect;
(Sender as TDBGrid).DefaultDrawColumnCell(Rect, DataCol, Column, State);
DefaultDrawing for the DBGrid should be true. This will guarantee that we know the position for the cell we´re editing.
Then in the OnSelectEditor event put the following code:
if (Column.DesignIndex = <whatever column index>) then
begin
ComboName.BoundsRect := FRect;
Editor := ComboName;
end;
finally in the OnChange event for the ComboBox put the following:
if not(yourTableOrQuery.State in [dsEdit, dsInsert]) then
yourTableOrQuery.Edit;
yourTableOrQuery.KeyFieldName.AsString := comboBox.Values[comboBox.ItemIndex];
if all works well this is all it takes.
I said table or query because I were using a query with CachedUpdates to make this work.
the code for my combobox component is as simple as this:
interface
type
TValComboBox = class(TComboBox)
private
FValues: TStringList;
FExecutarChange: Boolean;
FPressBKSP: Boolean;
FPressDEL: Boolean;
FHaviaSelessaum: Boolean;
procedure SetValues(Value: TStringList);
protected
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure Change; override;
procedure DropDown; override;
public
Selecionado: Integer;
procedure Sort;
constructor Create(AOwner: TComponent); override;
published
property Values: TStringList read FValues write SetValues;
end;
implementation
{ TValComboBox }
procedure TValComboBox.Change;
var
Ix,
SelSt
: Integer;
begin
if not FExecutarChange then
Exit;
FExecutarChange := False;
inherited Change;
try
if Text = '' then
begin
Selecionado := -1;
Exit;
end;
SelSt := Length(Text);
Ix := 0;
while Ix <= Items.Count do
if UpperCase(Copy(Items[Ix], 1, Length(Text))) = UpperCase(Text) then
Break
else
Inc(Ix);
if Ix <= Items.Count then
begin
Selecionado := Ix;
if FPressBKSP then
begin
if FHaviaSelessaum then
begin
Text := Copy(Text, 1, Length(Text) - 1);
Dec(SelSt);
end;
end;
if FPressDel then
begin
if FHaviaSelessaum then
begin
SelLength := 0;
Selecionado := -1;
Exit;
end;
end;
Text := Items[IX];
SelStart := SelSt;
SelLength := Length(Text) - SelSt;
end
else
Selecionado := -1;
finally
FExecutarChange := True;
end;
end;
procedure TValComboBox.SetValues(Value: TStringList);
begin
Values.Assign(Value);
end;
procedure TValComboBox.KeyDown(var Key: Word; Shift: TShiftState);
begin
FPressBKSP := Key = VK_BACK;
FPressDEL := Key = VK_DELETE;
FHaviaSelessaum := SelLength > 0;
inherited KeyDown(Key, Shift);
end;
constructor TValComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FValues := TStringList.Create;
FExecutarChange := True;
Selecionado := -1;
end;
procedure TValComboBox.Sort;
var
Itms, Vls
: array of string;
Ix
: Integer;
procedure QuickSort(var A, B: array of string; iLo, iHi: Integer);
var
Lo, Hi
: Integer;
Mid, T :
string;
begin
Lo := iLo;
Hi := iHi;
Mid := A[(Lo + Hi) div 2];
repeat
while A[Lo] < Mid do Inc(Lo);
while A[Hi] > Mid do Dec(Hi);
if Lo <= Hi then
begin
T := A[Lo];
A[Lo] := A[Hi];
A[Hi] := T;
try
T := B[Lo];
B[Lo] := B[Hi];
B[Hi] := T;
except
end;
Inc(Lo);
Dec(Hi);
end;
until Lo > Hi;
if Hi > iLo then QuickSort(A, B, iLo, Hi);
if Lo < iHi then QuickSort(A, B, Lo, iHi);
end;
begin
SetLength(Itms, Items.Count);
SetLength(Vls , Items.Count);
try
for Ix := Low(Itms) to High(Itms) do
begin
Itms[Ix] := Items[Ix];
try
Vls[Ix] := Values[Ix];
except
end;
end;
QuickSort(Itms, Vls, Low(Itms), High(Itms));
Items.Clear;
Values.Clear;
for Ix := Low(Itms) to High(Itms) do
begin
Items.Add(Itms[Ix]);
try
Values.Add(Vls[Ix]);
except
end;
end;
finally
Finalize(Itms);
Finalize(Vls);
end;
end;
procedure TValComboBox.DropDown;
begin
FPressBKSP := False;
FPressBKSP := False;
inherited DropDown;
end;
Hope it helps someone.
Nelson