2009. június 30., kedd

Decrementing a datetime field in Paradox


Problem/Question/Abstract:

Decrementing a datetime field in Paradox

Answer:

There is a bug in Local SQL on Paradox:

Executing an Update statement on a Paradox table where '1' is being subtracted in a datetime field does not subtract '1', but rather adds '1'.

// this will ADD one!
UPDATE SAMPLE.DB set DT = DT - 1

// the following workaround will give the correct result:
UPDATE SAMPLE.DB set DT = DT + (-1)

2009. június 29., hétfő

Jumping between compiler errors


Problem/Question/Abstract:

Jumping between compiler errors

Answer:

After compiling, when there were errors found:

Alt-F8 will take you to the next compiler error

Alt-F7 will take you to the previous error.

2009. június 28., vasárnap

Add a page break to an Excel worksheet


Problem/Question/Abstract:

How to add a page break to an Excel worksheet

Answer:

If WS is your worksheet:

{ ... }
Excel.ActiveWindow.View := xlPageBreakPreview;
WS.HPageBreaks.Add(WS.Cells.Item[78, 1]);
{ ... }

2009. június 27., szombat

How to hide the font size list in a TFontDialog


Problem/Question/Abstract:

How can I completely hide the fontsize selection combobox in the font dialog? I have manipulated some properties of the fontdialog but the combobox where you pick the font size is always visible. Furthermore, I want to keep the preview of the font but with a fixed font size.

Answer:

Set the fdLimitSize option in the dialogs Options to true and specifiy the same size for the MinFontsize and Maxfontsize property.

Hide the font size list. This requires a bit of spy work to determine the control IDs in the dialog. Once this has been done you can attach a handler to the fontdialogs Onshow handler:

procedure TForm1.FontDialog1Show(Sender: TObject);
begin
  EnableWindow(GetDlgItem(fontdialog1.handle, 1138), false);
  EnableWindow(GetDlgItem(fontdialog1.handle, 1090), false);
  ShowWindow(GetDlgItem(fontdialog1.handle, 1138), SW_HIDE);
  ShowWindow(GetDlgItem(fontdialog1.handle, 1090), SW_HIDE);
end;

1138 is the handle of the font size combobox (it is a combobox, despite looking like an edit with a list box below it), 1090 the text label above it. Without disabling the controls the accelerator for the size box will close the dialog for some reason.

For the future: the spy works done here was performed this way:

procedure TForm1.Button1Click(Sender: TObject);
begin
  fontdialog1.execute;
end;

function EnumProc(wnd: HWND; lines: TStrings): BOOL; stdcall;
var
  buf, caption: array[0..255] of char;
begin
  result := True;
  GetClassname(wnd, buf, 256);
  GetWindowText(wnd, caption, 256);
  lines.add(format('ID: %d, class: %s, caption: %s', [GetDlgCtrlID(wnd), buf,
    caption]));
end;

procedure TForm1.FontDialog1Show(Sender: TObject);
begin
  memo1.clear;
  EnumChildWindows(fontdialog1.handle, @EnumProc, integer(memo1.lines));
end;

{Output in memo:

ID: 1088, class: Static, caption: Schrift&art:
ID: 1136, class: ComboBox, caption: MS Sans Serif
ID: 1000, class: ComboLBox, caption:
ID: 1001, class: Edit, caption: MS Sans Serif
ID: 1089, class: Static, caption: &Schriftschnitt:
ID: 1137, class: ComboBox, caption: Standard
ID: 1000, class: ComboLBox, caption:
ID: 1001, class: Edit, caption: Standard
ID: 1090, class: Static, caption: &Grad:
ID: 1138, class: ComboBox, caption: 8
ID: 1000, class: ComboLBox, caption:
ID: 1001, class: Edit, caption: 8
ID: 1, class: Button, caption: OK
ID: 2, class: Button, caption: Abbrechen
ID: 1026, class: Button, caption: �&bernehmen
ID: 1038, class: Button, caption: &Hilfe
ID: 1072, class: Button, caption: Darstellung
ID: 1040, class: Button, caption: &Durchgestrichen
ID: 1041, class: Button, caption: &Unterstrichen
ID: 1091, class: Static, caption: &Farbe:
ID: 1139, class: ComboBox, caption: Schwarz
ID: 1073, class: Button, caption: Muster
ID: 1092, class: Static, caption: AaBbYyZz
ID: 1093, class: Static, caption:
ID: 1094, class: Static, caption: S&chrift:
ID: 1140, class: ComboBox, caption: Western
}

2009. június 26., péntek

Retreive information from a TDBGrid onCellClick


Problem/Question/Abstract:

How to retreive the information from a TDBGrid when you click a cell or row

Answer:

While you click a TDBGrid row, the information can be obtained by the following procedure:

DBAccounts is a TDBGrid
For this example e_F0..e_F2 are TEdit but it can be any object
You can use FieldCount to obtain the number of fields so you can fill an array like

for x = 0 to DBAccounts.FieldCount - 1 do
  AnyArray[x] := DBAccounts.Fields[x].DisplayText

For this Example, Set TDBGrid.Options[dgRowSelect] so when you click a cell the row will be selected. Trim Function removes spaces (OPTIONAL)

procedure TForm4.DBAccountsCellClick(Column: TColumn);
begin
  with DBAccounts.SelectedField do
  begin
    e_F0.Text := Trim(DBAccounts.Fields[0].DisplayText);
    e_F1.Text := Trim(DBAccounts.Fields[1].DisplayText);
    e_F2.Text := Trim(DBAccounts.Fields[2].DisplayText);
    // and so on ....
    //.
    //.
    //.
  end;
end;

2009. június 25., csütörtök

How to move icons between TImageLists


Problem/Question/Abstract:

How to move icons between TImageLists

Answer:

procedure TForm1.Button1Click(Sender: TObject);
var
  ico: TIcon;
begin
  ico := TIcon.Create;
  try
    Imagelist1.GetIcon(0, ico);
    Imagelist2.AddIcon(ico);
  finally
    ico.Free;
  end;
end;

2009. június 24., szerda

Create a sorted TList that holds integers


Problem/Question/Abstract:

How can I create a TStringlist cousin which holds integers rather than strings. I need the ability to keep a list of objects sorted by an integer with full binary IndexOf.

Answer:

Use a TList, and do casts where appropriate:

To write:

MyList.Add(Pointer(17));
MyList.Add(Pointer(39));

To read:

MyInt := Integer(MyList[0]);

To sort:

procedure CompareInts(Item1, Item2: Pointer): Integer;
begin
  if Integer(Item1) > Integer(Item2) then
    Result := 1
  else if if Integer(Item1) < Integer(Item2) then
    Result := -1
  else
    Result := 0;
end;
{ ... }
MyList.Sort(CompareInts);

2009. június 23., kedd

How to create a message box with your own icon


Problem/Question/Abstract:

The message box has limited icons as set by Microsoft. I would like to use one of the icon I have and insert it into the message box. Is there a way to do that? Do I have to create a component to handle it?

Answer:

function CustMsgBox(const AMsg, ACaption, BCap1, BCap2, BCap3: string;
  IconInd: integer; FocusInd: byte; Mainform: TForm): integer;
const
  Userexe: array[0..9] of char = 'user.exe';
const
{$IFDEF Win32}
  BHeight = 23;
{$ELSE}
  BHeight = 25;
{$ENDIF}
  BWidth = 77;
var
  W: TForm;
  lCaption: TLabel;
  But1, But2, But3: TButton;
  i1: integer;
  Image1: TImage;
  IHandle: THandle;
  P1: array[byte] of char;
  Textsize: TSize;
  MDC: hDC;
  CurMetrics: TTextMetric;
  Curfont: HFont;
  Msgrect: TRect;
begin
  W := TForm.CreateNew(Application);
  But2 := nil;
  But3 := nil;
  try {set up form}
    W.BorderStyle := bsDialog;
    W.Ctl3D := True;
    W.Width := 360;
    W.Height := 160;
    W.Caption := ACaption;
    W.Font.Name := 'Arial' {Mainform.Font.Name};
    W.Font.CharSet := BALTIC_CHARSET;
    W.Font.Size := Mainform.Font.Size;
    W.Font.Style := Mainform.Font.Style;
    {Get text extent}
    for i1 := 0 to 25 do
      P1[i1] := Chr(i1 + Ord('A'));
    for i1 := 0 to 25 do
      P1[i1 + 26] := Chr(i1 + Ord('a'));
    GetTextExtentPoint(W.Canvas.Handle, P1, 52, Textsize);
    {Get line height}
    MDC := GetDC(0);
    CurFont := SelectObject(MDC, W.Font.Handle);
    GetTextMetrics(MDC, CurMetrics);
    SelectObject(MDC, CurFont);
    ReleaseDC(0, MDC);
    {Set icon}
    Image1 := TImage.Create(W);
    StrPCopy(P1, ParamStr(0));
    if Image1 <> nil then
    begin
      Image1.Width := Image1.Picture.Icon.Width;
      Image1.Height := Image1.Picture.Icon.Height;
      Image1.Left := 20;
      Image1.Top := Textsize.CY + (Textsize.CY div 2);
      Image1.Width := 32;
      Image1.Height := 32;
      Image1.Parent := W;
      Image1.Name := 'Image';
      {get icon index}
      case IconInd of
        16: IHandle := ExtractIcon(hInstance, userexe, 3);
        32: IHandle := ExtractIcon(hInstance, userexe, 2);
        48: IHandle := ExtractIcon(hInstance, userexe, 1);
        64: IHandle := ExtractIcon(hInstance, userexe, 4);
        128: IHandle := ExtractIcon(hInstance, userexe, 0);
        256: IHandle := ExtractIcon(hInstance, userexe, 5);
        512: IHandle := ExtractIcon(hInstance, userexe, 6);
      else
        IHandle := ExtractIcon(hInstance, P1, IconInd);
      end;
      if IHandle <> 0 then
        Image1.Picture.Icon.Handle := IHandle
      else
        Image1.Picture.Icon := Application.Icon;
    end;
    SetRect(MsgRect, 0, 0, Screen.Width div 2, 0);
    DrawText(W.Canvas.Handle, PChar(AMsg), -1, MsgRect, DT_CALCRECT or DT_WORDBREAK);
    {set up label}
    lCaption := TLabel.Create(W);
    lCaption.Parent := W;
    lCaption.Left := 72;
    lCaption.Top := Image1.Top;
    lCaption.Width := Msgrect.Right;
    LCaption.Height := Msgrect.Bottom;
    lCaption.Autosize := False;
    lCaption.WordWrap := True;
    {Adjust form width...must do here to accommodate buttons}
    W.Width := lCaption.Left + lCaption.Width + 30;
    lCaption.Caption := AMsg;
    {buttons}
    But1 := TButton.Create(W);
    But1.Parent := W;
    But1.Caption := BCap1;
    But1.ModalResult := 1;
    if BCap2 <> '' then
    begin
      But2 := TButton.Create(W);
      But2.Parent := W;
      But2.Caption := BCap2;
      But2.ModalResult := 2;
      if BCap3 <> '' then
      begin
        But3 := TButton.Create(W);
        But3.Parent := W;
        But3.Caption := BCap3;
        But3.ModalResult := 3;
      end;
    end;
    {Set button positions}
    {set height depending on whether icon or message is tallest}
    if lCaption.Height > Image1.Height then
      But1.Top := (lCaption.Top + lCaption.Height + 20)
    else
      But1.Top := (Image1.Top + Image1.Height + 20);
    But1.Width := BWidth;
    But1.Height := BHeight;
    if But2 <> nil then
    begin
      But2.Height := BHeight;
      But2.Width := BWidth;
      But2.Top := But1.Top;
      if But3 <> nil then
      begin
        But3.Top := But1.Top;
        But3.Width := BWidth;
        But3.Height := BHeight;
        But3.Left := (W.Width div 2) + ((BWidth div 2) + 8);
        But2.Left := (W.Width div 2) - (BWidth div 2);
        But1.Left := (W.Width div 2) - ((BWidth div 2) + BWidth + 8);
        But3.Cancel := True;
      end
      else
      begin
        But2.Left := (W.Width div 2) + 4;
        But1.Left := (W.Width div 2) - (BWidth + 4);
      end;
    end
    else
    begin
      But1.Left := (W.Width div 2) - (BWidth div 2);
    end;
    {set focus}
    case FocusInd of
      3:
        if BCap3 <> '' then
          But3.Default := True;
      2:
        if BCap2 <> '' then
          But2.Default := True;
    else
      But1.Default := True;
    end;
    {Set clientheight to proper height}
    W.ClientHeight := But1.Top + But1.Height + Textsize.CY;
    { Left := (W.ClientWidth div 2) - (((OKButton.Width * 2) + 10) div 2) }
    {Show messagebox}
    {Set position}
    { Position := poScreenCenter;  }
    W.Left := Mainform.Left + ((Mainform.Width - W.Width) div 2);
    W.Top := Mainform.Top + ((Mainform.Height - W.Height) div 2);
    W.ShowModal;
    Result := W.ModalResult;
  finally
    W.Free;
  end;
end;

2009. június 22., hétfő

How to draw colored text on a TStatusBar


Problem/Question/Abstract:

How to draw colored text on a TStatusBar

Answer:

The status bar is a standard Windows control, and as such, displays the font in the clBtnText value, which is set via the Control Panel. This color is black by default, but it can vary due to the user's color scheme. Other standard Windows controls, such as buttons, exhibit this identical behavior. The StatusBar and its associated panels have an owner-draw capability that allow you to draw text in any colors you want. Be sure to change the Style property of the TStatusBar.Panels to OwnerDraw.

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar;
  Panel: TStatusPanel; const Rect: TRect);
begin
  if Panel = StatusBar.Panels[0] then
  begin
    StatusBar.Canvas.Font.Color := clRed;
    StatusBar.Canvas.TextOut(Rect.Left, Rect.Top, 'Panel - 0')
  end
  else
  begin
    StatusBar.Canvas.Font.Color := clGreen;
    StatusBar.Canvas.TextOut(Rect.Left, Rect.Top, 'Panel - 1');
  end;
end;

2009. június 21., vasárnap

Add a bitmap to a menu item (2)


Problem/Question/Abstract:

How to add bitmaps to a menu?

Answer:

Create a Picture. Load a .BMP from somewhere into the picture. Better have the picture as a resource and load the handle with LoadBitmap(). Use the SetMenuItemBitmaps API call to connect the Picture to the Menu.

All this can by coded in the .Create of a form.

Don't use a bitmap that is too large :) because only the right-top of the bitmap is displayed.


var
  Bmp1: TPicture;
  CheckedHandle,
    Bmp1Handle: THandle;

// ... in the FormCreate event:

// either load from an external file
Bmp1 := TPicture.Create;
Bmp1.LoadFromFile('c:\where\b1.BMP');
Bmp1Handle := Bmp1.Bitmap.Handle;
CheckedHandle := Bmp1Handle;

// or - using resources in the EXEcutable
Bmp1Handle := LoadBitmap(hInstance, 'RESOURCENAME');
CheckedHandle := LoadBitmap(hInstance, 'CHECKED_IMAGE');

// assign the bitmaps
SetMenuItemBitmaps(MenuItemTest.Handle, 0, MF_BYPOSITION,
  Bmp1Handle, CheckedHandle);
...

2009. június 20., szombat

Templates Delphi


Problem/Question/Abstract:

Templates in Delphi

Answer:

Here is an overview about the different templates in Delphi and where they are stored.
Important: If you reinstall or update Delphi, you should save these files first!

delphi32.dci
Delphi source file templates in a text file

delphi32.dct
Delphi Component Template IDE binary file with the Delphi componens templates

delphi32.dmt
Delphi Menu Template IDE / Menu designer binary file with the menu templates

delphi32.dro
Delphi Repository Options ID text file with the object repository's settings

2009. június 19., péntek

How to add items of a TListBox as sub-items to a selected tree node


Problem/Question/Abstract:

I have TreeView1, Button1 and ListBox1. ListBox one has x number of items. I need to be able to click Button1 and the items in ListBox1 are inserted as sub-items to the selected tree-node.

Answer:

var
  ix: integer;
  parentnode: TTreeNode;

  TreeView.Items.BeginUpdate;
try
  parentnode := TreeView.FocusedNode;
  for ix := 0 to ListBox1.Items.Count - 1 do
  begin
    if parentnode = nil then
      Tree.Items.Add(nil, ListBox1[ix])
    else
      Tree.Items.AddChild(parentnode, ListBox1[ix]);
  end;
finally
  TreeView.Items.EndUpdate;
end;

2009. június 18., csütörtök

Move components from Delphi 5 to Delphi 6


Problem/Question/Abstract:

Have you tried to compile your components, or 3rd party components you have in Delphi 5 into Delphi 6?
99% of them will not compile. However do not despare. It is only because of a few changes Borland has implemented on their latest product. This article covers the major changes.

Answer:

First of all, you will discover that the unit dsgnintf.pas is missing. Borland changed the name to Designintf.pas, moved the property editor code to a new unit, called DesignEditors.pas, put the constants used inside DesignConsts.pas and the menus inside DesignMenus.pas

Also the variants have moved from system.pas to their own unit called Variants.pas

The IFormDesigner interface isn't there anymore. You should use the IDesigner and typecast your variables. (this is a change probably made to accomodate the CLX and I was unable to find any documentation on it from either Borland or Delphi 6 Online help system. I only found that every IFormDesigner has been repaced with IDesigner)

The IDesignerSelections interface has also changed. The most helpfull change is the addition of a Get function that returns a TPersistent when giving the index of the member.

On previous versions if you wanted the TPersistent of an object you wrote:

var
  p: TPersistant;
  ...
    P := Selections[i] as TPersistant;

Now you only write:

var
  p: TPersistant;
  ...
    P := Selections.get[i];

That's about it. I have used these simple instructions to recompile all of  my third party tools, and all of my custom components.

P.S. Just remember... you have to have the source code to do this!!! :-)

2009. június 17., szerda

Determine if a given TTable has a restricted view


Problem/Question/Abstract:

I am trying to write a function to determine if a given TTable has a restricted view. The filtered and master-detail views are easy. Is there a way to determine if SetRange / ApplyRange, etc. have been used for a table? This is for Paradox tables.

Answer:

TMyTable = class(TTable)
public
  function IsRangeActive: Boolean;
end;

function TMyTable.IsRangeActive: Boolean;
begin
  Result := BuffersEqual(GetKeyBuffer(kiRangeStart), GetKeyBuffer(kiCurRangeStart),
    SizeOf(TKeyBuffer) + RecordSize) and BuffersEqual(GetKeyBuffer(kiRangeEnd),
    GetKeyBuffer(kiCurRangeEnd), SizeOf(TKeyBuffer) + RecordSize);
end;