Next: Part 2
Original: 2016-01-24
As mentioned, I have moved from Delphi to Lazarus. And at the same time, I have changed from Windows to Linux. The change has not been without problems, but I think it will work out in the end.
While Lazarus is quite similar to older versions of Delphi, cross-platform development does impose some constraints. To learn the details, I have decided to implement some software originally developed with Delphi on Windows in this new (for me) environment. And I am making some progress: conversion of the mathematical parser is complete while Caleçon, a calculator, is for the most part complete. And I am starting on a complete rewrite of Gaston, a function grapher.
It may prove useful to have a colour selection dialogue much like the
ones found in Inkscape or Gimp. That gave me an excuse to create my first
components: TColorBar and TSliderBar. They can be
seen in the following screen shot of the second demonstration program that
accompanies this topic. The red, green and blue bars are of type
TColorBar while the other three shapes are of type TSliderBar
.
Figure 1: Demo 2, Using colour bars to define a colour
There are three demonstration programs included in the dowloadable
archive. The first can be run without installing the components. It will
give you an idea of capabilities of the TColorBar component. It
is basically a colour track bar which can be associated with a
TSpinEdit for finer control.

Figure 2: Demo 1, Colour bar properties
The TSliderBar component can be thought of as an owner
drawn TColorBar. As such, it is relatively easy to create a
track bar with that component. See Demo3 in the archive. The components does
not need to be be installed in the Lazarus IDE to compile this example.
You must install the components to compile the second demonstration
program. This entails installing a package file. It is named
MdSliderBarsLaz.lpk and is located in the package folder. Follow the
usual steps to install the package, which means accepting the default values
at each step.
To create the colour selector, seen in the top image, drop three
TColorBars and three spin edits on a form. Add a TSliderBar
, the labels and a TButtonPanel. Using the object
inspector, adjust the displayed buttons and displayed glyphs on the buttons
of the TButtonPanel to your taste.
Again, with the object inspector, change the following properties in each of the colour bar:
Associate: set to the appropriate spin editMarkerStyle: set tomsTriangular(optional as long asmsNoneis not chosen)MaxValue: 255 (again optional but the natural range 0-255 is what Inkscape uses)
OnChange event of the three bars to a common event
handler which could be called ColorBarChange. That handler is a
simple calls to a routine, RedrawBars, that redraws the
appropriate components whenever a colour value is changed either by using
the mouse or keyboard arrows to move the slider in a colour bar or by
entering a value in the associated spin edit. The colour bar handles its
associated spin edit, there is nothing to do with it.
As for the TSliderBar change the following property
MarkerStyle: set to msNone- TabStop: set to False.
Click on the component's OnPaint event to create a handler
which will fill the left half with the initial colour and the right half
with the currenly defined colour.
procedure TPickerForm.colorBarPaint(Sender: TObject; aRect: TRect);
var
middle: integer;
orgRight: integer;
begin
orgRight := aRect.Right;
middle := (aRect.left + orgRight) div 2;
with Sender as TSliderBar do begin
with canvas do begin
// fill the left half with the initial colour
aRect.right := middle;
brush.color := InitialColor;
FillRect(aRect);
// and fill the right half with the currently selected colour
aRect.Right := orgRight;
aRect.Left := middle;
brush.color := SelectedColor;
FillRect(aRect);
end;
end;
end;
Now there remains the task of writing the code, which is very simple because most of the work is done by the components. Start by adding the private RedrawBars procedure and by defining two private variables of the same type representing the initial colour when starting the dialogue and the selected colour which will be updated as the user changes a colour value.
type
TPickerForm = class(TForm)
...
private
{ private declarations }
FInitial, FSelected: packed record
case boolean of
false: (color: TColor);
true: (Red: byte;
Green: byte;
Blue: byte;
Alpha: byte);
end;
procedure RedrawBars;
public
{ public declarations }
property InitialColor: TColor read FInitial.Color write FInitial.Color;
property SelectedColor: TColor read FSelected.color;
end;
These two variables are exposed as public properties called
InitialColor which is read and write and SelectedColor
which is read only. Note how the record gives access to the colours as both
TColor and as individual RGB values (the Alpha value is not
used here).
The procedure RedrawBars does most of the work. First, it
updates the selected colour stored in the FSelected record.
Then each of the three colour bars is redrawn. Each colour bar is a linear
gradients along the corresponding colour channel. Take the red bar as an
example. The gradient will be drawn from a red value of 0 to the maximum
red value of 255. The values of green and blue channel are constant and
equal to the values of the selected colour. While the start colour and end
colour are properties which can be set individually, it is better to use the
SetColors procedure to avoid unnecessary drawing:
with FSelected do
RedBar.SetColors(RGB(0, Green, Blue), RGB(255, Green, Blue));
The other colour bars are updated similarly. Here is the complete code for the procedure:
procedure TPickerForm.RedrawBars;
begin
with FSelected do begin
// update the selected colour using the colour bar values
// one of which has presumably been changed
Red := RedBar.value;
Green := GreenBar.value;
Blue := BlueBar.value;
// redraw all the colour bars, because they are interdependant
RedBar.SetColors(RGB(0, Green, Blue), RGB(255, Green, Blue));
GreenBar.SetColors(RGB(Red, 0, Blue), RGB(Red, 255, Blue));
BlueBar.SetColors(RGB(Red, Green, 0), RGB(Red, Green, 255));
// update the hexadecima value of the selected color
label4.Caption := Format('%.2x%.2x%.2x', [Red, Green, Blue]);
end;
// redraw the control showing the selected color
colorBar.Invalidate;
end;
The only other significant procedure paints the initial and selected
colour bar at the bottom. TSliderBar is a TCustomControl
descendant, so that its Canvas property is public. The
client area is specified in a TRect variable. Drawing the
inside of the bar is a simple matter of filling the left half with the
original colour and the right half with the selected colour.
Upcoming: addition of a two-dimensional slider component (see Part 2).
Test environment: Lazarus 1.4.4, FPC 2.64, Ubuntu 14.04 LTS 64 bit.
Modifications: as of the 26 th of January, the following corrections have been made to the the package:
- Addition of a 3rd demonstration program.
- Unhooked old associate’s
OnChangeevent inTCustomSlider.SetAssociate. - Added a destructor to
TCustomSliderto unhooked associate’sOnChangeevent. - Fixed the default value for
MarkerStyle. - Fixed the package file (small Lazarus/Delphi gotcha).
Download the package archive: mdsliderbarslaz.zip. See Part 2 for a bigger package containing an additional two components.