How to change DBLookupComboBox value in Delphi? - database

I'm trying to change the visible text (value) of a DBLookupComboBox, using :
DBLookupComboBox1.KeyValue:=S;
and
DBLookupComboBox2.KeyValue:=X;
If the KeyValue and S are strings, then everything works fine, and I can set the value.
But when the KeyValue is an integer/Int64 (UID in the DB), and X is an Int64 variable - it doesn't work, and nothing changes.
So for an example, i need to set "Amsterdam" in DBLookupComboBox1, and 1500 in DBLookupComboBox2.
"Amsterdam" from the "City" field of the users, and 1500 as the UID.
What am I doing wrong please?
Thanks

This code is Important for you:
lkcbbArzSource.KeyValue:=2;//c(or another number);
lkcbbArzSource is a dbLookupComboBox object and you can insert only a number in this!why? because is numeric and another side of that there is a field that show a text or String of that numeric in combo.
in below sample code you can see a dbLookupComboBox how to menage and fill with Data-set and add in a grid :
rzSource.Enabled:= True;
lkcbbArzSource.Font.Size:=8;
lkcbbArzSource.Tag := V_Counter;
lkcbbArzSource.Visible:= True;
lkcbbArzSource.Enabled:= True;
lkcbbArzSource.Font.Name:='tahoma';
lkcbbArzSource.ListSource := myDsrSource;
lkcbbArzSource.KeyField := 'Code';
lkcbbArzSource.ListField := 'Des';
lkcbbArzSource.KeyValue:= IntToStr(FieldByName('P_ARZSOURCE').AsInteger);
lkcbbArzSource.OnChange := myBicLookUpChange;
SGrid2.Objects[look_col,lkcbbArzSource.Tag]:= lkcbbArzSource;
SGRID2.Objects[look_col,V_Counter] := nil;

Setting the KeyValue calls the SetKeyValue of the TDBLookupControl which in Delphi 7 appears as:
procedure TDBLookupControl.SetKeyValue(const Value: Variant);
begin
if not VarEquals(FKeyValue, Value) then
begin
FKeyValue := Value;
KeyValueChanged;
end;
end;
procedure TDBLookupComboBox.KeyValueChanged;
begin
if FLookupMode then
begin
FText := FDataField.DisplayText;
FAlignment := FDataField.Alignment;
end else
if ListActive and LocateKey then
begin
FText := FListField.DisplayText;
FAlignment := FListField.Alignment;
end else
begin
FText := '';
FAlignment := taLeftJustify;
end;
Invalidate;
end;
As you can see, your variable x is used as part of a LocateKey.
function TDBLookupControl.LocateKey: Boolean;
var
KeySave: Variant;
begin
Result := False;
try
KeySave := FKeyValue;
if not VarIsNull(FKeyValue) and FListLink.DataSet.Active and
FListLink.DataSet.Locate(FKeyFieldName, FKeyValue, []) then // << ---here
begin
Result := True;
FKeyValue := KeySave;
end;
except
end;
end;
Stepping into these procedures and functions should help you to debug your issue. All are located in the DbCtrls unit..

I have used this and solved my problem.
Use this lines of code at Form1.OnShow :
DBLookupComboBox1.ListSource.DataSet.Locate('City', 'Amsterdam', []);
DBLookupComboBox1.ListSource.DataSet.FieldByName(DBLookupComboBox1.KeyField).Value;
DBLookupComboBox2.ListSource.DataSet.Locate('UID', '1500', []);
DBLookupComboBox2.ListSource.DataSet.FieldByName(DBLookupComboBox2.KeyField).Value;

Related

Delphi Text File and Array

I have the following Scenario: In a textfile (justin#us883) the program must extract the password - us883 check if the password typed in is correct to the one in the list and then make a button visible to enter program: Code that is not working:
var
textf:textfile;
oneline,spass,scheck :string;
place,i,icount :integer;
Arrpass : array[1..Maxnames] of string;
begin
scheck := edtpass.Text;
assignfile(textf,'Userlist.txt');
reset(textf);
if fileExists('Userlist.txt')= false then
exit;
while not eof(textf) do
begin
Readln(textf, oneline);
place := pos('#',oneline);
delete(oneline,1,place);
spass := copy(oneline,1,place-1); // get the us883
Arrpass[i] := spass;
for i := Low(Arrpass) to High(Arrpass) do
if Arrpass[i] = spass then
begin
btnenter.Visible := true
end
else
btnenter.Visible := False;
Showmessage('Wrong Password');
end;
closefile(textf);
end;
Maybe you want to do it more delphi like:
var
list : TStringList;
user, password : String;
i : Integer;
begin
user := 'user1';
if fileExists('Userlist.txt')= false then exit;
list := TStringList.create();
list.NameValueSeparator := '#';
list.LoadFromFile('Userlist.txt');
i := list.IndexOfName(user);
if i >=0 then begin
password := list.Values[user];
// check password
end;
Issue 1:
place := pos('#',oneline);
delete(oneline,1,place);
spass := copy(oneline,1,place-1); // get the us883
The third line uses position of # that is not more actual (after deletion).
If you don't expect more symbols after password, just use
spass := oneline;
Issue 2:
How Arrpass array sould be filled?
This line Arrpass[i] := spass; uses uninitialized variable i. And what is a logic to compare just inserted value with itself? Perhaps you want to fill ArrPass before text reading.
Issue 3:
It is worth to check if fileExists before file handling.

Getting database field value not working

I am using the ado connection a adoquery and dsr and adotable
I have a database with bookingnumbers as a field in the table client.
I would like to get the last bookingnumber in the field and store it in a variable.
The booking number is saved as text on access.
So far I have:
Var
sNum : string;
....
sNum := Datamodule1.tblClient['BookingNumber'].Last;
but it is not working.
please help?
It is not a good idea to try and find the maximum value of a field by navigating the dataset, especially if the dataset isn't necessarily ordered by the field in question. Try something like this instead:
function TForm1.GetMaxBookingNumber : Integer;
var
Q : TAdoQuery;
begin
Q := TAdoQuery.Create(Nil);
Q.Connection := DataModule1.AdoConnection1; // or whatever the name of your connection is
try
Q.SQL.Text := 'SELECT MAX(BookingNumber) FROM CLIENT';
Q.Open;
// the `not IsNull` in the following allows for the table being empty
if not Q.Fields[0].IsNull then
Result := Q.Fields[0].AsInteger
else
Result := -1;
finally
Q.Free;
end;
end;
So here is what i wanted :
var
sNum : string;
procedure button click
begin
with Datamodule1 do
begin
qryClient.SQL.Add('SELECT BookingNumber FROM Client');
qryClient.Open;
qryClient.last;
sNum := qryClient['BookingNumber'];
end;
end;

Inno Setup : Automatically check a checkbox after a specified time in seconds

Hello I want My Inno Setup Script to automatically check a CheckBox in one of my wizard pages after a specified time (e.g. 5 seconds).
Here's Why:
I created a checkbox which can change WizardForm's ClientWidth and ClientHeight when toggled.
If I don't click on it, the width and height of the WizardForm stays same. That's how it behaves.
The code I written to do that:
var
MinimizerCheckBox: TNewCheckBox;
procedure InitializeWizard();
begin
MinimizerCheckBox := TNewCheckBox.Create(WizardForm);
with MinimizerCheckBox do
begin
Name := 'MinimizerCheckBox';
Parent := WizardForm;
Left := ScaleX(560);
Top := ScaleY(315);
Width := ScaleX(90);
Height := ScaleY(14);
Alignment := taLeftJustify;
Caption := 'Compact Mode';
OnClick := #MinimizerCheckBoxClick;
TabOrder := 3;
end;
end;
procedure MinimizerCheckBoxClick(Sender: TObject);
begin
if MinimixerCheckBox.Checked then
begin
with WizardForm do
begin
WizardForm.ClientWidth:=420;
WizardForm.ClientHeight:=175;
end;
end else begin
with WizardForm do
begin
WizardForm.ClientWidth:=654;
WizardForm.ClientHeight:=407;
end;
end;
end;
I want to check that checkbox automatically after a specified time.
Any example code to do this?
Thanks in advance.
You can schedule a timer to check the checkbox like this:
[Code]
var
MinimizerCheckBox: TCheckBox;
...
function SetTimer(
hWnd: longword; nIDEvent, uElapse: longword; lpTimerFunc: longword): longword;
external 'SetTimer#user32.dll stdcall';
function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL;
external 'KillTimer#user32.dll stdcall';
var
CheckTimerID: Integer;
procedure StopCheckTimer;
begin
Log('Killing timer');
KillTimer(0, CheckTimerID);
CheckTimerID := 0;
end;
procedure CheckProc(h: LongWord; msg: LongWord; idevent: LongWord; dwTime: LongWord);
begin
Log('Timer elapsed');
StopCheckTimer;
MinimizerCheckBox.Checked := True;
end;
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpXXX then { your page id }
begin
Log('Starting 5s timer');
CheckTimerID := SetTimer(0, 0, 5000, CreateCallback(#CheckProc));
end
else
if CheckTimerID <> 0 then
begin
StopCheckTimer;
end;
end;
For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.

Index out of range (-1) when I click on any item in the TListBox

The TListBox called lboMtrlList is populated with records from the database. The data displays properly when I run the application. When I click on any item in the list, shows the error:
Index out of range (-1)
despite the list not being empty.
Here's the code for populating the lboMtrlList:
procedure TfrmMakeQuote.FormCreate(Sender: TObject);
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\katiee\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
query.Connection := con;
performQuery;
query.SQL.Text :=
'SELECT [Material Description] FROM MtrlDatabase ORDER BY MtrlID';
try
query.Open;
lboMtrlList.Items.Clear;
while not query.EOF do
begin
lboMtrlList.Items.Add(query.Fields[0].AsString);
query.Next;
end;
finally
query.Close;
end;
//ledtDesc.Height := 81;
//ledtNotes.Height := 51;
end;
I want to be able to double click on an item in the lboMtrlList and move it to another TListBox called lboSelectedMtrl. Here's the code:
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
begin
lboMtrlList.Items.Add(lboSelectedMtrl.Items.Strings[lboSelectedMtrl.ItemIndex]);
end;
I want to be able to double click on an item in the lboMtrlList and move it to another TListBox called lboSelectedMtrl.
Your code is doing the opposite of that. It is trying to move an item from lboSelectedMtrl to lboMtrlList. You are getting the bounds error because there is no item selected in lboSelectedMtrl (lboSelectedMtrl.ItemIndex is -1).
Swap the ListBox variables, and add some error checking:
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
var
Idx: Integer;
begin
Idx := lboMtrlList.ItemIndex;
if Idx <> -1 then
lboSelectedMtrl.Items.Add(lboMtrlList.Items.Strings[Idx]);
end;

What is the proper way to dynamically create and call a stored procedure in Delphi using FireDac?

I am relatively new to FireDAC. I want to be able to call a stored procedure "on the fly", dynamically. So far I have the following:
function TForm21.ExecuteStoredProc(aSPName: string; aParams: TADParams): Boolean;
var
LSP: TADStoredProc;
i: Integer;
begin
LSP := TADStoredProc.Create(nil);
try
LSP.Connection := ADConnection1;
LSP.StoredProcName := aSPName;
LSP.Prepare;
for i := 0 to aParams.Count - 1 do
begin
LSP.Params[i].Value := aParams[i].Value;
end;
LSP.ExecProc;
finally
LSP.Free;
end;
Result := True;
end;
I call it with
procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TADParams;
begin
LParams := TADParams.Create;
LParams.Add.Value := 612;
LParams.Add.Value := '2008';
ExecuteStoredProc('HDMTEST.dbo.spARCHIVE_HISTORY_DATA', LParams);
end;
However, the stored procedure fails to execute. That is, the code runs fine, no error message is shown, but the stored procedure doesn't run.
Further info -- it runs fine if I drop a component and set up the params in code.
Anyone have any idea what I am missing?
Seeing as this q has been left unanswered for a while, I thought I'd try to get the code working without using the clues from the comments and found it not quite as easy as I'd imagined.
I immediately got stuck with the SP params. I found this
http://docwiki.embarcadero.com/RADStudio/XE5/en/TFDQuery,_TFDStoredProc_and_TFDUpdateSQL_Questions
which says
"If you have difficulties with manual definition of parameters,
populate the Params collection automatically and check how the
parameters are defined. Then compare that to your code. "
but I couldn't find a way of "automatically" populating the Params. I asked on the EMBA
FireDac newsgroup and the FD author, Dimitry Arefiev, kindly explained that
you can do that by checking that the FetchOptions include fiMeta, and then clearing and setting the FDStoredProc's StoredProcName.
Using a StoredProc in the pubs demo database on my SqlServer defined as follows:
create procedure test(#ANumber int, #AName varchar(20))
as
begin
select
#ANumber * 2 as "Number",
#AName + #AName as "Name"
end
I changed a couple of sections of the OP's code like this
[...]
LSP.Params.Clear;
LSP.StoredProcName := '';
LSP.FetchOptions.Items := LSP.FetchOptions.Items + [fiMeta];
LSP.StoredProcName := aSPName;
LSP.Prepare;
Assert(LSP.ParamCount > 0);
for i := 0 to aParams.Count - 1 do
begin
LSP.Params.ParamByName(aParams[i].Name).Value := aParams[i].Value;
end;
[...]
procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TFDParams;
Param : TFDParam;
begin
LParams := TFDParams.Create;
Param := LParams.Add;
Param.Name := '#ANumber';
Param.Value := 612;
Param := LParams.Add;
Param.Name := '#AName';
Param.Value := '2008';
ExecuteStoredProc('test', LParams);
end;
and it worked fine.
The OP mentions in the q he'd first had the problem that the SP failed to execute
but that he'd found that it worked if he "[dropped] a component and set up the params in code" so I thought I'd include here a console application where of course necessarily everything is done in code. This wasn't difficult, but the time it took me to get the Uses clause right is my main reason for posting this as an answer, for future reference. W/o the correct uses, you get errors complaining about various class factories being missing.
Console app (created and tested in XE6):
program ConsoleStoredProcProject3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, FireDac.DApt, FireDAC.Stan.Def, FireDAC.Stan.ASync,
FireDAC.Stan.Param, FireDAC.Stan.Option, FireDAC.Comp.Client,
FireDAC.Phys.MSSQL, VCL.ClipBrd;
procedure TestSP;
var
Connection : TFDConnection;
StoredProc : TFDStoredProc;
Param : TFDParam;
begin
Connection := TFDConnection.Create(Nil);
Connection.DriverName := 'MSSQL';
Connection.Params.Values['Server'] := // your server name'';
Connection.Params.Values['Database'] := 'pubs';
Connection.Params.Values['user_name'] := 'user'; // adjust to suit
Connection.Params.Values['password'] := 'password'; // ditto
Connection.LoginPrompt := False;
Connection.Connected := True;
StoredProc := TFDStoredProc.Create(Nil);
StoredProc.Connection := Connection;
StoredProc.FetchOptions.Items := StoredProc.FetchOptions.Items + [fiMeta];
StoredProc.StoredProcName := 'test';
StoredProc.Prepare;
Param := StoredProc.Params.ParamByName('#ANumber');
Param.Value := 333;
Param := StoredProc.Params.ParamByName('#AName');
Param.Value := 'A';
StoredProc.Active := True;
WriteLn(StoredProc.FieldByName('Number').AsInteger);
WriteLn(StoredProc.FieldByName('Name').AsString);
ReadLn;
end;
begin
try
TestSP;
except
on E: Exception do
Clipboard.AsText := E.Message;
end;
end.

Resources