Jump to content

Anders Melander

Members
  • Content Count

    2297
  • Joined

  • Last visited

  • Days Won

    119

Everything posted by Anders Melander

  1. Anders Melander

    Logitech Gaming LED SDK for Delphi

    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..."
  2. Anders Melander

    Logitech Gaming LED SDK for Delphi

    So I guess this is your preferred keyboard : https://www.daskeyboard.com/daskeyboard-4-ultimate/
  3. Anders Melander

    Logitech Gaming LED SDK for Delphi

    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.
  4. Anders Melander

    Updated Community Edition

    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.
  5. Anders Melander

    Updated Community Edition

    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.
  6. Anders Melander

    Updated Community Edition

    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.
  7. Anders Melander

    Updated Community Edition

    Because they haven't made one. Why? Only Embarcadero knows.
  8. Anders Melander

    Office Assistant component..

    DoubleAgent uses the same animations as MS Agent did, so you can just use those.
  9. Anders Melander

    Office Assistant component..

    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.
  10. Anders Melander

    Office Assistant component..

    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/
  11. Anders Melander

    Weak reference is dangerous

    [weak] is not unsafe if you respect its limitations. Otherwise you might as well ague that strings are unsafe.
  12. Anders Melander

    Weak reference is dangerous

    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.
  13. Anders Melander

    ways to organize related code in a form?

    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.
  14. Anders Melander

    ways to organize related code in a form?

    Rubber Ducking: Monologuing a description of a problem to someone (or something) in order to get a better understanding of it.
  15. Anders Melander

    ways to organize related code in a form?

    Okay, but that didn't really explain anything. Are you just rubber ducking?
  16. Anders Melander

    ways to organize related code in a form?

    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
  17. Anders Melander

    How create a website whit Delhpi

    I'm amazed that people are able to offer architectural and implementation suggestions for "How create a website". Your physic powers must be excellent.
  18. Anders Melander

    DPM Package Manager - presentation

    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
  19. Anders Melander

    Large project does not start

    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.
  20. Anders Melander

    Manage overloaded IfThen functions

    Nice! Didn't know that one.
  21. Anders Melander

    In Case You Didn't Know

    Because 7 bits ought to be enough for everything https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#Pascal
  22. You'll get no complaint from me on that.
  23. Agree. It's a balance, as I'm sure Embarcadero knows and takes into account. Like all evolution, too much change leads to extinction. Too much stability leads to stagnation and obsolescence.
  24. Easy to say when you have already enjoyed the benefit of that backward compatibility.
  25. I'm not sure what it is you disagree with. Optimizing code when there is no need to optimize it is by definition premature optimization. The tool might be able to spot where code can be optimized but it will not be able to spot where that optimization is relevant. For the vast majority of the code I write I make an effort to make the code as readable and verbose as possible, at the cost of performance, because the possible gain of optimization is simply irrelevant. However when I know the code I'm writing is performance critical then I pay attention to what the compiler will do, alignment, loops, implicit finalization, etc., but that's the exception. Of course there are patterns that I have leaned to use regardless of the code being performance sensitive or not (e.g. pass managed types by const). In the cases where I get it wrong, or circumstances changes, then a profiler will tell me exactly where to focus my efforts and, as I said, then it's trivial to correct. I'm not against tools that can spot generic problems but a tool that identifies all cases of function returning managed type, passed as parameter, would be worthless to me. There are better ways of solving that "problem".
×