-
Content Count
2563 -
Joined
-
Last visited
-
Days Won
133
Everything posted by Anders Melander
-
How to optimize exe loading times
Anders Melander replied to a topic in Software Testing and Quality Assurance
...at least one too many -
How to optimize exe loading times
Anders Melander replied to a topic in Software Testing and Quality Assurance
So the problem isn't actually related to "How to optimize exe loading times" but rather "how to speed up form loading"...? I use the layout control a lot, and on complex forms it can become a bit slow, but I've never had it affect application startup time or the time it takes for the main form to display. You aren't by chance "auto creating" your forms? -
ANN: Parnassus Parallel Debugger
Anders Melander replied to Dave Millington (personal)'s topic in Delphi Third-Party
That's not what Assert is for. An Assert is a verification that the assumption under which the code is written holds. If the assumption proves to be wrong, i.e. the Assert fails, then all bets are off. There is no "best effort" that can save it. There's nothing to prevent the application from presenting an assertion error the same way as all other exceptions, but the fact is that it's an internal error that the user can do nothing about, and the application shouldn't just pretend that everything is fine. Since I write a lot of framework and library code I use assertions a lot but at one of my former employers, a company in the medical device sector, I was told to remove all assertions because it "made their software look bad". Pointing out that that if there was assertion errors then looking bad was the least of their problems didn't go down well. Apparently they preferred random catastrophic errors of unknown origin to immediate errors that could be traced back to their software. -
ANN: Parnassus Parallel Debugger
Anders Melander replied to Dave Millington (personal)'s topic in Delphi Third-Party
Do you prefer Access Violations or other random errors? -
Logitech Gaming LED SDK for Delphi
Anders Melander replied to FPiette's topic in RTL and Delphi Object Pascal
It's a QPAD MK-80 so not a RGB keyboard; It's blue or nothing. It's using Cherry MX Blue switches (tactile+click - the closest I could come to the IBM model M) and AFAIR it wasn't possible to get RGB with those switches back when I bought it. -
Logitech Gaming LED SDK for Delphi
Anders Melander replied to FPiette's topic in RTL and Delphi Object Pascal
Well my alternate keyboard, the one I use when I'm traveling or need USB connection (the IBM keyboard only has the old PS/2 connector and draws too much power to boot reliably from USB ) has blue illumination with variable intensity. Blue is pretty but I'd much prefer red as it's easier on the eyes when it's dark. Yeah, I can think of some applications too but then the user isn't really supposed to be looking at the keyboard so I think I'll file that idea under "sounds like a good idea, but..." -
Logitech Gaming LED SDK for Delphi
Anders Melander replied to FPiette's topic in RTL and Delphi Object Pascal
So I guess this is your preferred keyboard : https://www.daskeyboard.com/daskeyboard-4-ultimate/ -
Logitech Gaming LED SDK for Delphi
Anders Melander replied to FPiette's topic in RTL and Delphi Object Pascal
Yeah. I recently was looking to buy a new keyboard for my daughter. Since I'm a bit of a keyboard freak (I'm typing this on an IBM model M keyboard) I wanted a mechanical keyboard of good build quality. Well it turns out that it's near impossible to find a good mechanical keyboard worth it's price unless it's a "gaming keyboard" - i.e. with full RGB. Ironically if there's anybody that absolutely does not want to get distracted by flashing lights on their keyboard it's professional gamers. They're a useless as Anne Frank's drum set. FWIW I ended up buying a Logitech G513 with Romer-G tactile switches at a bargain. -
Yeah, reality' a bitch. Embarcadero has changed things to the better, I'll give them that; Remember how bad things were back when the idiots chased the enterprise market. Inprise? What a farce. I agree that they need to recapture the hobby and amateur segment. They're not Microsoft so the decision to use Delphi will not come from the top. It will have to come from the bottom, from the developers. The $99 strategy worked for Borland with Turbo Pascal but it would not work today. They can no longer expect to sell a gazillion licenses of a cheap tool because of the competition from other cheap or free tools. It would also have to be so crippled that nobody would use it. No. Not easy at all.
-
How do you know what people are using? I think it widely depends. A few years ago I worked at a place where we stuck with XE and XE2 because the later XE versions sucked. I doubt that they have updated since then but I would have updated them to 10.3 if I had any involvement with them anymore. At my previous job we were around 30 developers all using 10.3. At my current client we're using most of what the 10.3 language and RTL provides and when we've done our next major release I expect we will all update to 10.4.
-
What's your source for this? If that is the case then I'm disappointed by their lack of understanding of the ecosystem they're a part of and their own position within it. These days, from my POW, given the entry level price of Delphi, the best they can hope for with a free version is to keep Delphi alive by seeding knowledge of it, and what it can do, into the younger generations. Nothing is lost by giving it away for free to those that can't afford it anyway. I think the $5000 limit on the CE edition is a reasonable rule but thinking that it will cause much conversion is IMO naive.
-
Because they haven't made one. Why? Only Embarcadero knows.
-
DoubleAgent uses the same animations as MS Agent did, so you can just use those.
-
Yes, well it's one of those things that sounds like a great idea - and it's very easy to sell to management and the customer. Unfortunately once you start to work with it you quickly realize that it's extremely difficult to integrate with the existing application without getting in the way and that there are better/easier/cheaper ways of doing whatever it's purpose is supposed to be. It's not for nothing that users hated the feature and Microsoft quickly abandoned it. I've implemented it in at least three different applications and it never saw any use beyond the welcome sequence.
-
The Microsoft Agent is a COM server so you don't need a component for that. Just import the type library, create an instance of the TAgent object in code and then manipulate it through the interfaces. I used DWScript to drive the agent actions and interaction (hence I made a DWScript wrapper library), but here's some code fractions of the host application: uses AgentObjects_TLB, DoubleAgentSvr_TLB, ... type TFormMain = class(TForm) private FAgent: TAgent; FAgentCharacter: IAgentCtlCharacter; FAgentRequestStart: IAgentCtlRequest; FAgentRequestComplete: IAgentCtlRequest; procedure LoadAgent; procedure AgentOnRequestStart(Sender: TObject; const Request: IDispatch); procedure AgentOnRequestComplete(Sender: TObject; const Request: IDispatch); procedure AgentOnClick(Sender: TObject; const CharacterID: WideString; Button: Smallint; Shift: Smallint; x: Smallint; y: Smallint); procedure AgentWaitForRequest(Request: IAgentCtlRequest; WaitForStart: boolean); procedure AgentWaitForIdle; {$endif AGENT} procedure AssistantMessage(const Msg: string); procedure AssistantDirectedMessage(FocusArea: TRect; const Msg: string); procedure AssistantAction(Action: TAssistantAction); procedure AssistantPlay(const Action: string); procedure AssistantHide; end; ... procedure TFormMain.LoadAgent; var s: string; begin if (FAgent <> nil) then exit; FAgent := TAgent.Create(Self); try FAgent.Parent := Self; FAgent.Connected := True; FAgent.OnRequestStart := AgentOnRequestStart; FAgent.OnRequestComplete := AgentOnRequestComplete; FAgent.OnClick := AgentOnClick; s := 'james.acs'; if (FileExists(ExtractFilePath(Forms.Application.ExeName)+s)) then s := ExtractFilePath(Forms.Application.ExeName)+s; FAgent.Characters.Load('James', s); FAgentCharacter := FAgent.Characters['James']; except FAgentCharacter := nil; FreeAndNil(FAgent); end; end; procedure TFormMain.OnShowAgentClick(Sender: TObject); begin LoadAgent; if (FAgentCharacter <> nil) and (FAgentCharacter.Visible) then FAgentCharacter.Hide(True); end; procedure TFormMain.AssistantAction(Action: TAssistantAction); const Actions: array[TAssistantAction] of string = ('Acknowledge', 'Congratulate', 'Confused', 'Decline', 'Pleased'); begin if (FAgentCharacter = nil) then exit; if (not FAgentCharacter.Visible) then FAgentCharacter.Show(False); FAgentCharacter.Play(Actions[Action]); end; procedure TFormMain.AssistantMessage(const Msg: string); begin if (FAgentCharacter = nil) then exit; if (not FAgentCharacter.Visible) then FAgentCharacter.Show(False); FAgentCharacter.Speak(Msg, Unassigned); end; procedure TFormMain.AssistantPlay(const Action: string); begin if (FAgentCharacter = nil) then exit; if (not FAgentCharacter.Visible) then FAgentCharacter.Show(False); FAgentCharacter.Play(Action); end; procedure TFormMain.AssistantDirectedMessage(FocusArea: TRect; const Msg: string); begin if (FAgentCharacter = nil) then exit; AgentWaitForRequest(FAgentCharacter.MoveTo(FocusArea.Right, FocusArea.Top - (FAgentCharacter.Height div 2), 1000), False); if (not FAgentCharacter.Visible) then FAgentCharacter.Show(False); AgentWaitForRequest(FAgentCharacter.GestureAt((FocusArea.Left + FocusArea.Right) div 2, (FocusArea.Top + FocusArea.Bottom) div 2), False); AssistantMessage(Msg); end; procedure TFormMain.AssistantHide; begin if (FAgentCharacter = nil) then exit; if (FAgentCharacter.Visible) then FAgentCharacter.Hide(True); end; procedure TFormMain.AgentOnRequestComplete(Sender: TObject; const Request: IDispatch); begin FAgentRequestComplete := Request as IAgentCtlRequest; FAgentRequestStart := nil; end; procedure TFormMain.AgentOnRequestStart(Sender: TObject; const Request: IDispatch); begin FAgentRequestComplete := nil; FAgentRequestStart := Request as IAgentCtlRequest; end; procedure TFormMain.AgentWaitForIdle; begin while (FAgentRequestStart <> nil) and ((FAgentRequestComplete = nil) or (FAgentRequestStart.ID <> FAgentRequestComplete.ID)) do Forms.Application.ProcessMessages; end; procedure TFormMain.AgentWaitForRequest(Request: IAgentCtlRequest; WaitForStart: boolean); begin if (WaitForStart) then begin while (FAgentRequestStart = nil) or (FAgentRequestStart.ID <> Request.ID) do Forms.Application.ProcessMessages; end else begin while (FAgentRequestComplete = nil) or (FAgentRequestComplete.ID <> Request.ID) do Forms.Application.ProcessMessages; end; end; procedure TFormMain.OnClose(Sender: TObject); begin if (FAgentCharacter <> nil) then begin if (FAgentCharacter.Visible) then begin FAgentCharacter.Play('Wave'); FAgentCharacter.Speak('Goodbye', Unassigned); AgentWaitForRequest(FAgentCharacter.Hide(False), False); end; FAgentCharacter := nil; FAgent.Connected := False; end; end; Since Microsoft Agent has been deprecated for ages you should use something like DoubleAgent instead. DoubleAgent is drop-in-compatible (i.e. uses the same interfaces and the same API). http://doubleagent.sourceforge.net/
-
[weak] is not unsafe if you respect its limitations. Otherwise you might as well ague that strings are unsafe.
-
If the weak reference is not thread safe then the the weak-to-strong copy also isn't thread safe. As far as I can tell there's no way that [weak] references can be implemented thread safe so I don't see a bug here.
-
ways to organize related code in a form?
Anders Melander replied to David Schwartz's topic in General Help
Yes maybe. I guess I'm just puzzled by the need of posting questions about stuff one can easily or better answer oneself - and the walls of text that has little to do with the topic, I'm not against rubber ducking, I use it extensively myself, but rubber ducking in public is just wasting other peoples time. -
ways to organize related code in a form?
Anders Melander replied to David Schwartz's topic in General Help
Rubber Ducking: Monologuing a description of a problem to someone (or something) in order to get a better understanding of it. -
ways to organize related code in a form?
Anders Melander replied to David Schwartz's topic in General Help
Okay, but that didn't really explain anything. Are you just rubber ducking? -
ways to organize related code in a form?
Anders Melander replied to David Schwartz's topic in General Help
So your asking for input on how to organize your big ball of mud while keeping it a big ball of mud? Okay, I've got some of those myself. I don't know why you need to ask for help on this as you seem competent enough to figure this out for yourself by trial and error, but here goes; Generally I organize the functions of a unit as: Global functions. Unit wide (interface section) utility functions. Class constructors/destructor. Class utilities. Class methods ordered by context/task. Disclaimer: Not completely sober -
I'm amazed that people are able to offer architectural and implementation suggestions for "How create a website". Your physic powers must be excellent.
-
DPM Package Manager - presentation
Anders Melander replied to Vincent Parrett's topic in Delphi Third-Party
I think it's pointless trying to comer up with a "cool" abbreviation. Just pick a name that has some good derivative or related words that can be used for the "bundles" and such. "DOPE" fit's that criteria nicely -
Yes. I usually use a simple factory pattern. It briefly goes like this (view = frame): Create a "view registry" class. This class wraps a dictionaly that maps between a view interface and a class type. Move all your stuff into frames. For each frame assign them an interface and register the interface and the view class in the view registry. Create a "view manager" class. This class wraps a TDictionary<TGUID, TView> that contains the currently active view instances and is also responsible for creating new views. So something like: View (i.e. frame) abstract base class and API: unit Foo.Views.API; interface type IView = interface ['{4057A1F4-F22C-4CCF-89DE-9F4AE2E790DE}'] procedure Initialize; end; type // Abstract base class of your views. TView = class abstract(TFrame, IView) protected // IView procedure Initialize; virtual; end; TViewClass = class of TView; type IViewRegistry = interface ['{B4EC0F81-24DF-41D9-BF8A-CE0D9958C9A9}'] procedure RegisterView(const GUID: TGUID; ViewClass: TViewClass); procedure UnregisterView(const GUID: TGUID); function FindView(const GUID: TGUID): TViewClass; end; type IViewManager = interface ['{B4EC0F81-24DF-41D9-BF8A-CE0D9958C9A9}'] function OpenView(const GUID: TGUID): IView; procedure CloseView(const GUID: TGUID); function FindView(const GUID: TGUID): IView; end; implementation ... end. The API of a single view: unit Foo.Views.MyView.API; interface type IMyView = interface ['{063646E3-FB0D-4B8C-984A-A5E54F543651}'] procedure FooBar; end; implementation end. The implementation of a single view: unit Foo.Views.MyView; interface uses Foo.Views.API, Foo.Views.MyView.API; type // Trick to get the IDE to behave without registering the frame in a package TFrame = TView; TMyView = class(TFrame, IMyView) protected // IView procedure Initialize; override; // IMyView procedure FooBar; end; implementation ... intialization // Register our implementation of the IMyView interface ViewRegistry.RegisterView(IMyView, TMyView); end; and then you "just" have to Implement IViewRegistry and IViewManager unit Foo.Views.Manager; interface uses Foo.Views.API; function ViewRegistry: IViewRegistry; function ViewManager: IViewManager; implementation type TViewRegistry = class(TInterfacedObject, IViewRegistry) private FRegistry: TDictionary<TGUID, TViewClass>; protected // IViewRegistry procedure RegisterView(const GUID: TGUID; ViewClass: TViewClass); procedure UnregisterView(const GUID: TGUID); function FindView(const GUID: TGUID): TViewClass; end; var FViewRegistry: TViewRegistry; function ViewRegistry: IViewRegistry; begin if (FViewRegistry = nil) then FViewRegistry := TViewRegistry.Create Result := FViewRegistry; end; procedure TViewRegistry.RegisterView(const GUID: TGUID; ViewClass: TViewClass); begin FRegistry.Add(GUID, ViewClass); end; procedure TViewRegistry.UnregisterView(const GUID: TGUID); begin FRegistry.Remove(GUID, ViewClass); end; function TViewRegistry.FindView(const GUID: TGUID): TViewClass; begin if (not FRegistry.TryGetValue(GUID, Result)) then Result := nil; end; type TViewManager = class(TInterfacedObject, IViewManager) private FViews: TDictionary<TGUID, IView>; protected // IViewManager function OpenView(const GUID: TGUID): IView; procedure CloseView(const GUID: TGUID); function FindView(const GUID: TGUID): IView; end; function TViewManager.OpenView(const GUID: TGUID): IView; begin if (FViews.TryGetValue(GUID, Result) then Exit; var ViewClass := ViewRegistry.FindView(GUID); if (ViewClass = nil) then Boom! Result := ViewClass.Create; FViews.Add(Result); Result.Initialize; end; ...etc. etc... end.
-
Manage overloaded IfThen functions
Anders Melander replied to Mike Torrettinni's topic in General Help
Nice! Didn't know that one.