Troubleshooting Common TImagePicker Errors and Memory Leaks

Written by

in

Building a custom TImagePicker component in Delphi encapsulates an interactive user interface (UI) container, a preview window, and an image-loading mechanism into a single reusable tool.

This comprehensive guide focuses on building a compound control for the VCL framework. The control inherits from TCustomControl (giving it a window handle and canvas) and embeds a child TImage along with a TButton to trigger an image file dialog. Core Architecture of the Component A well-designed custom control requires:

Encapsulation: Internal child components (like buttons or images) must be instantiated, destroyed, and managed automatically inside the component.

Design-Time Publishing: Exposing properties (like the chosen bitmap, button text, or alignment options) in the Delphi Object Inspector.

Custom Events: Providing an OnImageSelected event so developers can react when a user loads a new photo. Step-by-Step Component Implementation

Save the code below as a standalone unit named ImagePicker.pas.

unit ImagePicker; interface uses System.SysUtils, System.Classes, Vcl.Controls, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Dialogs, Vcl.Graphics; type // Custom event trigger definition TImageSelectedEvent = procedure(Sender: TObject; const AFileName: string) of object; TImagePicker = class(TCustomControl) private FImage: TImage; FButton: TButton; FOpenDialog: TOpenTextFileDialog; FOnImageSelected: TImageSelectedEvent; procedure OnButtonClick(Sender: TObject); function GetPicture: TPicture; procedure SetPicture(Value: TPicture); function GetButtonCaption: string; procedure SetButtonCaption(const Value: string); protected procedure Resize; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; published // Expose crucial sub-properties to the Object Inspector property Align; property Anchors; property ButtonCaption: string read GetButtonCaption write SetButtonCaption; property Picture: TPicture read GetPicture write SetPicture; property Visible; // Custom event property OnImageSelected: TImageSelectedEvent read FOnImageSelected write FOnImageSelected; end; procedure Register; implementation procedure Register; begin // Register the component onto the ‘Samples’ IDE palette tab RegisterComponents(‘Samples’, [TImagePicker]); end; { TImagePicker } constructor TImagePicker.Create(AOwner: TComponent); begin inherited Create(AOwner); // Set default dimensions for the container Width := 200; Height := 150; // Initialize the subcomponents dynamically FOpenDialog := TOpenTextFileDialog.Create(self); FOpenDialog.Filter := ‘Image Files|.png;.jpg;.jpeg;.bmp;*.gif’; // Create and configure the internal TImage FImage := TImage.Create(self); FImage.Parent := self; FImage.Align := alClient; // Fills the container space not used by the button FImage.Proportional := True; // Prevents image distortion FImage.Stretch := True; // Create and configure the action button FButton := TButton.Create(self); FButton.Parent := self; FButton.Align := alBottom; // Pins the button to the bottom of the control FButton.Height := 30; FButton.Caption := ‘Select Image…’; FButton.OnClick := OnButtonClick; // Map internal click behavior end; destructor TImagePicker.Destroy; begin // Child components owned by ‘self’ are freed automatically via TComponent inherited Destroy; end; procedure TImagePicker.Resize; begin inherited Resize; // Handle layout adjustments gracefully during resizing if needed end; procedure TImagePicker.OnButtonClick(Sender: TObject); begin // Open dialog and safely handle the user selection if FOpenDialog.Execute then begin FImage.Picture.LoadFromFile(FOpenDialog.FileName); // Trigger custom event if a developer bound a method to it if Assigned(FOnImageSelected) then FOnImageSelected(self, FOpenDialog.FileName); end; end; { Property Getters and Setters } function TImagePicker.GetPicture: TPicture; begin Result := FImage.Picture; end; procedure TImagePicker.SetPicture(Value: TPicture); begin FImage.Picture.Assign(Value); end; function TImagePicker.GetButtonCaption: string; begin Result := FButton.Caption; end; procedure TImagePicker.SetButtonCaption(const Value: string); begin FButton.Caption := Value; end; end. Use code with caution. Key Technical Aspects Explained 1. Composite Window Handlers

Because TImagePicker inherits from TCustomControl, it manages its own window coordinates (HWND). When assigning parents to internal elements using FImage.Parent := self, you attach child handles directly into the custom control’s display real estate. 2. Encapsulation of AOwner vs Parent

Owner: Passed inside TImage.Create(self). It handles memory lifecycle management. When TImagePicker is destroyed, Delphi frees FImage, FButton, and FOpenDialog smoothly without manual calls.

Parent: Dictates the actual visual layout. If Parent is not set to self, the subcomponents remain invisible. 3. Image Aspect Ratio Settings

Setting FImage.Proportional := True ensures that uploaded graphics do not warp horizontally or vertically inside changing frame boundaries. How to Install and Use the Component

To make this component accessible inside your RAD Studio IDE layout:

Click File > New > Package – Delphi to start a new design package.

Right-click the package project panel and select Add…. Select your ImagePicker.pas file.

Right-click the project folder and choose Compile, then click Install.

Look at your Component Palette (under the Samples tab). Drop TImagePicker directly onto any project form.

If you are expanding this for a multi-platform environment using FireMonkey (FMX) instead of VCL, let me know. I can show you how to swap VCL classes for TLayout, TImage, and access the native mobile media libraries.

First Steps to Creating a Component in Delphi: From Idea to Implementation

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *