Wednesday, 21 February 2018

Animate opening and closing a panel


Thought I would share an example of how I animate the opening and closing of a panel that can contain various controls and how each control can also be animated.



Here is the example code:

unit AnimatePanelFrm;

interface

uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls;

type
    TForm1 = class(TForm)
        Panel1 : TPanel;
        Shape1 : TShape;
        Label1 : TLabel;
        BitBtn1 : TBitBtn;
        BitBtn2 : TBitBtn;
        BitBtn3 : TBitBtn;
        BitBtn4 : TBitBtn;
        procedure Label1Click(Sender : TObject);
    private
        {Private declarations}
    public
        {Public declarations}
    end;

var
    Form1 : TForm1;

implementation

{$R *.dfm}

procedure TForm1.Label1Click(Sender : TObject);

const
    Expanded_Height = 106;
    Collapse_Height = 44;
    Speed           = 100;
    Speed2          = 200;
begin

    AnimateWindow(BitBtn1.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);
    AnimateWindow(BitBtn2.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);
    AnimateWindow(BitBtn3.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);
    AnimateWindow(BitBtn4.Handle, Speed, AW_HOR_NEGATIVE OR AW_SLIDE OR AW_HIDE);

    AnimateWindow(Panel1.Handle, Speed2, AW_VER_NEGATIVE OR AW_SLIDE OR AW_HIDE);
    if Panel1.Height = Expanded_Height then
        Panel1.Height := Collapse_Height
    else
        Panel1.Height := Expanded_Height;
    AnimateWindow(Panel1.Handle, Speed2, AW_VER_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);

    AnimateWindow(BitBtn4.Handle, Speed, AW_VER_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);
    AnimateWindow(BitBtn3.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);
    AnimateWindow(BitBtn2.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);
    AnimateWindow(BitBtn1.Handle, Speed, AW_HOR_POSITIVE OR AW_SLIDE OR AW_ACTIVATE);

end;

end.

Wednesday, 31 January 2018

Project setting for absolute paths

I've noticed that with the current version of Delphi (Berlin) the project file (.dpr) uses relative paths and when you manually change the paths to absolute paths and then add a something to the project (e.g. a .pas file) it converts them back to relative paths.

I prefer to use relative paths, however the problem I have is that both the MD and the Development Manager at the company insist on using absolute paths, the MD seems to think and apparently has heard that using relative paths can causes problems. I cannot find any project or environmental setting to force the paths for the project files in the .dpr file to be absolute. Does anyone know of such a setting or why relative paths in the .dpr file cause problems? 

Wednesday, 24 January 2018

Can and should user access permissions be stored in Active Directory?

I am currently looking at various designs of how to store user permissions, it is most likely I will choose on a Role Based Access Control (RBAC) and my original thought was to store the various role permissions in the database and in the application there would be an area that would allow an administrator to control the various user roles and role permissions. But some developers have mentioned to me not to do this and allow 'Active Directory' to control the various user permissions. This would mean that the access definitions (rules) would not need to be in the database and the control of these permissions do not need to be done in an application. I imagine the access enforcement to the various areas of the software e.g. Purchase Orders would still need to be controlled by the application and how the application interrogates the active directory permissions I still do not know.

The developers who have suggested doing this give the impression that it is possible and easier (saving time) than doing the access control using the database and application, although they have never done it themselves. Before I journey into how to develop for Active Directory, does anyone have experience of using it for access control for multiple areas of a Delphi application, and is this the direction access control is going for applications?   

Thursday, 21 December 2017

Auto create forms and data modules does not quite work

I've recently moved to Delphi 10.1 Berlin Update 2 from using XE and XE5. One thing that caught me out was that I forgot to turn off the 'Auto create forms and data modules' in the 'Form Designer' options. This setting means that when you add a form or data module to a project it gets auto-created at run-time.



The problem with this setting is that it does not fully work. I have a project where I do not want to auto create any forms or data modules, I have a class that is responsible for doing the initial creation of the required forms and objects, but if I add a form or data module to the project it always gets added to the auto create list in the project. This option assumes you want just one form in the list, once one is added it does not add anymore.

This problem could occur in all versions of XE and the now the more recent versions (DX), I plan to check this with XE and will hopefully soon be updating to the latest version of Delphi.

Tuesday, 5 December 2017

Delphi interesting skinning issue with .NET COM wrapper

I've come across an interesting issue with skinning and invoking a .NET Windows form and messagebox. I have a test Delphi application that is skinned using either Alpha Skins or setting the custom styles, I then invoke a .NET wrapper DLL developed in Visual Studio 2015 (COM interop)  and call the method to show a Windows form, this does not get skinned. However on the Windows form there is a button that shows a Windows messagebox, this does get skinned, see image below.


It would be nice if the Windows form also was skinned to match the Delphi application and it seems strange that the Windows messagebox which is invoked by the Windows form is skinned.

Thursday, 21 September 2017

TObjectList vs TObjectDictionary

When I need to store a list of objects I usually use a TObjectList (Generics.Collections), but I was speaking to another developer who uses TObjectDictionary to store a list of objects. I searched the net for when to use a TObjectDictionary instead of a TObjectList and vice-versa, but could not find any definitive answers. I decided to write a little test app to understand the difference, this simply did the following:

  • Created 1 million objects for each list and added them to the list.
  • Cleared the list of the 1 million objects.
  • Populated the list with 1 million newly created objects.
  • Found 100 objects in the list.
Below are the results, time is in ms:


ObjectList Clear - 47
ObjectList Populate - 344
ObjectList Find - 78
ObjectList Find - 78
ObjectList Find - 78
ObjectList Find - 79

ObjectDictionary Clear - 265
ObjectDictionary Populate - 579
ObjectDictionary Find - 0
ObjectDictionary Find - 0
ObjectDictionary Find - 0
ObjectDictionary Find - 0

As you can see the TObjectDictionary was slower to clear and populate the list, but was faster finding the 100 objects. This is most likely due to the TObjectDictionary being derived from TDictionary which is a hash table and is optimised for lookups.

So, generally from these results I am happy sticking with TObjectList, but if I need to store a lot of objects and also need to find a lot of objects then using a TObjectDictionary is a better choice. 

Tuesday, 25 July 2017

Windows 10 Notification

Here is a quick and simple example of a notification procedure. On a form I added a 'TNotificationCenter' component from the 'System' tool palette.

procedure TForm.DoNotification(aName, aTitle, aBody: string);
var
    appNotification: TNotification;
begin
    appNotification := NotificationCenter1.CreateNotification;
    try
        appNotification.Name := aName;
        appNotification.Title := aTitle;
        appNotification.AlertBody := aBody;
        NotificationCenter1.PresentNotification(appNotification);
    finally
        appNotification.Free;
    end;
end;

procedure TForm.ShowTestNotification;
begin
    DoNotification('Test Name', 'Test Title', 'This is an example');
end;

There is an event in the NotificationCenter component called 'OnReceiveLocalNotification', which is useful if you want to display a notification and when a user clicks on the notification the software performs an operation. 

I did this example in Delphi 10.1 Berlin, it is a very limited example due to Delphi being very limited with what can be done with Windows Notifications. Looking at the documentation you can do more with iOS, I am not sure why they have made it so limited. I have briefly looked at some C# examples and you can do more with notifications like custom sounds, icons, images and actions. 

One thing I have noticed is that when I run this example the notification is shown and then when it goes away it is automatically removed from the action centre. One thing I would require is that if the user does not acknowledge the notification, it should stay in the Action Centre list. For me it would be really useful to have the following:
  • Custom image.
  • Custom sound.
  • FireDate to work in Windows 10.
  • Option for the notification to stay in the Action Centre.

I would like to see Embarcadero expand on what these notifications can do, obviously they are limited to what the OS can do. If they could persist in the Action Centre until clicked then I can think of multiple uses for notifications.