views:

89

answers:

4

I am looking for a way to provide a ListSource to a TDBLookupComboBox in delphi without having an actual table on the database server to draw that list from. The DataField for the Combo Box is a 1 character field that contains a coded value such as 'A' = 'Drivers License', 'B' = 'Passport', 'C' = 'Library Card', etc. That is to say that the table only contains A, B, or C. The application is responsible for Displaying 'Drivers License' in the GUI. Normally a database might have a look up table but this database does not and I can not add one. My idea is that the DataSource and ListSource for a DB Look-up control do not have to be the same database, so if it were possible to define a small table in my form that contains the look-up data then I could use that an not require a real database table.

Does anyone know of a delphi component that allows a TDataSet to be defined on a form without having any actual data files behind it?

A: 

If you use the jvcl, what you want can be accomplished without involving a dataset. Just use a TjvDBComboBox, use the Items property to set the values you want the UI to display, and use the Values property to set the actual values stored in the database.

jachguate
+1  A: 

Use a TClientDataset and define the fields, then connect to a datasource. In the oncreate event of the form do this: execute the createdataset method of the clientdataset and then populate it with the A,B,C data.

Francis Lee
+6  A: 

I know there's different in-memory dataset. Delphi comes with TClientDataSet, which you can use the way you want. You have to deploy the midas.dll with your executable in order to work, or you must include the the MidasLib in your uses clause in order to statically link this library in your executable (no midas.dll needed at runtime).

To get what you want from the TClientDataSet, you can create fields and:

  • store the records in a xml file (for example with another auxiliary tool you made). At runtime load the data with the LoadFromFile method of the TClientDataSet. Additionally you can store this xml as a resource with the $R directive and manipulate this resource at runtime to feed your ClientDataSet with the contained data, to prevent the deployment (and possible modification) of the xml file with your exe.
  • use the CreateDataSet method and insert/populate records with what you want at runtime

code sample:

procedure TFrom1.Init;
begin
  cdsIDType.CreateDataSet;
  cdsIDType.InsertRecord('A', 'Drivers License');
  cdsIDType.InsertRecord('B', 'Passport');
  //etcetera.
end;
jachguate
This is a technically correct answer, however it made a significant increase in the memory usage of my program, and the size of installater (which is an issue because I distribute the program electronically.)
William Leader
I made a simple test with Delphi 2007 too see what you consider a significant increase in the size of a the installer. Adding TClientDataSet component and MidasLib to uses clause exe grows ~320Kb and installer (made with inno setup+lzma) grows ~120Kb. Unless you're distributing it using 3.44" diskettes, I think such increase in size worths the power you gain using ClientDataSets.
jachguate
+2  A: 

An alternative solution is to use TComboBox rather than TDBLookupComboBox. Use a TDictionary to define a simple in memory lookup.

type
  TMyForm = class(TForm)
    MyComboBox: TComboBox;
    MyDataset: TSimpleDataSet;
    procedure MyComboBoxChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    ComboLookup: TDictionary<string, Char>;
  end;

implementation

{$R *.dfm}

procedure TMyForm.FormCreate(Sender: TObject);
var
  Key: string;
begin
  ComboLookup := TDictionary<string, Char>.Create;
  ComboLookup.Add('Drivers License', 'A');
  ComboLookup.Add('Passport', 'B');
  ComboLookup.Add('Library Card', 'C');
  for Key in ComboLookup.Keys do
  begin
    MyComboBox.Items.Add(Key);
  end;
end;

procedure TMyForm.MyComboBoxChange(Sender: TObject);
begin
  // This may be wrong didn't bother to look
  //up the correct way to change a field's value in code.
  MyDataset.Fields.FieldByName('IDCard').AsString := ComboLookup[MyComboBox.Text];
end;

You could use TComboBox.Items.AddObject instead of a separate lookup table but you'd have to create a wrapper class to store a char as a TObject or use Chr to convert it to an integer then cast it to TObject but a the above is simpler in my opinion.

codeelegance
This isn't what I asked for, but it is a good solution. My only problem is that the TDictionary doesn't seem to be available for Delphi Win32. I suspect you are suggesting the use of a .Net class. I ended up creating a small dictionary class for myself that allowed me to use this solution. Despite having to make my own dictionary class this didn't increase the memory use of my program so much and didn't require me to add anything to my installer. That makes this solution preferable to me.
William Leader
@William TDictionary<T, T> was added to Win32 in Delphi 2009 with support for generics. It is located in Generics.Collections.pas along TList<T>, TQueue<T>, TStack<T> and a few other useful classes.
codeelegance