Columbo 1 Posted December 14, 2023 (edited) My first program with Delphi 11 Community is coming along slowly but surely. I have set up a database, SQLite, and I am able to connect to it and to the table. I have a number of TEdit controls, (which I call fields), a Memo and a TabbedSheet containing TImage controls on my form. ( the form is frmDino). This is the point where I need help. I would like to be able to set up a query that, using a variable containing a name, will pull one record from the database, based on a match between the name in the variable and the ‘name’ column in the database and then populate the fields (TEdits) with the data from the record found. All names in the database are unique. The first TEdit on my form is edtName and if I can populate this field I think I can do the others. I have searched the internet and found a number of query examples but they are all using queries set up at design time. Can anyone give me example code of a query that is set up at run time as explained in the above paragraph? Comments in the code would be helpful. The database is called dino.db and the table is called ‘dino’. The column in the database to search is called ‘name’. The variable containing the name to search for is called sName. Any help greatly appreciated. Edited December 14, 2023 by Columbo Share this post Link to post
Remy Lebeau 1436 Posted December 14, 2023 1 hour ago, Columbo said: I have searched the internet and found a number of query examples but they are all using queries set up at design time. Can anyone give me example code of a query that is set up at run time as explained in the above paragraph? There should be no difference between setting up a query at design-time vs runtime. So, what are you REALLY having trouble with, exactly? Can you show the actual code that you are having trouble with? All you need is something like this: Query.SQL.Text := 'SELECT Name, OtherFieldsAsNeeded from dino where Name = :PName'; Query.ParamByName('PName').AsString := sName; Query.Open; edtName.Text := Query.FieldByName('Name').AsString; Share this post Link to post
Columbo 1 Posted December 14, 2023 (edited) Thanks Remy. That looks exactly like what I want however, I am getting an error with that code. The only change that I made to your code is, that for testing purposes, I tried to only get the name data from the database. Here is the code: procedure getdbrecord; var sName: String; begin Query.SQL.Text := 'SELECT name FROM dino where name = :PName'; Query.ParamByName('PName').AsString := sName; Query.Open; edtName.Text := Query.FieldByName('name').AsString; I am getting the following errors. E2003 Undeclared Identifier 'Query' E2029 '(' expected but ':=' found I tried adding Query: String under the var but it made no difference. I've only been playing with Delphi 11 for about 2 weeks so I'm still a baby at this stuff. end; Edited December 14, 2023 by Columbo Share this post Link to post
weirdo12 21 Posted December 14, 2023 Drop a TFDQuery component on your form. If it's the first one, it will be named FDQuery1. Set FDQuery1.Connection property to the TFDConnection you use to connect to the SQLite database. Then, in your code, replace Query. with FDQuery1. Share this post Link to post
Remy Lebeau 1436 Posted December 14, 2023 (edited) 1 hour ago, Columbo said: Thanks Remy. That looks exactly like what I want however, I am getting an error with that code. Obviously, you need to adjust the code for your particular setup, which you did not provide ANY details about, so I could only give you a GENERAL solution. What kind of database are you are trying to access? What component(s) are you are using to access that database? 1 hour ago, Columbo said: Here is the code: procedure getdbrecord; var sName: String; begin Query.SQL.Text := 'SELECT name FROM dino where name = :PName'; Query.ParamByName('PName').AsString := sName; Query.Open; edtName.Text := Query.FieldByName('name').AsString; I am getting the following errors. E2003 Undeclared Identifier 'Query' E2029 '(' expected but ':=' found I tried adding Query: String under the var but it made no difference. My example was meant to represent whatever Query component you are actually using on your Form, such as a TQuery, TFDQuery, etc. Use whatever the actual component name really is. Not a String variable. 1 hour ago, Columbo said: I've only been playing with Delphi 11 for about 2 weeks so I'm still a baby at this stuff. Have you read Delphi's documentation on working with Databases? There are whole books on this subject. Edited December 14, 2023 by Remy Lebeau Share this post Link to post
Columbo 1 Posted December 14, 2023 On my form I had TFDConnect (conPlife), FDTable (tblPlife) and Datasource1. I placed a TFDQuery component on my form. When I went to set the Connection property it was already pointing to my connection 'conPLife'. When I run the program it is not flagging any errors but it does not display any data in edtName when run. I thought maybe in the FDQuery1 properties I might have to set Active to True but when I did I got dialog saying: [FireDAC][Phys][SQLite]-306. Command[FDQuery1] text must not be empty. The Active was reset to False. Here is my entire code so far: unit Dinobase_u; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.jpeg, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ComCtrls, System.ImageList, Vcl.ImgList, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteWrapper.Stat, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.DBCtrls, Vcl.Buttons; type TfrmDino = class(TForm) pnlTitlebar: TPanel; Image1: TImage; pnlHeader: TPanel; Image2: TImage; lblName: TLabel; edtName: TEdit; lblMeaning: TLabel; lblPronounce: TLabel; edtPronounciation: TEdit; edtPeriod: TEdit; lblPeriod: TLabel; edtMeaning: TEdit; edtMainGroup: TEdit; lblMainGroup: TLabel; pnlFooter: TPanel; Footer: TImage; edtSize: TEdit; lblSize: TLabel; edtLived: TEdit; lblLived: TLabel; edtDiet: TEdit; lblDiet: TLabel; edtFossils: TEdit; lblFossils: TLabel; memFactfile: TMemo; PLTabSheet: TPageControl; TabSheet1: TTabSheet; SizeComp: TTabSheet; dinoImage: TImage; dinoSize: TImage; conPLife: TFDConnection; tblPLife: TFDTable; DBNavigator1: TDBNavigator; Datasource1: TDataSource; edtRecno: TEdit; lblRecno: TLabel; BitBtn1: TBitBtn; Query: TFDQuery; procedure FormCreate(Sender: TObject); procedure BitBtn1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure getdbrecord; end; var frmDino: TfrmDino; implementation {$R *.dfm} procedure TfrmDino.BitBtn1Click(Sender: TObject); begin Application.Terminate; end; procedure TfrmDino.FormCreate(Sender: TObject); var img1: String; img2: String; begin WindowState := wsMaximized; lblName.Font.Color := TColor(#575); lblMeaning.Font.Color := TColor(#575); lblPronounce.Font.Color := TColor(#575); lblPeriod.Font.Color := TColor(#575); lblMainGroup.Font.Color := TColor(#575); lblSize.Font.Color := TColor(#575); lblLived.Font.Color := TColor(#575); lblDiet.Font.Color := TColor(#575); lblFossils.Font.Color := TColor(#575); edtName.Font.Color := TColor(#575); edtMeaning.Font.Color := TColor(#575); edtPronounciation.Font.Color := TColor(#575); edtPeriod.Font.Color := TColor(#575); edtMainGroup.Font.Color := TColor(#575); edtSize.Font.Color := TColor(#575); edtLived.Font.Color := TColor(#575); edtDiet.Font.Color := TColor(#575); edtFossils.Font.Color := TColor(#575); memFactfile.Font.Color := TColor(#575); lblRecno.Font.Color := TColor(#575); // Set image name img1 := 'Anomalocaris'; img2 := 'Anomalocaris_size'; //TImage.dinoImage.LoadFromFile(img1); //TImage.dinoSize.LoadFromFile(img2); end; //Add a procedure here to clear all TEdits, Memo and Pictures procedure TfrmDino.getdbrecord; //Get record procedure var sName: String; //holds name of dino record to retrieve begin FDQuery1.SQL.Text := 'SELECT name FROM dino Where name = :PName'; FDQuery1.ParamByName('PName').AsString := sName; FDQuery1.Open; //place data into edtName edtName.Text := FDQuery1.FieldByName('name').AsString; end; end. Share this post Link to post
Columbo 1 Posted December 14, 2023 (edited) Quote Have you read Delphi's documentation on working with Databases? There are whole books on this subject. For some reason when I installed Delphi 11 Community the help files, documentation and example were not installed. Click on 'Help' or press 'F1' and nothing. As I mentioned, I looked around the internet and almost all of the examples were at design time. Edited December 14, 2023 by Columbo Share this post Link to post
Remy Lebeau 1436 Posted December 14, 2023 41 minutes ago, Columbo said: When I run the program it is not flagging any errors but it does not display any data in edtName when run. Where are you calling TfrmDino.getdbrecord() from? It is not in the code you have shown. 41 minutes ago, Columbo said: I thought maybe in the FDQuery1 properties I might have to set Active to True but when I did I got dialog saying: [FireDAC][Phys][SQLite]-306. Command[FDQuery1] text must not be empty. The Active was reset to False. You can't activate the query before you have configured it. Sounds like you hadn't defined the SQL for it yet before trying to use it. 41 minutes ago, Columbo said: Here is my entire code so far: All of that setup stuff you are doing in the Form's OnCreate event should be done using the Object Inspector at design-time instead. 43 minutes ago, Columbo said: For some reason when I installed Delphi 11 Community the help files, documentation and example were not installed. Click on 'Help' or press 'F1' and nothing. As I mentioned, I looked around the internet and almost all of the examples were at design time. Start with this: https://docwiki.embarcadero.com/RADStudio/en/FireDAC Share this post Link to post
tgbs 16 Posted December 14, 2023 And once you manage to call getdbrecord, you'll still need to fill in the meaning of sName, now it's unknown Share this post Link to post
Columbo 1 Posted December 14, 2023 Thanks Remy, Quote All of that setup stuff you are doing in the Form's OnCreate event should be done using the Object Inspector at design-time instead. I you are referring to the setting of the font colors for the labels and TEdits, the colors that I need are not available in the font menu list and the only way that I could get the color that I want was to do it that way. I tried entering the custom color to the list but it wouldn't accept it. As tgbs pointed out, I hadn't assigned the name that I wanted to search for in the variable sName. I did that and I believe that it is working now. Thank you for all of your help on this. Very much appreciated. As I get more familiar with Delphi I am sure that my coding will improve. Share this post Link to post
Columbo 1 Posted December 14, 2023 @tgbs Thank you. I missed that and I believe that I now have it working. Share this post Link to post
Columbo 1 Posted December 14, 2023 Apparently I still have one problem. When the TEdit (edtName) is populated the text is highlighted like it is selected. Is there a way to prevent this,... just normal text? Share this post Link to post
Gary 18 Posted December 14, 2023 @Columbo Glad you did not give up! The control that is selected (Focused) when your app runs is determined by it's TabOrder. You can see this as a property in the Object Inspector. To reorder them you can change them manually or right click the edit box and select TabOrder... to arrange all components. Share this post Link to post
Remy Lebeau 1436 Posted December 14, 2023 (edited) 2 hours ago, Columbo said: I you are referring to the setting of the font colors for the labels and TEdits Yes. 2 hours ago, Columbo said: the colors that I need are not available in the font menu list and the only way that I could get the color that I want was to do it that way. I tried entering the custom color to the list but it wouldn't accept it. You can enter a custom color value directly into the property editor, you just have to use decimal notation (drop the #) or hex notation, ie use '575' or '$23F' (without the quotes). Even in your code, don't use '#' for color values. '#' is used to specify a Char constant, and a character is not a color. Use TColor(575) or TColor($23F) in code, or more expressive TColor(RGB(63, 2, 0)) or TColor(RGB($3F, $2, $0)). 1 hour ago, Columbo said: Apparently I still have one problem. When the TEdit (edtName) is populated the text is highlighted like it is selected. Is there a way to prevent this,... just normal text? It is highlighted because that TEdit has the input focus at the time. Simply put the focus somewhere else, such as the Form itself. Also, make sure the Form's ActiveControl property is not set at design-time (or, set it to the UI control you actually want to have the focus initially). Edited December 15, 2023 by Remy Lebeau Share this post Link to post
Columbo 1 Posted December 14, 2023 Thanks Gary, All of these TEdits are Read Only and I experimented a bit and found that I could prevent this by setting the AutoSelect property to False. Although I have a good start on this program I still have a long way to go. I will send you the finished program when it is done. Thanks for you encouragement. Cheers Share this post Link to post
Columbo 1 Posted December 14, 2023 Thanks again Remy. Quote You can enter a custom color directly into the property editor, you just have to use hex notation instead of decimal, ie use $23F instead of #575, etc. Is there a list of hex colors somewhere in the net? If I were going to use a color like the dark brown that I am using in my program, I know that it is #502E0F or RGB(80,47,15) but how would I know that is $23F ? Thanks again. Share this post Link to post
Remy Lebeau 1436 Posted December 15, 2023 (edited) 43 minutes ago, Columbo said: Is there a list of hex colors somewhere in the net? It is raw RGB, use whatever values you want for the R, G, B channels. 43 minutes ago, Columbo said: If I were going to use a color like the dark brown that I am using in my program The code you showed is not using a dark brown, it's more like a red-ish brown. 43 minutes ago, Columbo said: I know that it is #502E0F or RGB(80,47,15) RGB(80,47,15) is actually #502F0F in paint programs (not to be confused with the '#xxxx' character constant notation in Pascal!). 43 minutes ago, Columbo said: but how would I know that is $23F ? It is not. Completely different RGBs. TColor(#575) is decimal 575 is hex $23F (use any calculator to verify that), and TColor($0000023F) is R=63($3F) G=2($02) B=0($00). RGB(80,47,15) would be TColor($0F2F50). If you want to set that in code, you can use the actual RGB() function: edtLived.Font.Color := TColor(RGB(80,47,15)); BTW, you may want to have a look at the TControl.ParentFont property. Instead of setting the Font.Color on every control individually, you can set it once on their parent instead, and then have the controls inherit it via ParentFont. Edited December 15, 2023 by Remy Lebeau Share this post Link to post
Gary 18 Posted December 15, 2023 @Columbo FWIW Listen to Remy! He's been around for a while, even part of the old Team 'B' I believe. He's one of the few experienced programmers that actually help newbies, and that takes patience. He helped me some time ago with some Interbase deployment issues that looking back were so simple yet at the time I just couldn't get it. Weirdo12 seems to be experienced with Database's especially Firebird, FireDac and Zeos so read his posts closely as well. I've learned a lot just reading them 🙂 The Database landscape has changed drastically since DBase and the Borland Database Engine. Everything is in the cloud, 3 Tier and Rest and it is good to embrace this change for Enterprise applications, but for the kind of Home and friend use that you and I do, Delphi offers much simpler 2 Tier or even direct access solutions. For example, you can use a DBEdit instead of a plain edit and connect it to the "Name" field in your Query and never have to worry about 'Loading data' into controls. There are several Data Aware controls that you just set their DataSource, or additionally a particular field and the data just display's. You can right click on the TFDQuery in your designed and if you have your connection active you can use the 'Parameters' tab to set a value and see the result at design time, and more.. Much of what you are doing looks like a console application. Everything is Visual now. Like Remy said set up your UI in the Object inspector, look for properties, there is a WindowState property set it in the designer to wsMaximized not in code (Check out the Position property of the form). In the last projects you posted what you are trying to do can be done in the designer and only 1 or 2 lines of actual code. While that may not sound exciting if you want to write code, you can whip out a simple Home use DB application that way in a matter of minutes, very exciting! BTW online help for Delphi 11 can be found here: https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Main_Page Share this post Link to post
Stano 143 Posted December 15, 2023 8 hours ago, Columbo said: Thanks Gary, All of these TEdits are Read Only and I experimented a bit and found that I could prevent this by setting the AutoSelect property to False. Although I have a good start on this program I still have a long way to go. I will send you the finished program when it is done. Thanks for you encouragement. In this case, put all affected components on the panel. Then set MyPanel.Enabled := False; Remark: For bulk setting of component properties on forms, I recommend to create a recursive function and deal with it there. be direct or create a list of components and work with it Share this post Link to post
Columbo 1 Posted December 15, 2023 Quote n this case, put all affected components on the panel. Then set MyPanel.Enabled := False; Thanks Stano. Share this post Link to post
Columbo 1 Posted December 15, 2023 (edited) During my learning process with this program that I am working on I have been able to figure out and resolve a number of errors but here is one that I am really stuck on. I have been working on pulling the data from my DB and filling in my TEdits with the data from the record. For testing purposes I am only working with 1 record. I pull the data from the database using: FDQuery1.SQL.Text := 'SELECT record,name FROM dino Where name = :PName'; FDQuery1.ParamByName('PName').AsString := sName; FDQuery1.Open; //place data into edtName edtRecno.Text := FDQuery1.FieldByName('record').AsString; edtName.Text := FDQuery1.FieldByName('name').AsString; This is working ok. Being a bit cautious I have been adding the columns 1 at a time and running the program after each addition to be sure there are no errors. There are 10 columns (fields) in the database which are: record, name, meaning, pronounce, period, size, lived, diet, fossils, factfile. Everything works perfectly except when I add the 'group' column and then it flags an error. If I remove that 1 column from the query all of the others work fine. The error that I am getting is: Dinobase_p [FireDAC][Phys][SQLite]Error: near 'group'; syntax error. I checked the column name in the database and it is correct. All that I am doing is adding the 'group' to the query the same as I did for the other 9 TEdits but as soon as I do,... ERROR! Here is my entire code: unit Dinobase_u; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Imaging.jpeg, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ComCtrls, System.ImageList, Vcl.ImgList, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef, FireDAC.Stan.ExprFuncs, FireDAC.Phys.SQLiteWrapper.Stat, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, Vcl.DBCtrls, Vcl.Buttons; type TfrmDino = class(TForm) pnlTitlebar: TPanel; Image1: TImage; pnlHeader: TPanel; Image2: TImage; lblName: TLabel; edtName: TEdit; lblMeaning: TLabel; lblPronounce: TLabel; edtPronounciation: TEdit; edtPeriod: TEdit; lblPeriod: TLabel; edtMeaning: TEdit; edtMainGroup: TEdit; lblMainGroup: TLabel; pnlFooter: TPanel; Footer: TImage; edtSize: TEdit; lblSize: TLabel; edtLived: TEdit; lblLived: TLabel; edtDiet: TEdit; lblDiet: TLabel; edtFossils: TEdit; lblFossils: TLabel; memFactfile: TMemo; PLTabSheet: TPageControl; TabSheet1: TTabSheet; SizeComp: TTabSheet; dinoImage: TImage; dinoSize: TImage; conPLife: TFDConnection; tblPLife: TFDTable; DBNavigator1: TDBNavigator; Datasource1: TDataSource; edtRecno: TEdit; lblRecno: TLabel; BitBtn1: TBitBtn; FDQuery1: TFDQuery; edtSearch: TEdit; btnSearch: TButton; lblSearch: TLabel; procedure FormCreate(Sender: TObject); procedure BitBtn1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure getdbrecord; end; var frmDino: TfrmDino; implementation {$R *.dfm} procedure TfrmDino.BitBtn1Click(Sender: TObject); begin Application.Terminate; end; procedure TfrmDino.FormCreate(Sender: TObject); var img1: String; img2: String; begin WindowState := wsMaximized; getdbrecord; // Set image name img1 := 'Anomalocaris'; img2 := 'Anomalocaris_size'; //TImage.dinoImage.LoadFromFile(img1); //TImage.dinoSize.LoadFromFile(img2); end; //Add a procedure here to clear all TEdits, Memo and Pictures procedure TfrmDino.getdbrecord; //Get record procedure var sName: String; //holds name of dino record to retrieve begin sName := 'Anomalocaris'; FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,group,period,size,lived,diet,factfile FROM dino Where name = :PName'; FDQuery1.ParamByName('PName').AsString := sName; FDQuery1.Open; //place data into edtName edtRecno.Text := FDQuery1.FieldByName('record').AsString; edtName.Text := FDQuery1.FieldByName('name').AsString; edtMeaning.Text := FDQuery1.FieldByName('meaning').AsString; edtPronounciation.Text := FDQuery1.FieldByName('pronounce').AsString; edtPeriod.Text := FDQuery1.FieldByName('period').AsString; edtMainGroup.Text := FDQuery1.FieldByName('group').AsString; edtSize.Text := FDQuery1.FieldByName('size').AsString; edtLived.Text := FDQuery1.FieldByName('lived').AsString; edtDiet.Text := FDQuery1.FieldByName('diet').AsString; memFactfile.Text := FDQuery1.FieldByName('factfile').AsString; end; end. Edited December 15, 2023 by Columbo Share this post Link to post
Stano 143 Posted December 15, 2023 (edited) GROUP is a reserved word. See "GROUP BY". That's why it doesn't work. Reserved words cannot be used in MetaData. You're supposed to have TDBEdit instead of TEdit. It seems to me that someone has written that to you here as well. Unless you didn't want to use DB components. I had such a period. I just had everything handled centrally using a class. If you're not going to have it that way, you'll have to take care of: retrieving data from the DB updating data e.g. changing a record storing the data in the DB It's a lot of extra unnecessary work. Plus a high probability of errors! One more addition. Use only capital letters of the English alphabet everywhere in the DB (MetaData). In the Delphi code, write the whole expression for Query.Sql.Text in uppercase as well. The reason for this is that some DBs require it. That's why I have set this as a default for myself. What if the DB changes? That's how I've seen it with all the pros as well. Edited December 15, 2023 by Stano Share this post Link to post
Columbo 1 Posted December 15, 2023 Thanks again Stano. I must look to see a list of all of the keywords in Delphi. Yes, using DBEdit was mentioned before but I had spent a fair of time on the design and, at least for now, I didn't want to have to change everything. If I can get this working I will change them to DBEdits later. I know that it would probably be easier to do it now. Thanks again. Share this post Link to post
Remy Lebeau 1436 Posted December 15, 2023 (edited) 7 hours ago, Columbo said: The error that I am getting is: Dinobase_p [FireDAC][Phys][SQLite]Error: near 'group'; syntax error. 'group' is a reserved keyword in SQL. To use a reserved keyword in an object name, like a column field, you have to surround the name with square brackets, eg: FDQuery1.SQL.Text := 'SELECT record,name,meaning,pronounce,[group],period,size,lived,diet,factfile FROM dino Where name = :PName'; Edited December 16, 2023 by Remy Lebeau Share this post Link to post
Columbo 1 Posted December 15, 2023 (edited) Thanks Remy, Stano pointed that out. I changed 'group' to maingroup at it is working now. I have a TEdit as a 'Search' box and a 'Go' button. I was able to figure out how to be able to use the button or to press the <ENTER> key to invoke the search and that works well now. My next step is to figure out how to load an image from a folder into a TImage control at runtime. The images have the same name as the variable 'sName' which is the pulled from the 'name' column in the record that has been selected from the DB. Example: sName + ".jpg'; // the first record in the DB would set the image name to 'Anomalocaris.jpg'. The image is located in D:\Delphi_11_Community\MyProjects\Dinobase\dino_images . I think that it is loaded with 'LoadFromFile()' but I have to see how to code that. Edited December 15, 2023 by Columbo Share this post Link to post