The TDBLookupCombobox control gets a list of values from its ListSource (which e.g. represents a table with product info, "Products"). It then:
- displays the values in the ListField (e.g. a "ProductName" field) while
- remembering the values in the KeyField (e.g. an "ID" field)
The combobox stores the result (i.e. the KeyField value in the DataField, e.g. the "ProductID" field in the DataSource property (e.g. an "Orders" table).
The difference with the TDBComboBox is that the TDBComboBox is a (as it were) "singly data bound control": it stores the results in a database field but the list of values to select from is supplied by code/via the Object Inspector.
You can get the combobox to look up values from one table without storing the results in another by leaving the DataSource and the KeyField properties empty.
The following sample code snippet will:
- Allow a TDBLookupCombo box to be configured in unbound mode (i.e. no changes made to any table in the database)
- Ensure the visible data in the TDBLookupComboBox is from the selected record in the dataset (i.e. choosing a new value in TDBLookupComboBox contents will scroll the dataset to the correct record)
- Set the initial displayed value in the TDBLookupComboBox and the selected record in the datset to previously remembered values.
The following sample code snipper will NOT:
- Automatically update the TDBLookupComboBox value if the dataset is scrolled (you need to add your own handler to Dataset.OnScroll to achieve this)
interface type TForm1 = class(TForm) cboLookup: TDBLookupComboBox; dsSource: TDatasource; dsetSource: TDataset; ... protected FDisplayField: string; FKeyField: string; FPreviousKeyValue: string; // May be any datatype - see below ... end; ... implementation ... // Remember previous value FPreviousKeyValue:= load_from_settings_in_your_preferred_way_; ... // Configure DBLookupCombo dsSource.Dataset := dsetSource; cboLookup.ListSource := dsSource; cboLookup.ScrollListDataset := True; // This ensures that changing the ComboBox will automatically scroll // the dataset cboLookup.Style := csDropDownList; cboLookup.KeyField := FKeyField; cboLookup.ListField := FDisplayField; // This is the field that will appear in the contents of the ComboBox dsetSource.Open; // The ComboBox should now be populated, however intially no text is displayed // So right now there is no relationship between the selected record in the dataset // and the contents of the ComboBox // cboLookup.KeyValue reads and writes a Variant, so you may actually define // FPreviousKeyValue as any data type you feel is appropriate. // Remember a previous value if FPreviousKeyValue <> '' then begin dsetSource.Locate(FKeyField, FPreviousKeyValue, ); // Note: This will fail to correctly set the ComboBox, // But will set the Datatset to the correct record. // Now the dataset is on the correct record, lets ensure the DBLookupCombo // is showing the same value as the selected record If (cboLookup.KeyValue = Null) And (dsetSource.RecordCount > 0) Then cboLookup.KeyValue := dsetSource.FieldByName(FKeyField).AsVariant; end; ... // Save current value for next time FPreviousKeyValue:= cboLookup.KeyValue; write_to_settings_in_your_preferred_way_(FPreviousValue);
At least for TDBLookupComboBox, there is a bug with FPC 2.6.0 (used in Lazarus 1.0, 1.0.2 etc) that requires the listfield to be present in the datasource as well.
Workaround: you can bypass this by declaring a calculated field with the same name as the listfield in the datasource's dataset that does nothing.
The Rx controls (in the RxNew package) have the RxDBLookupCombobox which has some extra functionality; it e.g. allows to display multiple fields/columns next to each other (much like MS Access comboboxes):
RxDBLookupCombo.LookupDisplay = 'field1;field2'; //takes a semicolon-delimited list of fields
It additionally has a property DisplayAllFields.