

JonRobertson
Members-
Content Count
289 -
Joined
-
Last visited
-
Days Won
7
Everything posted by JonRobertson
-
I do the same thing with ADO, preferring MSOLEDBSQL if it is installed. Although not my actual code, the code below does the job. In my case, I dynamically update the ADO Connection String before connecting to SQL Server. function GetADOProvider: string; const PREFERRED_SQL_PROVIDER = 'MSOLEDBSQL'; SQLOLEDB_SQL_PROVIDER = 'SQLOLEDB.1'; begin var lstProviderNames := TStringList.Create(); try GetProviderNames(lstProviderNames); if lstProviderNames.IndexOf(PREFERRED_SQL_PROVIDER) > -1 then Result := PREFERRED_SQL_PROVIDER else Result := SQLOLEDB_SQL_PROVIDER; finally lstProviderNames.Free(); end; end;
-
I wouldn't say FireDAC succeeded ADO/dbGo. I would agree that FireDAC succeeded dbExpress. As far as I know, FireDAC uses SQL Native Client, which Microsoft deprecated, I think in 2019. Microsoft no longer updates it or supports it and Native Client is not fully compatible with newer versions of SQL Server. There is a QC to add support for MSOLEDBSQL to FireDAC, but that QC was closed. RSP-32494
-
When you say "manipulate table", do you mean insert/update/delete data in the table? If so, nothing special is needed. Use the Insert, Edit, Post, and Delete methods of TADODataSet. If you are modifying the structure/schema of a table, you can do that with SQL statements using TADODataSet or TADOQuery. In that scenario, I recommend setting the ExecuteOptions property to [eoExecuteNoRecords]. The CommandType property specifies whether CommandText contains SQL Text (cmdText), the name of a table (cmdTable), the name of a stored procedure (cmdStoredProc), or the filename of a dataset persisted on disk (not in a database). Best practice is to avoid cmdTable, or the equivalent component TADOTable, as that doing a SELECT * FROM and will always retrieve all rows and all columns. Best practice is to limit the SELECT to only the columns needed.
-
Copy your patched FMX.Platform.UI.Android.pas to the same folder containing your project. You could also add it to the project. Delphi will compile and use the one in your project folder rather than the version shipped with Delphi. If you need to use this for multiple projects, or later need to patch another FMX unit, you could create a folder named something like FMXOverrides. I don't use FMX but I've had a VCLOverrides folder for years.
-
CreateSemaphore/FileLock etc
JonRobertson replied to hsvandrew's topic in Algorithms, Data Structures and Class Design
I used CodeSite Express (and later upgraded to full version) for years at a previous job. It worked well for our needs. @hsvandrew CodeSite Express can be installed via GetIt Package Manager. There are a couple others that I came across that you may want to investigate: loggerpro and SynLog There is also SmartInspect. Although not free, there is a trial version available. -
Network scan in Delphi (Windows), get MAC addresses
JonRobertson replied to ErikT's topic in Network, Cloud and Web
Age is relative. Fwiw, I'm 51 and started "hacking" (and learning) BASIC on a Commodore PET in 1981. -
Network scan in Delphi (Windows), get MAC addresses
JonRobertson replied to ErikT's topic in Network, Cloud and Web
I disagree. In my opinion, hack/hacker/hacking has never been a bad thing. Hacking is a terrific way to learn, especially for self-taught individuals such as myself. Sure, people have done a great deal of malice, which is unfortunate. And believing that all hackers are malicious is an unfortunate side effect of the harm caused by others. -
Network scan in Delphi (Windows), get MAC addresses
JonRobertson replied to ErikT's topic in Network, Cloud and Web
You could try another set of Internet components, such as ICS. I have not needed low-level Internet functionality for a while. But I used to use ICS quite a lot. Internet Component Suite ICS is available for VCL and FMX. In recent versions of Delphi, it can also be installed via GetIt Package Manager. -
Network scan in Delphi (Windows), get MAC addresses
JonRobertson replied to ErikT's topic in Network, Cloud and Web
I suggest searching using a search engine. You will find several results. The most common approach is to calculate the IP range for your LAN using the computer's IP address and subnet mask. Once you know the range of IP addresses for the LAN, ping each IP address. For better performance, use multiple threads to ping several addresses simultaneously. Note that just because ping does not receive a response does not mean that there is not a device at that address. Not all devices respond to ping requests. If you want to "search deeper", you could scan a port range for each IP address. Although that would take significantly longer. If you are looking for a particular device or application, you may be able to find out what it uses for network discovery, such as Apple's Bonjour. If you are wanting to discover your own applications running on other machines within the network, take a look at UDP broadcasts (servers and listeners). -
No difference. It is either personal preference or, in a professional setting, a team policy or design decision. I prefer field names to be "CamelCase". For example, FirstName. I prefer this for variables and class members as well.
-
https://docwiki.embarcadero.com/ is also down.
-
Not impossible. If the "system buttons" to minimize, maximize, and close the application are not important, set the form's BorderStyle property to bsNone in the Object Inspector. Note that the window will not be movable or sizable without some additional code. You could paint the caption bar yourself, although that is not trivial. See StackOverflow for one possible answer: Change the color of the applications title bar I suggest experimenting more with CustomTitleBar and TTitleBarPanel. Use TTitleBarPanel instead of TPanel for pnlTitlebar, then set CustomTitleBar.Control to your TTitleBarPanel. Unfortunately I don't have specific advice on property values for CustomTitleBar. But experimenting is a great way to learn. You could start a new VCL Project and experiment with an empty form.
-
I have not explored the CustomTitleBar parameter or TTitleBarPanel component until today. Columbo's project gave me an opportunity to do so. When using an image that spans the width of the window, it covers TTitleBarPanel CustomButtons. I suspect buttons would need to be painted in OnPaint and "clicking" them handled in an OnClick handler. But I am still exploring those options... However, moving the form using the mouse is possible by adding an OnMouseDown event handler to the Image1 component: procedure TfrmDino.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const sc_DragMove = $F012; begin ReleaseCapture; Perform(wm_SysCommand, sc_DragMove, 0); end;
-
The easy way is via frmDino.BorderStyle. Forms.TFormBorderStyle Value Meaning bsDialog Not resizable; no minimize/maximize menu bsSingle Not resizable; minimize/maximize menu bsNone Not resizable; no visible border line bsSizeable Standard resizable border bsToolWindow like bsSingle but with a smaller caption bsSizeToolWin like bsSizeable with a smaller caption
-
The code below assigned ItemIndex + 1 to iSelect, then assigned lbxData.Items[iSelect] to selectedItem. In the source you posted, selectedItem is not used for anything. However, that assignment does result in a "List index out of bounds" error if you click on the last item in the list box. iSelect := lbxData.ItemIndex +1; //Get the item number of the slected item in the listbox. Add 1 because item list starts at zero (0). lboxNum := iSelect -1; selectedItem := lbxData.Items[iSelect]; This attached version builds the paths for the DB and images using Application.ExeName, as Remy suggested. It shows an alternate way of building the full path for both images. It still expects your database and image folders to be in the same folder as Dinobase_p.exe. Jon Dinobase_u.pas
-
That works if you always run it from the location where Delphi writes the .EXE. If you want it use it on another machine or give it to your friends, that doesn't work so well.
-
You have a misunderstanding of Delphi list controls. Nearly everything in Delphi is zero indexed. Strings (UnicodeString, AnsiString, etc) are a notable exception. iSelect := lbxData.ItemIndex +1; //Get the item number of the slected item in the listbox. Add 1 because item list starts at zero (0). You use iSelect to retrieve the selected item from lbxData: selectedItem := lbxData.Items[iSelect]; If the last item in the list is selected, an "Index out of bounds" error will occur. Since the "item list starts at zero", you need to use a zero-based index for lbxData.Items[]. I wanted to show how you can use the dataset's events to your advantage. I have attached a modified Dinobase_u.pas/.dfm that implements TFDTable.AfterScroll to eliminate duplicating code/work in other methods. Dinobase_u.zip
-
The first thing to change is to set conPLife.Connected to False before building the project. When Dinobase launches and loads your main form, it is attempting to immediately open the database connection because Connected is set to True at design-time. Setting Connected to True is very useful while you are developing, but it needs to be set to False before building a project that will run anywhere except on your development machine. This is a pain and there are ways to automate it. But that is a different post. ;) I would have expected removing the path in Params.Database to resolve the path issue. But I do not have experience with SQLite or FireDAC. If you are certain the database will always be in the same folder as the .EXE, the path can be adjusted before opening the database. Here is one approach, which I put at the top of FormCreate: procedure TfrmDino.FormCreate(Sender: TObject); //Form creation begin conPLife.Params.Database := IncludeTrailingPathDelimiter(TDirectory.GetCurrentDirectory) + conPLife.Params.Database; conPLife.Connected := True; tblPLife.Active := True; Note that System.IOUtils needs to be added to your uses clause to resolve the reference to TDirectory. This is still not ideal, but it works for your first project. An ideal solution would be to store the database and images in a folder intended for app data, such as TPath.GetPublicPath (typically C:\ProgramData). There are other folders that you could use. Through the years, Microsoft has changed gears on app data folders a few times. After that, I copied the dino_images and dino_size folders from your earlier zip to my project folder and was able to run your project, navigate the db, and see the images. I have a couple of quick suggestions from a brief look at your form's code. Your Exit button calls "self.Close". "self." is not needed here. There are times that it is useful for clarity, but not necessary. The btnExitClick method is a member of TfrmDino, so calling Close calls the Close method of TfrmDino. You declared sName, recno, and recnum as globals in the var section of the unit. You should get in the habit of declaring "form" related variables as members of the form, as private members when possible. (Although it seems recno and recnum are not currently needed.) private sName: String; Lastly, pay attention to warnings from the compiler: [dcc32 Warning] Dinobase_u.pas(126): W1036 Variable 'iSelect' might not have been initialized How should lbxDataClick "behave" if lbxData.ItemIndex is not greater than -1? Jon
-
Same for me. I suspect your code is still hardcoding the path to the database.
-
Take a look at the AfterScroll event of the dataset. If the code that loads an image is not already a separate function/procedure, move it to one. Then call that from the AfterScroll event. https://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TDataSet.AfterScroll
-
He meant don't use a modified TDBNavigator. You said at some point something about adding your own buttons. If the buttons provided by TDBNavigator provide the functionality you are wanting but you weren't able to get it to work as intended, that can be corrected. If you want additional buttons to provide functionality that is not built into TDBNavigator, that is a different story. For what you are doing, you should get the project working using single dataset component and a single datasource component. Based on your posts, it seems as though you may be using multiple datasets. I would use a separate dataset to load the picture. But that is easier to implement once the project works using a single dataset.
-
That code would add sName. But sName may be an empty string ('') at that point of code execution. Have you confirmed that sName contains a value when LoadFromFile is called? Have you set a breakpoint to examine sName before LoadFromFile is called? Or added a ShowMessage(sName) before calling LoadFromFile?
-
I was able to get his project working on my machine. I don't use SQLite either. So as a test I tried several combinations of character case on the table name and they all worked. Table names (and likely any object name) do not seem to be case sensitive. His project also works with the database connection and query assigned 100% in code, with zero design-time configuration.
-
His project was building to Project\Win32\Debug and dat2.sqlite was in the root Project folder.
-
Delphi 12: Install Packages inconsistency?
JonRobertson replied to PeterPanettone's topic in Delphi IDE and APIs
I disagree. No reason for the IDE to load packages if they won't be needed by my next action. My next action could be closing the IDE or loading a different project that also does not use all of the default packages. The only issue that occurs to me is if my next action was to create a new form, without loading or starting a project first. In that case, I may be confused why a package is not loaded that I would expect to be loaded. But I wouldn't want to change the design or code of a form without having a project loaded. There is a lot of IDE functionality unavailable in that scenario.