Jump to content
Registration disabled at the moment Read more... ×

dormky

Members
  • Content Count

    149
  • Joined

  • Last visited

Everything posted by dormky

  1. dormky

    MyDAC copy to another DB

    So I need to copy the contents of one table to another database. But it seems changing the Connection on a TMyQuery erases the data stored in it. Any alternatives that do not require creating a TMyTable ?
  2. dormky

    MyDAC copy to another DB

    You mean that MySQL can transfer data directly from one server to the other ? I'm not talking about doing replication, this is for select rows
  3. dormky

    MyDAC copy to another DB

    The databases aren't on the same server. Obviously if that was the case this would be trivial
  4. dormky

    Anonymous instance methods

    Figured that anonymous methods on instance procedures such as OnClick was actually possible with this little tick : type // Allows instance anonymous procs by giving it to the constructor here and giving OnSender to the OnClick event for example // You need to give the instance on which the OnSender will be attributed so the object gets garbage-collected. // MyButton.OnClick := TAnonProc.Create(MyButton, procedure (Sender: TObject) begin /* */ end).OnSender; TAnonProc = class(TComponent) proc: TProc<TObject>; constructor Create(AOwner: TComponent; AProc: TProc<TObject>); reintroduce; procedure OnSender(Sender: TObject); end; constructor TAnonProc.Create(AOwner: TComponent; AProc: TProc<TObject>); begin inherited Create(AOwner); proc := AProc; end; procedure TAnonProc.OnSender(Sender: TObject); begin if Assigned(proc) then proc(Sender); end;
  5. Consider : procedure Test(); var number: single; begin number := 0.96493138416; // Too long for a single precision // Assert(number = 0.96493138416); // Will fail, normal number := RoundTo(number, -3); Assert(number = 0.965); Fails end; Here number is supposed to be a value I'm getting from the data I'm running the test on. Due to binary representation the number will never be exactly correct, however trying to Assert with the value given by the debugger doesn't work either. So how am i meant to assert on floats ? Thanks.
  6. dormky

    How do I assert a single ?

    Ended up landing on this, works fine for my purpose : procedure AssertFloat(const value, should: Extended); begin Assert(Abs(value - should) < 0.00001); end;
  7. In Data.DB, the dataset events are defined as TDataSetNotifyEvent = procedure(DataSet: TDataSet) of object; This means that such code as MyTableTest.BeforeDelete := procedure (d: TDataSet) begin LogTableOperation('MyTableTestBeforeDelete'); end; not valid. Is there anyway of casting this ? I'd rather not define a procedure in my data module for every event of every table...
  8. This is related : https://stackoverflow.com/questions/4652958/is-there-a-way-to-log-every-gui-event-in-delphi I wrote this unit based on it, it might give you ideas. Note that this is not perf-tested and is probably quite bad in that regard with all the looping of rtti info. Also might crash if you have cases I have not covered when interpreting RTTI. unit UEventLogger; // See https://stackoverflow.com/questions/4652958/is-there-a-way-to-log-every-gui-event-in-delphi // Call TEventLogger.AddEventInterceptors in every FormCreate. // Since TEventLogger is a compnent, it gets destroyed when his parent gets destroyed. interface uses EEvents, EException, Classes, Controls, Generics.Collections, Rtti; type OnEventLoggerEvent = reference to procedure(const event: string; const controlName: string); TEventLogger = class(TComponent) private EventName: string; originalEvent: TNotifyEvent; procedure HandleEvent(Sender: TObject); constructor Create(Control: TControl; EventName: string; originalEvent: TNotifyEvent); class procedure RecurseControls(Control: TControl; ExaminedControls: TList<TControl>; context: TRttiContext); public class procedure AddEventInterceptors(Control: TControl); class procedure RegisterEurekaLogWriter(); class var logs: TArray<string>; class var OnEvent: OnEventLoggerEvent; end; implementation uses TypInfo, SysUtils, Windows; type TStupidEL = class procedure OnReproduceRequest(AExceptionInfo: TEurekaExceptionInfo; var AReproduceText: String; var ACallNextHandler: Boolean); end; var h: TStupidEL; constructor TEventLogger.Create(Control: TControl; EventName: string; originalEvent: TNotifyEvent); begin inherited Create(Control); self.EventName := EventName; self.originalEvent := originalEvent; end; procedure TEventLogger.HandleEvent(Sender: TObject); begin // Log the event : datetime - event name - control name logs := logs + [FormatDateTime('dd/mm/yy hh:nn:ss.zzz', Now()) + ' - HandleEvent ' + EventName + ' on ' + (Sender as TControl).Owner.Name+'.'+(Sender as TControl).Name]; if Assigned(OnEvent) then OnEvent(EventName, (Sender as TControl).Owner.Name+'.'+(Sender as TControl).Name); // Forward to the original handler originalEvent(Sender); end; class procedure TEventLogger.RecurseControls(Control: TControl; ExaminedControls: TList<TControl>; context: TRttiContext); var theTypeInfo: TRttiInstanceType; theProperty: TRttiProperty; interceptor: TEventLogger; theEvent: TNotifyEvent; theValue: TValue; field: TRttiField; newControl: TControl; instanceType: TRttiInstanceType; begin ExaminedControls.add(Control); theTypeInfo := context.GetType(Control.ClassInfo) as TRttiInstanceType; for theProperty in theTypeInfo.GetProperties do begin if (not theProperty.IsWritable) then continue; if (not (theProperty.PropertyType.ToString.StartsWith('TNotifyEvent'))) then continue; if (theProperty.Name = 'OnClick') or (theProperty.Name = 'OnDblClick') then begin theValue := theProperty.GetValue(Control); theEvent := nil; if not theValue.IsEmpty then theEvent := theValue.AsType<TNotifyEvent>(); if Assigned(theEvent) then begin interceptor := TEventLogger.Create(Control, theProperty.Name, theEvent); theProperty.SetValue(Control, TValue.From<TNotifyEvent>(interceptor.HandleEvent)); end; end end; try for field in theTypeInfo.GetFields do begin if field.name.StartsWith('F') then continue; // All the private F fields ; we're only interested in our boutons and things like that. if field.FieldType = nil then continue; // Undefined types, like pointers (^TQCTestAll) if field.FieldType.TypeKind = tkClass then begin instanceType := field.FieldType As TRttiInstanceType; if instanceType.MetaclassType.InheritsFrom(TControl) then begin newControl := nil; theValue := field.GetValue(Control); if not theValue.IsEmpty then newControl := theValue.AsType<TControl>; if Assigned(newControl) then if not ExaminedControls.Contains(newControl) then RecurseControls(newControl, ExaminedControls, context); end; end; end; except on E: EAccessViolation do // For some reason we can get an AccessViolation while looping through the fields. Seemed to happen // on ParentControl. end; end; class procedure TEventLogger.AddEventInterceptors(Control: TControl); var examinedObjects: TList<TControl>; begin examinedObjects := TList<TControl>.Create(); TEventLogger.RecurseControls(Control, examinedObjects, TRttiContext.Create()); examinedObjects.Free; end; procedure TStupidEL.OnReproduceRequest(AExceptionInfo: TEurekaExceptionInfo; var AReproduceText: String; var ACallNextHandler: Boolean); begin AReproduceText := sLineBreak + String.join(sLineBreak, TEventLogger.logs); TEventLogger.logs := []; end; class procedure TEventLogger.RegisterEurekaLogWriter(); begin RegisterEventReproduceRequest(h.OnReproduceRequest); end; end.
  9. dormky

    Suggestions for new vendor of a delphi app?

    If you're open-source, you need to sell something else (training, resources, support, etc...)
  10. I've tried calling Application.ProcessMessages from a thread, that didn't work. Had to try it lol. My goal is to have a loading gif playing while the work is ongoing. The work cannot be moved out of the main thread, as this would require rewriting multiple thousands of lines of code, which is sure to create bugs (especially as this deals with COM ports). Any ideas ?
  11. I'm 100% agreeing with you. Management doesn't. Management wants a pretty loading icon without actually putting in the work 🙂 Imo the windows cursor does a perfectly fine job, we're talking ~10s loading time here.
  12. I thought about this, but dismissed the idea as this would mean the loading gif is dissociated from the window in which the loading occurs. If the window gets resized, moved, minimized or simply if the user opens up another program in that screen space that form is in trouble (ie will not be kept visible only when the working window is visible, and centered within it).
  13. Going around a bunch of files inserting calls to ProcessMessages in mostly random places (the work is not deterministic) seems like a magnificient way of shooting both feet at the same time 😕
  14. dormky

    Introducing TRange<T>

    For most cases, I would recommend using the delphi-provided libraries instead of rolling your own, see https://docwiki.embarcadero.com/Libraries/Sydney/en/System.Math.InRange
  15. So I just made a form where the user can double-click in a list to make a selection, with this simplifed code : procedure TTestForm.DBGrid1DblClick(Sender: TObject); begin ModalResult := mrOK; Close(); end; However in the call to Close, there's this code : procedure TCustomForm.Close; var CloseAction: TCloseAction; begin if fsModal in FFormState then ModalResult := mrCancel else // stuff end; end; Okay that's very nice of you Delphi, but you're overwriting my stuff. How am I meant to programmatically close a form AND set the result ? Thanks 🙂
  16. To note ; the OnFormClose event isn't called when calling Close. However I just discovered there is a CloseModal function, which doesn't set the ModalResult to cancel in the case where the form is modal. It does set ModalResult to 0 in the case where the Action is set to caNone. Again, just a badly designed API. OnFormClose should be called no matter how you close the form. There shouldn't be 3 separates ways of closing the form, there should be one (taking arguments if you do want to manipulate some behavior). And said way should not be manipulating the value I want to return to the caller, as that is app data. This is like having 3 locks on your door, each looking the door in a different way and you can only lock one at a time. Also the second and third lock each turn on a different porch light when you use them after 22:00.
  17. Sure, and using assembly is logically identical to using C. But for the vast majority of purposes one has a better API wouldn't you say ? Bit of an overkill comparison, but the point stand. The Windows API in this case is better than the Delphi one for reasons already outlined.
  18. If they implemented it in the same way (a single flag serving two purposes), I would levy the same critique. With the caveat that it least it doesn't make the API more confusing since it's internal. Whereas as far as I'm aware, Delphi had no obligation to implement it in the same way, although it might have been a volition at the time to do a one-to-one of Windows. Which could be critiqued in itself, of course.
  19. Yes, and I established that it does it _internally_ and that you don't have a single flag serving two purposes, as you do in Delphi.
  20. Depends on the project of course, and secondarily on my current skillset. For the project that spawned this thread, I probably would have gone with WPF, which would have given me easy access to the .NET ecosystem which would be useful since there's a lot of places with custom drawing, while the rest of the interface is very basic.
  21. Of course, I never would have chosen Delphi for a new project. But there's a lot of old 90's projects out there for which it's not cost-effective to move to a more efficient platform, so Delphi sticks around.
  22. By implementing your own ShowModal which doesn't rely on it and instead listens for a "close" event, I suppose. Maybe you could make a "Close" function which would raise this event and set the return value to the value given by argument... You know, just how EndDialog does it 😉
  23. Hey, bad design doesn't mean it's not useful. I still use a car whose AC is less powerful then a fart lol.
  24. Yes, but the difference is that the flag is internal. We do not have access to it, nor is it the same as the value returned by ShowModal call. Again, to close in Windows I call function. In Delphi I set a flag. Fundamentally different things.
  25. You don't seem to get that I understand how it works. But it working doesn't mean it couldn't be better (way better). There's a reason Delphi is a dead language (just look at the average age of developers here), and that's because the design choices made at both the language and framework levels have been replaced by better alternatives. This is way I assume I know how it could have been better designed, become I know and use better alternatives. Those alternatives aren't perfect either, but they are better. This also doesn't mean Delphi wasn't a good framework compared to the competition 20 years ago. But that was 20 years ago, and Delphi has not improved (I mean we're still writing imperative UI code for Christ's sake), meaning the design choices that were bad but not worse than the competition are now just bad.
×