Difference between revisions of "TDBLookupComboBox"

From Lazarus wiki
Jump to navigationJump to search
(added rxdblookupcombo)
m (→‎Unbound use: Added Code Snippet (as an aid to my own memory :-) ))
Line 15: Line 15:
  
 
==Unbound use==
 
==Unbound use==
You can get the combobox to look up values from a table without storing the results by leaving the '''DataSource''' and the '''KeyField''' properties empty.
+
You can get the combobox to look up values from a table without storing the results by leaving the '''DataSource''' and the '''KeyField''' properties empty.<br/>
 +
Note:  I cannot get unbound mode to display any text without setting '''KeyField''' (see below) - Mike Thompson 05 June 2014
 +
<br/>
 +
<br/>
 +
The following sample code snippet will:
 +
* Allow a DBLookupCombo box to be configured in unbound mode (i.e. no changes made to any table in the database)
 +
* Ensure the visible data in the DBLookupCombo is from the selected record in the dataset (i.e. choosing a new value in DBLookupComboBox contents will scroll the dataset to the correct record)
 +
* Set the initial displayed value to a previously remembered value.
 +
 
 +
<syntaxhighlight>
 +
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
 +
  FPreviousValue := 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 be now 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
 +
 
 +
  // Remember a previous value
 +
  If FPreviousKeyValue <> '' Then
 +
  Begin
 +
    // I believe either one of the following two lines should work to synchronise the ComboBox and the Dataset,
 +
    // but I note from the Forums that there are cases when either one or the other will not work. 
 +
    // In all cases I could find at least one of these two lines always worked.
 +
 
 +
    //dsetSource.Locate(FKeyField, FPreviousKeyValue, []);  // Note: If this fails to correctly set the ComboBox, then scrolling the
 +
                                                            // dataset in future will not automatically update the ComboBox
 +
 +
    cboLookup.KeyValue := FPreviousKeyValue;  // cboLookup.KeyValue reads and writes a Variant, so you may actually define
 +
                                              // FPreviousKeyValue as any data type you feel is appropriate.
 +
  End;
 +
 
 +
...
 +
  // Save current value for next time
 +
  FPreviousValue := cboLookup.KeyValue;
 +
  write_to_settings_in_your_preferred_way_(FPreviousValue);
 +
</syntaxhighlight>
  
 
==Bugs==
 
==Bugs==

Revision as of 18:50, 5 June 2014

Template:Translate

Definition

Unit: Lazarus DbCtrls

Official documentation: TDBLookupComboBox

Description

A (doubly) data-bound combobox. 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 DBComboBox is a (as it were) "singly data bound control": it stores the results in a database fields but the list of values to select from is supplied by code/via the Object Inspector.

Unbound use

You can get the combobox to look up values from a table without storing the results by leaving the DataSource and the KeyField properties empty.
Note: I cannot get unbound mode to display any text without setting KeyField (see below) - Mike Thompson 05 June 2014

The following sample code snippet will:

  • Allow a DBLookupCombo box to be configured in unbound mode (i.e. no changes made to any table in the database)
  • Ensure the visible data in the DBLookupCombo is from the selected record in the dataset (i.e. choosing a new value in DBLookupComboBox contents will scroll the dataset to the correct record)
  • Set the initial displayed value to a previously remembered value.
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
  FPreviousValue := 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 be now 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

  // Remember a previous value
  If FPreviousKeyValue <> '' Then
  Begin
    // I believe either one of the following two lines should work to synchronise the ComboBox and the Dataset, 
    // but I note from the Forums that there are cases when either one or the other will not work.  
    // In all cases I could find at least one of these two lines always worked.

    //dsetSource.Locate(FKeyField, FPreviousKeyValue, []);  // Note: If this fails to correctly set the ComboBox, then scrolling the
                                                            // dataset in future will not automatically update the ComboBox
 
    cboLookup.KeyValue := FPreviousKeyValue;  // cboLookup.KeyValue reads and writes a Variant, so you may actually define
                                              // FPreviousKeyValue as any data type you feel is appropriate.
  End;

... 
  // Save current value for next time
  FPreviousValue := cboLookup.KeyValue;
  write_to_settings_in_your_preferred_way_(FPreviousValue);

Bugs

At least for DBLookupComboBox, 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.

Alternative control

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.