May 252017
 

Just so I can look it up later, if I need it:

The following are some interesting addons for Firefox:

  • FireGestures is a Firefox extension which enables you to execute various commands with six types of gestures.
  • Speed Start Speed Dial & Start Page with flexible layout for fast access to sites via visual bookmarks
  • uBlock an open source ad blocker. You can’t use the web without one nowadays (Anybody still remember Webwasher?)

I particularly like Speed Start. It allows me to configure the start page just the way I want it.

May 222017
 

Jeroen Wiert Pluimers has notified me in his comment on Google+ that the RSS feed for GExperts related posts doesn’t work. I apparently forgot a forward slash in the url:

correct:

http://blog.dummzeuch.de/category/gexperts/feed/

wrong:
http://blog.dummzeuch.de/category/gexpertsfeed/

It’s fixed now, sorry about that.

May 222017
 

I have been asked to provide GExperts for Delphi 10.2 Tokyo, multiple times, via various channels.

Apparently not everybody subscribed to the GExperts Community on Google+, where I posted this on 2017-04-01:

No April fools’ joke: GExperts 1.38 experimental 2017-04-01 for Delphi 10.2.

This version should solve several bugs that resulted in Access Violations in the IDE or made the IDE hang.

Again: This is not for the faint of heart. It is barely tested. Download only if you promise not to blame me for the work you lost.

Please report any bugs on sourceforge https://sourceforge.net/p/gexperts/bugs/

http://download.dummzeuch.de/GExperts/1.38_2017-04-01/GXRS10.2-138-experimental-twm-2017-04-01.exe

There seem to be multiple download links on the web for GExperts for Delphi 10.2 Tokyo that want to charge for a “VIP membership”. These have not been authorized by me at all.

To those who already downloaded it back then: This is still the same version. I have started working on a major change in the way dialog changes and bugfixes are handled internally, which currently is a mess. That change is far from finished, so it doesn’t make much sense to build a new installer right now.

May 142017
 

I ported my dzFeedReader tool which was originally written in Delphi 2009 to Lazarus. It’s still a Windows only program though.

This is more a proof of concept than a useful program, but it works. I also switched it from the SimpleRSS library to my own units so it is now under the MPL like all my other projects rather than the GPL.

May 132017
 

Some notes on Lazarus:

The Lazarus Wiki says on the topic of Internet Tools, that the following should load a web page:

uses simpleinternet;
..
str := retrieve('http://www.google.de');

Unfortunately it fails to mention (or if it is mentioned, I overlooked it), that you first need to download and install the Internet Tools.

After downloading them and adding three directories to the search path, it still failed to compile because it tried to use FLRE which is not part of the standard installation. To use the standard regular expression engine that comes with Lazarus, you need to add the conditional define USE_SOROKINS_REGEX.

Conditional defines for a project are set in Project Options -> Compiler Options -> Custom Options. Press the Defines button, enter the conditional define and press the Add button.

That finally got my simple test program to compile.

May 102017
 

So I don’t forget:

Adding a comment to an existing IXMLNode is simple, once you find out how:

var
  CommentNode: IXMLNode;
begin
  CommentNode := ParentNode.OwnerDocument.CreateNode('comment text', ntComment);
  ParentNode.ChildNodes.Add(CommentNode);

This is documented in the DocWiki

May 072017
 

Many months ago I used Yahoo Pipes to create a RSS feed aggregator of Delphi related blogs which I called The Delphi Pipe. Unfortunately shortly after that Yahoo shut down their Pipes service so The Delphi Pipe was rather short lived.

Today I revived it using a different technique. You can find all about it on The Delphi Pipe page.

Apr 232017
 

Two weeks ago I added the Donations for GExperts page. A few days later I received the first money through PayPal. Thanks for that!

I have now used that credit for donations to other open source software that I use daily:

I had always wanted to donate to those projects but never came around actually doing that. So, having some ready to use credits on PayPal made me finally do it.

Apr 162017
 

Today I had a need for a grid that looks like this:

It mixes text with two different bitmaps, representing an on/off state. In addition it should allow the user to switch the states using the mouse and the keyboard.

(If you are an experienced component developer, expect to be bored by this article. đŸ˜‰ )

I started out with a TListView in report view but when it came to switching with the keyboard I realized that I could only select the first column (or the whole row). I’m a fan of using the keyboard, so this was a no no. So I replaced the TListView with a TStringGrid. Adding a few events got me what I wanted:

  • OnDrawCell for drawing the bitmaps
  • OnMouseDown for intercepting mouse clicks
  • OnKeyPress for intercepting keyboard presses

I used a TImageList with two images for the bitmaps and set the cells that represent an on/off state to ‘0’ and ‘1’ (I could have used ‘Y’ and ‘N’ but ‘0’ and ‘1’ nicely correspond to the indices in the ImageList.)

I won’t go into this preliminary solution too much because the next step was to make this easier to use than having to set up the events each time I want to use it.

So, what else can we do? Create a component that descends from TStringGrid of course. But I didn’t want to install it, so I made it an interposer class instead.

unit Unit1;

interface

uses
  // ...
  Grids;

type
  TStringGrid = class(Grids.TStringGrid)
  private
    FImageList: TImageList;
    procedure SwitchCell(_Col, _Row: Integer);
  protected
    procedure KeyPress(var Key: Char); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect;
      AState: TGridDrawState); override;
    procedure Loaded; override;
  end;

type
  TForm1 = class(TForm)
    sg_IdeEnhancements: TStringGrid;
  private
  public
    constructor Create(_Owner: TComponent); override;
  end;

The code above declares a new type TStringGrid which descends from a class with the same name declared in unit Grids. It adds a field and a few methods.

But first, lets initialize the string grid:

constructor TForm1.Create(_Owner: TComponent);
begin
  inherited;
  sg_IdeEnhancements.RowCount := 4;

  sg_IdeEnhancements.Cells[0, 0] := 'Form';
  sg_IdeEnhancements.Cells[1, 0] := 'Make sizeable';
  sg_IdeEnhancements.Cells[2, 0] := 'Store size';
  sg_IdeEnhancements.Cells[3, 0] := 'Store position';
  sg_IdeEnhancements.Cells[4, 0] := 'ComboboxLines';

  sg_IdeEnhancements.Cells[0, 1] := 'Tools Properties';
  sg_IdeEnhancements.Cells[1, 1] := '1';
  sg_IdeEnhancements.Cells[2, 1] := '1';
  sg_IdeEnhancements.Cells[3, 1] := '0';
  sg_IdeEnhancements.Cells[4, 1] := '0';

  sg_IdeEnhancements.Cells[0, 2] := 'Install Packages';
  sg_IdeEnhancements.Cells[1, 2] := '1';
  sg_IdeEnhancements.Cells[2, 2] := '1';
  sg_IdeEnhancements.Cells[3, 2] := '0';
  sg_IdeEnhancements.Cells[4, 2] := '0';

  sg_IdeEnhancements.Cells[0, 3] := 'Find Text';
  sg_IdeEnhancements.Cells[1, 3] := '0';
  sg_IdeEnhancements.Cells[2, 3] := '0';
  sg_IdeEnhancements.Cells[3, 3] := '0';
  sg_IdeEnhancements.Cells[4, 3] := '1';
end;

As you can see, there isn’t anything special here. We just set the cells to strings.

Now to the more interesting code.

The string grid needs to know where to get its images from. Since I want to use a simple interposer class that should not require any special initialization code in the form, I decided it should get its image list from its owner in the method Loaded, it assumes that it is called ‘TheImageList’.

procedure TStringGrid.Loaded;
var
  cmp: TComponent;
begin
  inherited;
  cmp := Owner.FindComponent('TheImageList');
  if Assigned(cmp) and (cmp is TImageList) then
    FImageList := TImageList(cmp);
end;

The method Loaded is called by the streaming system after all components of a form have been created and initialized, so it is safe to assume that the image list exists.
Now, that the component has been set up, here is the code for drawing the bitmaps.

procedure TStringGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
  AState: TGridDrawState);
var
  s: string;
  bmp: TBitmap;
  xOff: Integer;
  YOff: Integer;
begin
  inherited;
  if not Assigned(FImageList) or (ARow = 0) or (ACol in [0, 5]) then
    Exit;

  s := Cells[ACol, ARow];

  Canvas.FillRect(ARect);
  bmp := TBitmap.Create;
  try
    if (s = '1') then
      FImageList.GetBitmap(1, bmp)
    else
      FImageList.GetBitmap(0, bmp);
    xOff := ARect.Left + ((ARect.Right - ARect.Left) - bmp.Width) div 2;
    YOff := ARect.Top + ((ARect.Bottom - ARect.Top) - bmp.Height) div 2;
    Canvas.Draw(xOff, YOff, bmp);
  finally
    FreeAndNil(bmp);
  end;
end;

Originally I had put this code into the OnDrawCell event.
It first checks that the image list is assigned and that the cell to draw is one for which I want to draw an image. It then reads the string from the cell and uses it to determine the bitmap to draw. It could have gone a step further and convert the string to an integer and use that as an index into the image list to select from more than two images. It then gets the image as a bitmap and draws it centered on the cell.

That takes care of painting the grid. The rest is even easier: We want to switch between ‘0’ and ‘1’ using the mouse and the keyboard.

procedure TStringGrid.KeyPress(var Key: Char);
begin
  inherited;
  if Key <> ' ' then
    Exit;
  SwitchCell(Col, Row);
end;

For the keyboard, we use the KeyPress method (originally assigned to the OnKeyPress event), check for the space key and call SwitchCell for the current column and row.

For the mouse, we first need to get the cell on which the user clicked. That’s simple because TStringGrid has a method for it: MouseToCell. We then pass column and row to SwitchCell as above.

procedure TStringGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  C: Integer;
  r: Integer;
begin
  inherited;
  MouseToCell(X, Y, C, r);
  SwitchCell(C, r);
end;

And finally the SwitchCell method. It checks again whether the cell is one we actually want to switch and then changes the cell’s string from ‘1’ to ‘0’ and vice versa.

procedure TStringGrid.SwitchCell(_Col, _Row: Integer);
var
  s: string;
begin
  if (_Row = 0) or (_Col in [0, 5]) then
    Exit;
  s := Cells[_Col, _Row];
  if s = '1' then
    s := '0'
  else
    s := '1';
  Cells[_Col, _Row] := s;
end;

Pretty easy, wasn’t it? So, why did I write this blog post?

Being a lazy bastard™ I of course googled for a solution first. I didn’t find any ready made examples for what I wanted to do so I thought I’d post one for others who are as lazy as I am. And maybe I will need it myself at a later time, so I can google it again.

Apr 152017
 

If you want to say thank you for my work on GExperts, there are the following options:

Contribute to the GExperts quality
You can either contribute good bug reports or – even better – bug fixes to GExperts. I’d actually prefer that over getting money. Good bug reports include the Delphi version (and language), the Windows version, the GExperts version, the settings used and steps to reliably reproduce the problem. Screen shots might also help. Use the bug report form on Sourceforge for that.

You can do even more by taking over the maintenance of GExperts for a particular Delphi version. I am currently using Delphi 2007 for most of my work, with a bit of Delphi XE2 and the latest version sprinkled in. So most of the other versions don’t really get tested. If you regularly use e.g. Delphi 6, 7, 2005, 2006, 2009 or 2010, why not take over testing and possibly bug fixing GExperts for these versions? For now, I still have working installations of these Delphi versions, but I am not sure that I will go to much effort to keep them working in the future. If one of them breaks, I might decide to drop GExperts support for them. By taking on the responsibility for them, you ensure they will still be around in a few years.

Contribute new features to GExperts
Contributing features to GExperts involves more than just suggestions (even though I am open to these too, please use the feature requests form page on SourceForge for that.)

It’s also not only about implementing them and sending me patches. It’s about thinking about how to integrate them into the existing code and UI. If you want to contribute code, please feel free to contact me.

Donate money
If you can’t do any of the above, you can donate money. I suggest the following amounts:

  • 50 Euros per year for private use via Flattr this or Paypal donate
  • 100 Euros per developer per year for commercial use via Flattr this or Paypal donate

It’s up to you of course. If you think it’s worth more, I definitely won’t complain, but if you can’t afford these, smaller amounts are also OK.

%d bloggers like this: