Gary
Members-
Content Count
137 -
Joined
-
Last visited
Everything posted by Gary
-
I have an app that has been working fine for some time. I use a TFDBatchMove to import csv info from a GPS provider. Recently one vehicle's hardware malfunctioned and now for those 3 days the value in the 'Arrival Time' field has '--' instead of a time value. Not a big deal, I can deal with it in code, the problem is I can't get the TFDBatchMoveTextReader to let this field change to atString. I have changed it everywhere I can think of and even removed and added it back I still get this error when executing the TFDBatchMove "Bad Text value [--] format for mapping item [Arrival Time]. '--' is not a valid time. The changes I have made: TFDBatchMoveTextReader Fields Changed 'Arrival Time' to atString with FieldSize 15. TFDBatchMoveDataSetWriter is set to a Virtual table vtRawDayData. I changed it's field 'ArrivalTime' to TStringFiels Size 15, Made sure it's fieldDefs was set properly as well. csv field is 'Arrival Time' with space vtRawDatDate field is 'ArrivalTime' no space and works fine if I delete the offending rows from the csv I still get the time format error Any ideas short of deleting and redoing the whole chain of components? The offending dates are in September and each week I download the full extent of their allowable data (4 months), The oldest date is in June currently, so even though it's not a big deal to edit out those dates I have to do it each week until I get past September 7-9. Of course if it happens again I would like to already have dealt with it in the app.
-
A little more reading: Documentation: procedure GuessFormat(AAnalyze: TFDBatchMoveAnalyze = [taDelimSep, taHeader, taFields]); Another option is to use the Analyze property. When Analyze is not empty, the GuessFormat method is automatically called by the Execute method. taFields worked for me. Setting the property or passing in the GuessFormat parameter works the same. bmTest2.Analyze := [taFields]; // bmTest2.GuessFormat([taDelimSep]); bmTest2.Execute; If any has problems understanding what's going on maybe my mistakes will help. Firstly what is happening in the WriteValue event. I kept trying to access the Source values in the AItem Var. I looked at the event as saying the AValue var is empty, you need to get the value from the source, perform any conversions and load into AValue. Also, I had no experience with Variants, so when I continually got A/V when accessing the AItem.Source values I thought it had something to do with the way I was access the Variant. What happens and makes perfect sense after a little thought is The AValue is already loaded and the TFDBatchMove has performed the conversion, now you can determine the DataType according to what is expected in the AItem.DestinationField and any further processing can be done. In my case TFDBatchMove was trying to convert an unexpected value '--' to a Time DataType. I had to fix the problem upstream, when the GuessFormat procedure was changing the String field to Time. Wierdo12 helped with the suggestion of resetting the field type after the GuessFormat call. I think that Analyze property or GuessFormat with the taField value may not change the DataType, I was calling it with empty param. We'll see.
-
TFDBatchMove.Analyze.Clear Does not compile. There is an AnalyzeSample Integer property that can be set -1 or 0; Things are working well without it though.
-
@wierdo12 Those examples really helped, thanks! Adding code to the events really slowed the import down, but at least it's working. I'll take out the logging and see how it goes. I didn't realize that GuessFormat actually changed field defs. I was executing it in design mode and that's what was keeping the date field in the dfm as I would save after running in design mode. So these changes worked: Reset my fields after Guess changes them bmFleetDay.GuessFormat; txrdrFleetDayData.DataDef.Fields[13].DataType := atString; txrdrFleetDayData.DataDef.Fields[13].FieldSize := 15; txrdrFleetDayData.DataDef.Fields[26].DataType := atString; txrdrFleetDayData.DataDef.Fields[26].FieldSize := 15; { TODO : Surround with exception handler } result := bmFleetDay.Execute <> 0; procedure TdmLocations.bmFleetDayWriteValue(ASender: TObject; AItem: TFDBatchMoveMappingItem; var AValue: Variant); begin if (AItem.DestField.FieldName = 'StartTime') or (AItem.DestField.FieldName = 'ArrivalTime') then if not VarIsNull(AValue) then if AValue = '--' then begin SiMain.LogMessage(Format('Field: %s Value: %s', [AItem.DestField.FieldName, AValue])); FSkipRecord := True; end; end; Skip record procedure TdmLocations.bmFleetDayWriteRecord(ASender: TObject; var AAction: TFDBatchMoveAction); begin if FSkipRecord then begin SiMain.LogMessage('Skipping Record'); AAction := paSkip; FSkipRecord := False; end; end; I think I'll track skipped records and show user a message with count of corrupted rows Thanks again for the help
-
I had difficulty understanding how to use the events and couldn't find any examples. I found the help to be vague even the parameters. I did find a commercial product from scalabium.com the import component has this event: Declaration property OnBeforeRecordEvent: TBeforeRecordEvent; Description This event allow to define global values for each parsed value before applying to fields. Also here you can skip some row from loading (just by your custom condition). The Fields parameter is a list of parsed field names. The Values parameter is a variant array with parsed value for each field name. To skip a row from loading just assign a False value to Accept parameter. By default the Accept is True. Looks like exactly what I need! I can just skip the offending record, even log and display how many were skipped. 50 EUR with source. I'll post how it goes. Thank you both for the help I will still experiment with your advice
-
Yes, get crazy results if not
-
I have found TFDBatchMove to really be troublesome, probably my ignorance, I would like to be able to control a fields import and am sure one of the properties let you do this but have been unable to find any understandable documentation or examples. It seems that everyone has their own csv import component, so the lack of some public getit project seems odd. I guess I'll have to roll my own as well
-
+1 for JonRobertson & ertank I use UniDac as well and you use the "AddField" Menu selection not the "NewField" Menu. I am always forgetting to set the Options.KeepDesignConnected property as well.
-
@Shrinavat Looks great! Years ago I used X-Data and one thing I miss is the master Detail in grid. Looks like Steema has this, and at an affordable price. While the Rosinsky DBGrid is very capable the show stopper for me are the Dialogs that he has produced. Your end users can customize the grid at runtime as much as you can at design time. Extremely impressive.
-
Not Free only $70.00 and includes source Delphi and C++ Builder VCL components - DBGrid, DBTreeView, DBCheckListBox, StringGrid, HTML Label, HTML ListView (rosinsky.cz)
-
Runtime error with TSVGIconImage compiled in a 64-bit VCL app
Gary replied to vmishka's topic in VCL
Compare your library path for 32 and 64 bit components Tools->Options->Language->Delphi->Library -
Hello all, How do you test if a FDConnection using SQLite is connected to an actual Database? If I drop a FDConnection on a form, set it's DriverName SQLite, leave the Params->Database property empty and connect there is no error. This code shows the "Connected' Message procedure TForm1.Button1Click(Sender: TObject); begin if FDConnection1.Connected then ShowMessage('Connected'); end;
-
Hello all, I am trying to separate my UI from the rest of my application. I want to use an interfaced listener on my main form and pass a reference to it around to parts of the application that need input from the user. I have no problem with the InputBox or MsgDialog as they don't take too many parameters, however I want to use TMSTaskDialog as well (Different listener since requires 3rd party). The problem I am having is that the TaskDialog has so many options that I want to pass a record with all the parameters. I only have a problem with TStrings. I get memory leak on close. Work in progress but here are the relevant parts. TTaskDialogParams = record DisplayedButtons : TPsTaskDialogDisplayedButtons; Title: String; Instruction: string; Content: string; Options: TPsTaskDialogOptions; CustomButtons : TStringList; Icon: TPsTaskDialogIcon; FResultCallBack: TProc<TTaskDialogReturnParams>; procedure Clear; class operator Initialize (out Dest: TTaskDialogParams); class operator Finalize (var Dest: TTaskDialogParams); end; IPsFNCTaskDialogUIListener = interface ['{BA6ABA84-F3EE-4421-856F-42E76C878D3B}'] procedure ExecuteDialog(const Params : TTaskDialogParams); end; procedure TTaskDialogParams.Clear; begin CustomButtons.Clear; CustomButtons.Free; end; class operator TTaskDialogParams.Finalize(var Dest: TTaskDialogParams); begin // Dest.CustomButtons.Free; end; class operator TTaskDialogParams.Initialize(out Dest: TTaskDialogParams); begin Dest.CustomButtons := TStringList.Create; end; In listener I set string params by enumerating through the recordsStringList. procedure TPsFNCTaskDialogUIListener.ExecuteDialog(const Params : TTaskDialogParams); begin SetDialogParams(Params); FTaskDialog.Execute; Params.Clear; // FTaskDialog.CustomButtons.Clear; end; Then show it procedure TPsFNCTaskDialogUIListener.ExecuteDialog(const Params : TTaskDialogParams); begin SetDialogParams(Params); FTaskDialog.Execute; Params.Clear; // FTaskDialog.CustomButtons.Clear; end; Some code in there is things I have tried to no avail. Any help would be appreciated. I tried this before and gave up and used an Interfaced Class instead.
-
From FastMM --------------------------------2023/12/28 22:32:03-------------------------------- A memory block has been leaked. The size is: 84 This block was allocated by thread 0x6A4, and the stack trace (return addresses) at the time was: 9371E6 [System.pas][System][@GetMem$qqri][4960] 938957 [System.pas][System][TObject.NewInstance][18324] 93905A [System.pas][System][@ClassCreate$qqrpvzc][19654] 9F9C30 [System.Classes.pas][System.Classes][Classes.TStringList.Create][8121] 94C231 [FastMM4.pas][FastMM4][UpdateHeaderAndFooterCheckSums$qqrp29Fastmm4.TFullDebugBlockHeader][9153] 94D214 [FastMM4.pas][FastMM4][DebugGetMem$qqri][9731] EA116F [int.PsFNCTaskDialogUIListener.pas][Int.PsFNCTaskDialogUIListener][Psfnctaskdialoguilistener.TTaskDialogParams._op_Initialize][66] 108E6E5 [PsFNCTaskDialogUIListener.pas][PsFNCTaskDialogUIListener][TPsFNCTaskDialogUIListener.SetDialogParams][32] 108E827 [PsFNCTaskDialogUIListener.pas][PsFNCTaskDialogUIListener][TPsFNCTaskDialogUIListener.ExecuteDialog][47] 108F3C9 [USender.pas][USender][TfrmSender.tbtnTaskDialogClick][77] C0CF34 [FMX.Controls.pas][FMX.Controls][Controls.TControl.GetHeight][5512] The block is currently used for an object of class: System.Classes.TStringList The allocation number is: 296325 Current memory dump of 256 bytes starting at pointer address 7E6DB770: 20 B9 9C 00 00 00 00 00 50 B9 30 7F 6C E3 1B 7F 00 00 00 00 00 00 00 00 2C 00 22 00 3D 00 0E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 8C AF 78 80 80 80 80 80 80 80 80 00 00 00 00 51 BB 6D 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88 85 04 00 9F A8 93 00 3C AD 93 00 A2 CC 93 00 F2 E6 08 01 27 E8 08 01 C9 F3 08 01 34 CF C0 00 9D AB C0 00 77 D6 CB 00 F4 B2 C0 00 D4 65 E8 00 A4 06 00 00 A4 06 00 00 02 72 93 00 59 A9 93 00 28 C5 93 00 E2 D3 C0 00 39 8B 93 00 6E 89 93 00 A5 90 93 00 2E 9A CB 00 B3 57 E5 00 ED 92 93 00 45 C0 E8 00 48 00 00 00 B0 04 02 00 CB 3D A4 8E 8C 7C 0C 01 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 . . . . . P 0 l . . . . . . . . . , . " . = . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x . . . . Q m ~ . . . . . . . . . . . . . . . . . . . < . . . . ' . . . . 4 . . w . . e . . . . . . . . r . Y . ( . . 9 . n . . . . W . . E . H . . . . . . = | . . --------------------------------2023/12/28 22:32:03-------------------------------- A memory block has been leaked. The size is: 20 This block was allocated by thread 0x6A4, and the stack trace (return addresses) at the time was: 9371E6 [System.pas][System][@GetMem$qqri][4960] 93A89F [System.pas][System][@NewUnicodeString$qqri][26024] 93AD3C [System.pas][System][@UStrAsg$qqrr20System.UnicodeStringx20System.UnicodeString][26946] 9F6F30 [System.Classes.pas][System.Classes][Classes.TStrings.Create][6729] 9F9C3D [System.Classes.pas][System.Classes][Classes.TStringList.Create][8122] 94D214 [FastMM4.pas][FastMM4][DebugGetMem$qqri][9731] EA116F [int.PsFNCTaskDialogUIListener.pas][Int.PsFNCTaskDialogUIListener][Psfnctaskdialoguilistener.TTaskDialogParams._op_Initialize][66] 108E6E5 [PsFNCTaskDialogUIListener.pas][PsFNCTaskDialogUIListener][TPsFNCTaskDialogUIListener.SetDialogParams][32] 108E827 [PsFNCTaskDialogUIListener.pas][PsFNCTaskDialogUIListener][TPsFNCTaskDialogUIListener.ExecuteDialog][47] 108F3C9 [USender.pas][USender][TfrmSender.tbtnTaskDialogClick][77] C0CF34 [FMX.Controls.pas][FMX.Controls][Controls.TControl.GetHeight][5512] The block is currently used for an object of class: UnicodeString The allocation number is: 296326 Current memory dump of 256 bytes starting at pointer address 7F1BE360: B0 04 02 00 01 00 00 00 02 00 00 00 0D 00 0A 00 00 00 AA 4B E7 F7 80 80 00 00 00 00 A1 FF 1B 7F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5F BF 04 00 E6 71 93 00 57 89 93 00 5A 90 93 00 7F 21 E8 00 12 EE E8 00 31 8A E8 00 1F 40 E8 00 63 40 E8 00 6E EE E8 00 62 DF A0 00 6B 8A 93 00 A4 06 00 00 A4 06 00 00 02 72 93 00 75 89 93 00 A5 90 93 00 E5 21 E8 00 6B 8A 93 00 35 38 E8 00 02 72 93 00 75 89 93 00 A5 90 93 00 F7 10 A8 00 6B 8A 93 00 14 00 00 00 DC E2 E6 00 4C 29 7E 8F 8C 7C 0C 01 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 B3 D6 81 70 00 00 00 00 C1 E9 1B 7F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9F BF 04 00 E6 71 93 00 57 89 93 00 5A 90 93 00 73 35 E3 00 1B 35 E3 00 51 C4 E2 00 13 C5 E2 00 3E 3F E8 00 D1 F1 E8 00 0A 3A E8 00 02 72 93 00 . . . . . . . . . . . . . . . . . K . . . . . . . . . . . . . . . . . . . . . _ . . q . W . Z . ! . . . 1 . . @ . c @ . n . b . k . . . . . . . . r . u . . ! . k . 5 8 . . r . u . . . . k . . . . . . L ) ~ | . . p . . . . . . . . . . . . . . . . . . . . . . . q . W . Z . s 5 . . 5 . Q . . . > ? . . . : . . r . --------------------------------2023/12/28 22:32:03-------------------------------- This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer): 13 - 20 bytes: UnicodeString x 1 69 - 84 bytes: System.Classes.TStringList x 1 Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine "EnableMemoryLeakReporting".
-
Sorry copied same block twice Here is the other part procedure TPsFNCTaskDialogUIListener.SetDialogParams(Params: TTaskDialogParams); begin ClearDialog; FTaskDialog.Title := Params.Title; FTaskDialog.Instruction := Params.Instruction; FTaskDialog.Icon := TTMSFNCTaskDialogIcon(Params.Icon); FTaskDialog.Options := TTMSFNCTaskDialogOptions(params.Options); for var s : String in params.CustomButtons do FTaskDialog.CustomButtons.Add(s); end;
-
@Columbo This is such a great sample app! Fine the way it is but simple enough that you can use it to experiment as you move forward. How about letting your users see your Dino's in the order they want? procedure TfrmDino.Reorder; begin tblPLife.Close; if rgSort.ItemIndex = 0 then tblPLife.SQL[1] := 'ORDER BY record;' else tblPLife.SQL[1] := 'ORDER BY name;'; tblPLife.Open; LoadList; LoadImages; end;
-
Sampling Profiler - DelphiTools
-
Setting designtime components can be very helpful, try this: Open the connection and table. Right click table and select FieldsEditor... Right Click FieldsEditor and select AddAllFields Notice the field objects are added to the form definition (tblPLifename) Click the dropdown of the FieldName on your DBEdits and notice you have a list to choose from, no typing in the field name where simple typo can derail you. Also you can now do this: No more tblPLife.FieldByName('name').AsString
-
I redownloaded the finished program and it works fine! I must have tried one of the others.
-
BTW Congratulations on your first project, and I have to say it's a beauty. Most first projects are dull and boring. However.... Your final project crashes on my computer, it will only run on your system! Reason is a common mistake that has bitten me many times. Your Database path is still hard coded to your system. If you proudly load it on a flash drive (as you should) and show it, it will crash(very embarrassing). See the procedure OpenConnection in my earlier post. You still need it hard coded to work with it in design mode, so the habit I have gotten into is to always set Connected to False and Database to an empty string first thing in the OnCreate event. Then make sure to use runtime function to get Database location before connecting.
-
First param is a string so name needs quotes 'name' You can leave the last param empty, but then they have to match exactly. That works here where you are selecting from a list, however I like to be more forgiving as to case as it can frustrate users if values are capitalized and they just type lowercase. You can eliminate both iSelect and sName and the assignment calls like this: tblPLife.Locate('name', lbxData.Items[lbxData.ItemIndex], [loCaseInsensitive]); Link is for 12.0 change Athens to Alexandria, but in this case no different Data.DB.TDataSet.Locate - RAD Studio API Documentation (embarcadero.com) Data.DB.TLocateOptions - RAD Studio API Documentation (embarcadero.com)
-
Increasing registration count not possible without active maintenance support
Gary replied to Leif Uneus's topic in Delphi IDE and APIs
@Uwe Raabe That sounds good, but it simply is not the case unless something has changed. Some time ago I decided after having paid for the Pro version as a hobbyist, that I would be satisfied with the version I was running and did not renew my subscription. 2 months later I changed my computer name from the default Desktopxxx to a more recognizable name. That invalidated my license, and I needed an install bump. I could not get Embarcadero to do it no matter who I talked to. They eventually allowed me to renew the license at the renew rate instead of full price, even though I was outside the grace period. Of course they backdated it 2 months as well. I consider Delphi ransomware, at least the renewal (Ransom) is not that high. I prefer Delphi to anything else I have tried. It's far easier for someone without a formal computer science education, at least the connection between code and UI. Embarcadero's policy on this is reprehensible and probably illegal. Any company with an install limit policy should be required to allow their users to deactivate/reactivate installs. I have several other software programs that do just that, and even when I have forgotten to do that, a simple email to support to move the license gets a quick response, with a reminder to remember to do it myself 🙂 I even have an original Delphi 2009 Pro CD in the case with Codegear serial numbers on it that I cannot register. -
I added a panel to the top image set align to all right width to 50 Caption -- font color clCream Panel color to your label's font color $0000023F (keep trying for exact match to your brown) and got rid of all borders. Add code to Panel OnClick JonRobertson's suggestion may be better to minimize the form but I don't have experience either. Add to top image OnMouseDown event for dragging procedure TfrmDino.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const SC_DRAGMOVE = $F012; begin if Button = mbLeft then begin ReleaseCapture; Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0); end; end;