-
Content Count
2771 -
Joined
-
Last visited
-
Days Won
147
Everything posted by Anders Melander
-
Indeed. All paths relative and everything it source control. This also makes it trivial to build the project on a build server. At my current client the main product used to have dependencies on 5-6 different Git repositories and a bunch of 3rd party libraries that wasn't under source control. One person was responsible for figuring out what revision to checkout from the different repositories and what version of the 3rd party libraries to install and then build a version that could be sent to QA or deployed to the customers. And of course there were no relative paths. It was a nightmare. I moved everything into Git, made the dependent repositories submodules of the project repository, adding the source of the 3rd party libraries (also as submodules) and made all the paths relative. It took a few days to set up and now we have a fresh build after each commit. Wouldn't it be great if the project package configuration actually worked like most people expect it to (i.e. only load the packages specified in the project settings) and we could specify a (relative) path to the packages? I wouldn't even mind if I had to restart Delphi to switch from one project to the next. It would be better than the current situation.
-
How to optimize exe loading times
Anders Melander replied to a topic in Software Testing and Quality Assurance
Yes but by doing it explicitly, at the point of your choice, you control exactly when it happens. The autocreate form/datamodule code, using TApplication.CreateForm, is managed by the IDE and it has been known to mess that up once you start editing the dpr file. -
That was pretty much the point of what I wrote; You can't just rescale an image (vector or raster) at run time and expect good results.
-
The problem is the same as the one you have when you resample bitmaps. For small bitmaps you want to leave out a lot of details but keep the important parts and take advantage of the fact that the brain uses pattern recognition to reassemble the details. For larger bitmaps you can add details but leave of parts that were necessary in the smaller bitmaps for pattern recognition. This is why one can't just start with a large bitmap and downsample it to whatever size needed. The result usually looks awful. Same with SVG: For small SVG you don't necessarily want all the vectors to be rasterized. For larger ones maybe you do. An example of this is TrueType font hinting; Rasterizations of a font to a small point size uses different metrics and rules than the rasterization of the same font to a larger point size. One reason is that even with antialiasing we still need to take the pixel grid into account to get a good result.
-
You believe it may? If you want vectorized images that sometimes, maybe, almost, resembles the original bitmaps, then yes I'm sure you could train an engine to do that. But it would be faster and cheaper to just have a professional design a new set of vector images.
-
You don't convert your PNGs to SVG. You have to replace the PNGs with new SVG images. Since SVG is a vector format (hence the "V" in SVG) the visual expression will probably be very different from what you have now and it might not be what you want. There are probably someone that will suggest using vectorization to convert from PNG to SVG but I wouldn't bother. Vectorization only works well with large bitmaps. If you stay with raster images then you have to provide the individual bitmaps in different sizes and use something like TVirtualImageList. You typically don't need that many different sizes; 16, 24 and 32 should do but that of course depends on what amount of scaling you're willing to accept. Make sure that your bitmaps use alpha for best result - i.e. PNG or 32 bit bitmaps.
-
How to optimize exe loading times
Anders Melander replied to a topic in Software Testing and Quality Assurance
Compile and press F7 and you'd know. I would recommend that you change the autocreate datamodules so they're created on-demand instead. That way you'll defer the overhead until the datamodule is actually needed. Something like: type TMyBigDataModule = class(TDataModule) ... end; function MyBigDataModule: TMyBigDataModule; implementation var FMyBigDataModule: TMyBigDataModule; function MyBigDataModule: TMyBigDataModule; begin if (FMyBigDataModule = nil) then FMyBigDataModule := TMyBigDataModule.Create(Application); Result := FMyBigDataModule; end; Yeah. All those features and versatility definitely comes at a price. Since they switched to a subscription only model they have become become lazy with regard to avoiding dependencies and so the applications become pretty bloated. Put a simple grid on a form and you get much of the spreadsheet stuff linked in as well. -
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.