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;
2009. június 16., kedd
How to remove the focus rectangle and highlighted cell in a read-only TDBGrid
Problem/Question/Abstract:
How can I get rid of highlighting, focus rectangle etc. in a TDBGrid. I want the grid to display information only - without the user seeing highlighted cells etc. If I disable the grid, the user cannot use the scrollbars.
Answer:
Try this. You can adjust it to your needs:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
if not (gdFixed in State) then
StringGrid1.Canvas.Brush.Color := clWindow;
StringGrid1.Canvas.FillRect(Rect);
InflateRect(Rect, -1, -1); {resize so text is not on line}
DrawText(StringGrid1.Canvas.Handle, PChar(StringGrid1.Cells[ACol, ARow]), -1,
Rect, DT_SINGLELINE or DT_VCENTER or DT_LEFT);
end;
2009. június 15., hétfő
Access the current row/column of a TMemo
Problem/Question/Abstract:
Access the current row/column of a TMemo
Answer:
The following code reads and writes the cursor's position as row and column; counting starts at 0.
procedure GetMemoRowCol(M: TMemo; var Row, Col: LongInt);
begin
Row := SendMessage(M.Handle, EM_LINEFROMCHAR, M.SelStart, 0);
Col := M.SelStart - SendMessage(M.Handle, EM_LINEINDEX, Row, 0);
end;
procedure SetMemoRowCol(M: TMemo; Row, Col: Integer);
begin
M.SelStart := SendMessage(M.Handle, EM_LINEINDEX, Row, 0) + Col;
end;
2009. június 14., vasárnap
Detect an HTTP proxy from an Opera installation
Problem/Question/Abstract:
Detect an HTTP proxy from an Opera installation
Answer:
For the uncommon situation that a user does not have IE installed, one could try to retrieve the proxy information from an Opera installation.
Opera software stores in the registry the directory in that the Opera browser is installed.
In this directory there is a configuration file "Opera.ini" that contains a [PROXY] section. This section holds the required information.
The following handy routine shows how to code it:
procedure TForm1.FormCreate(Sender: TObject);
var
OperaDir: string;
sResult: string;
begin
// get Proxy host info from an Opera installation!
with TRegistry.Create do
begin
sResult := '';
RootKey := HKEY_CURRENT_USER;
if OpenKey('\Software\Opera Software', false) then
begin
if ValueExists('Last Directory') then
begin
OperaDir := ReadString('Last Directory');
SetLength(sResult, 128);
SetLength(sResult,
GetPrivateProfileString(
'PROXY',
'HTTP Server',
'',
@sResult[1],
Length(sResult),
PChar(OperaDir + '\opera.ini')));
end;
end;
Free;
if sResult <> '' then
ShowMessage('Your http proxy is ' + sResult)
else
ShowMessage('Opera is not installed or no proxy found.');
end;
end;
2009. június 13., szombat
Delphi 4/5 and Formula 1 Spreadsheet ActiveX control
Problem/Question/Abstract:
I ran into some problems when upgrading a work environment from Delphi 4 to Delphi 5, where the Formula 1 Spreadsheet ActiveX control (OCX) was involved.
Normal installation of an OCX:
Menu 'Component | Import ActiveX Control'
In the list of ActiveX controls, select 'VC Formula One'. If it is not in the list, use the 'Add' button to insert the OCX (\winnt\system32\vcf15.ocx)
Option step: Hit button 'Create Unit'. This will create an import unit 'VCF15_TLB.PAS', by default into this directory: \Delphi5\Imports\. The 'TLB' means 'Type Library'.
Hit Button 'Install'. If needed, this will create the import unit (see previous step). Then this import unit will be added to a - selected - package.
Open this package, compile and if necessary install it.
This procedure worked fine for Formula 1 with Delphi 4. However, when I had Delphi 5 create the import unit, I ran into these problems:
// ************************************************************************
// Errors:
// Hint: Member 'Type' of 'IF1FileSpec' changed to 'Type_'
// Hint: Member 'Type' of 'IF1NumberFormat' changed to 'Type_'
// Hint: Member 'Type' of 'IF1Book' changed to 'Type_'
// Hint: Parameter 'Array' of IF1Book.CopyDataFromArray changed to 'Array_'
// Hint: Parameter 'Array' of IF1Book.CopyDataToArray changed to 'Array_'
// Hint: Member 'Type' of 'IF1BookView' changed to 'Type_'
// Hint: Parameter 'Array' of IF1BookView.CopyDataFromArray changed to 'Array_'
// Hint: Parameter 'Array' of IF1BookView.CopyDataToArray changed to 'Array_'
// ************************************************************************
To make matters worse, when trying to compile the package file, I would get incompatible type errors in these lines:
property ColWidth[nCol: Integer]: Smallint read Get_ColWidth write Set_ColWidth;
property RowHeight[nRow: Integer]: Smallint read Get_RowHeight write Set_RowHeight;
Answer:
I found that the manufacturer puts an import file into the Formula One directory. The name of this file is 'VCF15.pas' (instead of 'VCF15_TLB.pas')
So I had to go through all my source codes and in the uses clauses replace VCF15_TLB with VCF15.
I also noticed that arguments of type 'WideString' had to be replaced with 'String' in Delphi 5.
After these steps, I can now compile applications under Delphi 5 that use Formula 1 and the deployed executables work.
2009. június 12., péntek
Empty the recycle bin
Problem/Question/Abstract:
How to empty the recycle bin
Answer:
procedure EmptyRecycleBin;
const
SHERB_NOCONFIRMATION = $00000001;
SHERB_NOPROGRESSUI = $00000002;
SHERB_NOSOUND = $00000004;
type
TSHEmptyRecycleBin = function(Wnd: HWND; pszRootPath: pChar; dwFlags: DWORD):
HRESULT; stdcall;
var
SHEmptyRecycleBin: TSHEmptyRecycleBin;
LibHandle: THandle;
begin
LibHandle := LoadLibrary(pChar('Shell32.dll'));
if LibHandle <> 0 then
@SHEmptyRecycleBin := GetProcAddress(LibHandle, 'SHEmptyRecycleBinA');
if @SHEmptyRecycleBin <> nil then
begin
SHEmptyRecycleBin(Application.Handle, nil, SHERB_NOCONFIRMATION or
SHERB_NOPROGRESSUI or SHERB_NOSOUND);
end;
FreeLibrary(LibHandle);
@SHEmptyRecycleBin := nil;
end;
2009. június 11., csütörtök
Create a roll-up form
Problem/Question/Abstract:
How can I create a form that will roll up? That is, a form that when clicked will reduce its height to nothing but the title bar?
Answer:
unit testmain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, Buttons, ShellAPI;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FOldHeight: Integer;
procedure WMNCRButtonDown(var Msg: TWMNCRButtonDown);
message WM_NCRBUTTONDOWN;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
FOldHeight := ClientHeight;
end;
procedure TForm1.WMNCRButtonDown(var Msg: TWMNCRButtonDown);
var
I: Integer;
begin
if (Msg.HitTest = HTCAPTION) then
if (ClientHeight = 0) then
begin
I := 0;
while (I < FOldHeight) do
begin
I := I + 40;
if (I > FOldHeight) then
I := FOldHeight;
ClientHeight := I;
Application.ProcessMessages;
end;
end
else
begin
FOldHeight := ClientHeight;
I := ClientHeight;
while (I > 0) do
begin
I := I - 40;
if (I < 0) then
I := 0;
ClientHeight := I;
Application.ProcessMessages;
end;
end;
end;
end.
First, by way of synopsis, the roll-up/down occurs in response to a WM_NCRBUTTONDOWN message firing off and the WMNCRButtonDown procedure handling the message, telling the window to roll up/down depending upon the height of the client area. WM_NCRBUTTONDOWN fires whenever the right mouse button is clicked in a "non-client" area, such as a border, menu or, for our purposes, the caption bar of a form. (The client area of a window is the area within the border where most of the interesting activity usually occurs. In general, the Windows API restricts application code to drawing only within the client area.)
Delphi encapsulates the WM_NCRBUTTONDOWN in a TWMNCRButtonDown type, which is actually an assignment from a TWMNCHitMessage type that has the following structure:
type
TWMNCHitMessage = record
Msg: Cardinal;
HitTest: Integer;
XCursor: SmallInt;
YCursor: SmallInt;
Result: Longint;
end;
It's easy to create message wrappers in Delphi to deal with messages that aren't handled by an object by default. Since a right-click on the title bar of a form isn't handled by default, I had to create a wrapper. The procedure procedure WMNCRButtonDown(var Msg : TWMNCRButtonDown); message WM_NCRBUTTONDOWN; is the wrapper I created. All that goes on in the procedure is the following:
In order to make this work, I had to create a variable called FOldHeight and set its value at FormCreate whenever the form was to be rolled up. FOldHeight is used as a place for the form to remember what size it was before it was re-sized to 0. When a form is to be rolled up, FOldHeight is immediately set to the current ClientHeight, which means you can interactively set the form's size, and the function will always return the form's ClientHeight to what it was before you rolled it up.
So what use is this? Well, sometimes I don't want to iconize a window; I just want to get it out of the way so I can see what's underneath. Having the capability to roll a form up to its title bar makes it a lot easier to see underneath a window without iconizing it, then having to Alt-tab back to it. (If you are familiar with the Macintosh platform, the System 7.5 environment offers a very similar facility called a "window shade," and makes a roll-up sound when the shade goes up.)
2009. június 10., szerda
Copy/paste TStringGrids cells to/from ClipBoard
Problem/Question/Abstract:
How to copy/paste TStringGrids cells to/from ClipBoard
Answer:
uses
Clipbrd;
Copy
procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
GRect: TGridRect;
C, R: Integer;
begin
GRect := StringGrid1.Selection;
S := '';
for R := GRect.Top to GRect.Bottom do
begin
for C := GRect.Left to GRect.Right do
begin
if C = GRect.Right then
S := S + (StringGrid1.Cells[C, R])
else
S := S + StringGrid1.Cells[C, R] + #9;
end;
S := S + #13#10;
end;
ClipBoard.AsText := S;
end;
Paste
procedure TForm1.Button2Click(Sender: TObject);
var
Grect: TGridRect;
S, CS, F: string;
L, R, C: Byte;
begin
GRect := StringGrid1.Selection;
L := GRect.Left;
R := GRect.Top;
S := ClipBoard.AsText;
R := R - 1;
while Pos(#13, S) > 0 do
begin
R := R + 1;
C := L - 1;
CS := Copy(S, 1, Pos(#13, S));
while Pos(#9, CS) > 0 do
begin
C := C + 1;
if (C <= StringGrid1.ColCount - 1) and (R <= StringGrid1.RowCount - 1) then
StringGrid1.Cells[C, R] := Copy(CS, 1, Pos(#9, CS) - 1);
F := Copy(CS, 1, Pos(#9, CS) - 1);
Delete(CS, 1, Pos(#9, CS));
end;
if (C <= StringGrid1.ColCount - 1) and (R <= StringGrid1.RowCount - 1) then
StringGrid1.Cells[C + 1, R] := Copy(CS, 1, Pos(#13, CS) - 1);
Delete(S, 1, Pos(#13, S));
if Copy(S, 1, 1) = #10 then
Delete(S, 1, 1);
end;
end;
2009. június 9., kedd
How to determine the CPU type
Problem/Question/Abstract:
How can I check what type my CPU is? E.g. Pentium (PI, PII, PIII or PIV), AMD (K6, K7, Athlon, ThunderBird), IBM, Cyrix or other CPU's.
Answer:
uses
Windows;
type
TProcessor = (NON_INTEL, I_386, I_486, I_PENTIUM, I_PENTIUMPRO,
I_CELERON, I_PENTIUM2, I_PENTIUM3, I_PENTIUM4);
{This is for Intel - I haven't tried for AMD etc.}
function GetProcessor: TProcessor;
var
SI: SYSTEM_INFO;
begin
Result := NON_INTEL;
GetSystemInfo(SI);
if (SI.wProcessorArchitecture = 0) then
begin
case (SI.wProcessorLevel and 15) of
3:
Result := I_386;
4:
Result := I_486;
5:
Result := I_PENTIUM;
6:
case hi(SI.wProcessorRevision) of
1: Result := I_PENTIUMPRO;
3, 5: Result := I_PENTIUM2;
6: Result := I_CELERON;
7, 8, 10, 11: Result := I_PENTIUM3;
end;
15:
Result := I_PENTIUM4;
end;
end;
end;
2009. június 8., hétfő
Drag items from a TTreeView onto a TListBox
Problem/Question/Abstract:
I have a treeview which I need to be able to drag items from onto a listbox (they have to be deleted from the treeview when moved, of course). I have been able to do this between two listboxes, but this one eludes me. Can anyone get me started please?
Answer:
procedure TForm1.TreeView1MouseDown(Sender: TObject; Button:
TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if TreeView1.Items.Count = 0 then
exit;
if Button = mbLeft then
TreeView1.BeginDrag(False); {begin drag}
end;
procedure TForm1.ListBox1DragOver(Sender, Source: TObject; X, Y:
Integer; State: TDragState; var Accept: Boolean);
begin
Accept := (Sender = TreeView1);
end;
procedure TForm1.ListBox1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
dx: integer;
Node: TTreeNode;
begin
if Source = TreeView1 then
begin
Node := TreeView1.Selected;
if Node <> nil then
begin
with TListBox(Sender) do
begin
dx := ItemAtPos(Point(X, Y), false);
Items.Insert(dx, Node.Text);
{or use:
Items.InsertObject(dx, Node.Text, Pointer(Node.Data)); }
end;
Node.Delete;
end;
end;
end;
2009. június 7., vasárnap
How to determine the screen coordinates of highlighted text in a TRichEdit
Problem/Question/Abstract:
How can I determine the screen coordinates (x, y) of the highlighted text of a TRichEdit component?
Answer:
procedure TForm1.Button3Click(Sender: TObject);
var
pt: TPoint;
begin
with richedit1 do
begin
pt := point(0, 0);
Perform(messages.EM_POSFROMCHAR, WPARAM(@pt), selstart);
{pt is in client coordinates}
label3.caption := Format('(%d, %d)', [pt.x, pt.y]);
{convert to screen coordinates}
pt := ClientToScreen(pt);
label2.caption := Format('(%d, %d)', [pt.x, pt.y]);
end;
end;
2009. június 6., szombat
How to start an instance of an application inside another program
Problem/Question/Abstract:
Is there an easy way to start an instance of an application inside another application so it looks like it's MDI when its not. I have the sub-apps and they need to be able to be run seperately, but I would also like to create an application that runs them inside itself, kind of like Word running Excel.
Answer:
If you want to use the Office model (each application is a OLE document server that can be activated in an OLE container) be prepared for a lot of work. Writing OLE document servers is a major effort and the VCLs ActiveX framework will get you only partways to the goal.
For some reason one can get away with parenting a window in another process to a window in your own, via Windows.SetParent. It will then act somewhat like a child window.
procedure TForm1.Button1Click(Sender: TObject);
var
wnd: HWND;
begin
WinExec('notepad.exe', sw_hide);
Sleep(500);
wnd := FindWindow('notepad', nil);
Windows.SetParent(wnd, handle);
SetWindowPos(wnd, 0, 0, 0, clientwidth, clientheight, SWP_NOZORDER or
SWP_SHOWWINDOW);
end;
You will probably need to implement some inter-app communication, e.g. based on WM_COPYDATA messages, between your applets. Depending on how far you need to go with the integration that may get you most of the way.
2009. június 5., péntek
Assign TForm.Icon at run time
Problem/Question/Abstract:
Assign TForm.Icon at run time
Answer:
ImageEdit is not good. Try to get Borland's Resource Workshop or paint with paintbrush and use a freeware converter to convert from BMP to ICO, write a little resource script (*.rc) refering to the ICO file and compile it to *.res with BRCC.EXE (comes with Delphi).
Use {$R xxx.res} to include it. Then you may use the API function
HICON LoadIcon(
HINSTANCE hInstance, // handle of application instance
LPCTSTR lpIconName // icon-name string or icon resource identifier
);
Take this handle (HICON) with the message WM_SETICON to assign it to your form:
SendMessage(Form1.Handle, WM_SETICON, false, iconhandle);
Note: 3rd parameter = icon size (true -> large icon; false -> small icon).
2009. június 4., csütörtök
Sorting a TListView by the first or any arbitrary column
Problem/Question/Abstract:
How can I sort the items in a TListView?
Answer:
Sorting by the first column
Sorting a TListView by the first column is easy:
ListView1.SortType := stText;
Setting SortType to stText is more or less like setting Sorted to True in a TListBox object. The list will be sorted and will remain sorted after additions and modifications, until SortType is set back to stNone:
ListView1.SortType := stNone;
It's like setting Sorted to False in a TListBox object. It won't undo the sorting, but future additions and modifications to the items list won't be sorted.
Sorting with an OnCompare event
To have a TListView sorted on another column (or arbitrary data stored or referenced in TListItem objects), we should either write an OnCompare event or an ordering function to be used with the CustomSort method. If you want to sort keep a list sorted while adding and modifying items, then you should use an OnCompare event.
procedure(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer) of object;
The parameter Compare which is passed by reference should be set to 1, -1 or 0 depending on whether the first item is greater than (or should be placed after) the second item, the first item is lower than (or should be placed before) the second item, or if the two items are equal, respectively. In the following example we are sorting a TListView by its fourth column (wich represents integer values) in descending order:
procedure TForm1.ListView1Compare(Sender: TObject; Item1,
Item2: TListItem; Data: Integer; var Compare: Integer);
var
n1, n2: integer;
begin
n1 := StrToInt(Item1.SubItems[2]);
n2 := StrToInt(Item2.SubItems[2]);
if n1 > n2 then
Compare := -1
else if n1 < n2 then
Compare := 1
else
Compare := 0;
end;
Now that we have an OnCompare event, to sort the list and having sorted, we should set SortType to stBoth (instead of stText, that sorts by the first column without using the OnCompare event):
ListView1.SortType := stBoth;
If you just want to perform a temporal sort, you can do the following:
ListView1.SortType := stBoth;
ListView1.SortType := stNone;
or else:
ListView1.CustomSort(nil, 0);
Sorting with an ordering function
If you need a faster sort, then you should write an ordering function. This function should return 1, -1 or 0 (like the Compare parameter of the OnCompare event discussed above). For example:
function ByFourth(Item1, Item2: TListItem; Data: integer):
integer; stdcall;
var
n1, n2: cardinal;
begin
n1 := StrToInt(Item1.SubItems[2]);
n2 := StrToInt(Item2.SubItems[2]);
if n1 > n2 then
Result := -1
else if n1 < n2 then
Result := 1
else
Result := 0;
end;
Then, every time you want to sort the list, you call CustomSort passing the address of the ordering function. For example:
ListView1.CustomSort(@ByFourth, 0);
The Data parameter of the OnCompare event is 0 if the event is called automatically when SortType is stData or stBoth, but if it is generated because of a call to CustomSort, then its value is the second parameter to this method. The same happens with the Data parameter of the ordering function, so the Data parameter is normally
used to specify a column to sort (we didn't use it in our example to make it simple).
Source Example
var
Ascending: boolean;
function SortByColumn(Item1, Item2: TListItem; Data: integer):
integer; stdcall;
// Copyright (c) 2001 Ernesto D'Spirito
// edspirito@latiumsoftware.com
// http://www.latiumsoftware.com
begin
if Data = 0 then
Result := AnsiCompareText(Item1.Caption, Item2.Caption)
else
Result := AnsiCompareText(Item1.SubItems[Data - 1],
Item2.SubItems[Data - 1]);
if Result < 0 then
begin
if Ascending then
Result := -1
else
Result := 1;
end
else if Result > 0 then
begin
if Ascending then
Result := 1
else
Result := -1;
end;
end;
procedure TForm1.ListView1ColumnClick(Sender: TObject;
Column: TListColumn);
begin
// Toggle column Tag
Column.Tag := 1 - Column.Tag; // 0 -> 1 ; 1 -> 0
// Determine sort order based on the value of the Tag
Ascending := Column.Tag = 1;
// Perform the sort
TListView(Sender).CustomSort(@SortByColumn, Column.Index);
end;
Copyright (c) 2001 Ernesto De Spirito
Visit: http://www.latiumsoftware.com/delphi-newsletter.php
2009. június 3., szerda
Adding my own resource file: error "Duplicate Resource"
Problem/Question/Abstract:
When I try to add a resource to my project's .res file, I get a "Duplicate Resource" error when linking. The resource I have added is a unique resource.
Answer:
The projects resource file is generated by the IDE wizard, and is not intended to be modified. To add additional resources to your project, create a separate resource file with a unique name that does not conflict with either the project or any of the unit names, e.g. "MyRes.Res". Then to add the resource file to Delphi, simply add the following line to any unit file in the project:
{$R MyRes.Res}
2009. június 2., kedd
Reading and Writing System-Wide Environment Variables
Problem/Question/Abstract:
How do you set an environment variable that will apply outside the process that set the variable or those spawned by it?
Answer:
On Windows 2000, if you open the control panel and double click on the system icon, the system properties dialog box will open. On the "Advanced" tab, you can click the "Environment Variables" tab to see a list of the user and system environment variables. The procedures and functions below allow you to read and write those variables.
It is worth mentioning that you can also use "GetEnvironmentVariable" and "SetEnvironmentVariable" to read and write environment variables. However, if you set and environment variable with "SetEnvironmentVariable", the value you set applies only to the process that called "SetEnvironmentVariable" or are spawned by it.
The first two procedures read and write environment variables for the current user.
function GetUserEnvironmentVariable(const name: string): string;
var
rv: DWORD;
begin
with TRegistry.Create do
try
RootKey := HKEY_CURRENT_USER;
OpenKey('Environment', False);
result := ReadString(name);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LParam
(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, rv);
finally
Free
end
end;
procedure SetUserEnvironmentVariable(const name, value: string);
var
rv: DWORD;
begin
with TRegistry.Create do
try
RootKey := HKEY_CURRENT_USER;
OpenKey('Environment', False);
WriteString(name, value);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LParam
(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, rv);
finally
Free
end
end;
The next two procedures read and write environment variables for the system and thus
affect all users.
function GetSystemEnvironmentVariable(const name: string): string;
var
rv: DWORD;
begin
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SYSTEM\CurrentControlSet\Control\Session ' +
'Manager\Environment', False);
result := ReadString(name);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LParam
(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, rv);
finally
Free
end
end;
// Modified from
// http://www.delphiabc.com/TipNo.asp?ID=117
// The original article did not include the space in
// "Session Manager" which caused the procedure to fail.
procedure SetSystemEnvironmentVariable(const name, value: string);
var
rv: DWORD;
begin
with TRegistry.Create do
try
RootKey := HKEY_LOCAL_MACHINE;
OpenKey('SYSTEM\CurrentControlSet\Control\Session ' +
'Manager\Environment', False);
WriteString(name, value);
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LParam
(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, rv);
finally
Free
end
end;
2009. június 1., hétfő
How to create a vertical progress bar and fill it from top to bottom
Problem/Question/Abstract:
Is it possible for the position parameter to fill a vertically orientated ProgressBar going down (rather than starting from its bottom and going up)? I want to indicate negative values. Ideal would be Min = -negative value and Max = +positive value with zero position in center and the fill would start from zero center and go either up or down depending on value.
Answer:
Here's one with that capability:
unit W95meter;
{This component is a Windows 95 style progress meter. It is free and donated to
the public domain. I do claim copyright of this code and I hereby prohibit the sale of the source or compiled code to anyone for any amount.
Modified 11/29/00 by Eddie Shipman
1. Added Direction Property to allow reverse fills.
Modified 10/15/97 by Eddie Shipman
1. Added a Max Value so Values over 100 can be used
2. Fixed the Invalidation of the control after properties are changed.
Modified 12/22/95 by John Newlin
1. Caught by Larry E. Tanner 70242,27. Decreasing the Value of the Percent property
would fail to clear the higher segments. Fixed.
2. Setting the EdgeStyle propety to St95None would not eliminate painting the edge outline. Fixed.
by John Newlin CIS 71535,665}
interface
uses
WinTypes, WinProcs, Messages, SysUtils, Classes, Controls, Forms, Menus, Graphics, Dialogs;
type
StyleType = (st95None, st95Lowered, st95Raised);
TDirection = (dirForward, dirReverse);
TW95Meter = class(TGraphicControl)
private
FAlign: TAlign;
FPercent: Integer;
FBackColor: TColor;
FSegColor: TColor;
FSegWidth: Integer;
FSegGap: Integer;
FMax: Integer;
FEdgeStyle: StyleType;
FDirection: TDirection;
procedure Initialize;
procedure SetPercent(Value: Integer);
procedure SetAlign(Value: TAlign);
procedure SetBackColor(Value: TColor);
procedure SetDirection(Value: TDirection);
procedure SetSegColor(Value: TColor);
procedure SetSegWidth(Value: Integer);
procedure SetSegGap(Value: Integer);
procedure SetMax(Value: Integer);
procedure SetStyle(Value: StyleType);
protected
procedure UpdateProgress;
procedure Paint; override;
procedure AdjustSize; dynamic;
procedure RequestAlign; dynamic;
public
constructor Create(AOwner: TComponent); override;
property Canvas;
function IntPercent(High, Low: Longint): Integer;
function RealPercent(High, Low: real): Integer;
published
property OnClick;
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property Cursor;
property Align: TAlign read FAlign write SetAlign default alNone;
property Direction: TDirection read FDirection write SetDirection default dirForward;
property EdgeStyle: StyleType read FEdgeStyle write SetStyle default st95Lowered;
property SegmentGap: Integer read FSegGap write SetSegGap default 2;
property SegmentWidth: Integer read FSegWidth write SetSegWidth default 8;
property SegmentColor: TColor read FSegColor write SetSegColor default clActiveCaption;
property BackGroundColor: TColor read FBackColor write SetBackColor default clBtnFace;
property Percent: Integer read FPercent write SetPercent default 0;
property Max: Integer read FMax write SetMax default 100;
property Width default 100;
property Height default 18;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Win32', [TW95Meter]);
end;
procedure TW95Meter.SetSegWidth(Value: Integer);
begin
if (Value > 0) and (Value <> FSegWidth) then
begin
FSegWidth := Value;
Invalidate;
end;
end;
procedure TW95Meter.SetMax(Value: Integer);
begin
if Value <> FMax then
begin
FMax := Value;
Invalidate;
end;
end;
procedure TW95Meter.SetSegGap(Value: Integer);
begin
if (Value > 0) and (Value <> FSegGap) then
begin
FSegGap := Value;
Invalidate;
end;
end;
procedure TW95Meter.SetBackColor(Value: TColor);
begin
if FBackColor <> Value then
begin
FBackColor := Value;
Invalidate;
end;
end;
procedure TW95Meter.SetSegColor(Value: TColor);
begin
if FSegColor <> Value then
begin
FSegColor := Value;
Invalidate;
end;
end;
procedure TW95Meter.SetPercent(Value: Integer);
var
bRefresh: boolean;
begin
if Value <> FPercent then
begin
if FPercent > Value then
bRefresh := true
else
bRefresh := false;
FPercent := Value;
if (Fpercent = 0) or (bRefresh = true) or (csDesigning in ComponentState) then
Invalidate;
UpdateProgress;
end;
end;
procedure TW95Meter.SetStyle(Value: StyleType);
begin
if Value <> FEdgeStyle then
begin
FEdgeStyle := Value;
Invalidate;
end;
end;
procedure TW95Meter.Initialize;
begin
Width := 100;
Height := 18;
FPercent := 0;
FBackColor := clBtnFace;
FSegColor := clActiveCaption;
FSegWidth := 8;
FSegGap := 2;
FEdgeStyle := st95Lowered;
FMax := 100;
FDirection := dirForward;
end;
constructor TW95Meter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Initialize;
end;
procedure TW95Meter.UpdateProgress;
var
x1, y1, x2, y2, max: Integer;
bg: TColor;
procedure DoHorizontalF;
var
i: Integer;
begin
x1 := 4;
x2 := x1 + FSegWidth;
y1 := 4;
y2 := Height - 4;
max := Width div (FSegWidth + FSegGap);
Max := round(max * (FPerCent / FMax));
for i := 1 to Max do
begin
with canvas do
begin
if x2 <= width - 4 then
Rectangle(x1, y1, x2, y2);
x1 := x1 + FSegWidth + FSegGap;
x2 := x1 + FSegWidth;
end;
end;
end;
procedure DoVerticalF;
var
i, h: Integer;
begin
h := height;
x1 := 4;
x2 := Width - 4;
y1 := Height - (FSegWidth + 4);
y2 := Height - 4;
max := Height div (FSegWidth + FSegGap);
max := round(max * (FPercent / FMax));
for i := 1 to max do
begin
with canvas do
begin
if y1 >= 4 then
Rectangle(x1, y1, x2, y2);
y1 := y1 - (FSegWidth + FSegGap);
y2 := y1 + FsegWidth;
end;
end;
end;
procedure DoHorizontalR;
var
i: Integer;
begin
x1 := Width - 4;
x2 := x1 - FSegWidth;
y1 := 4;
y2 := Height - 4;
max := Width div (FSegWidth + FSegGap);
Max := round(max * (FPerCent / FMax));
for i := 1 to Max do
begin
with canvas do
begin
if x2 <= width - 4 then
Rectangle(x1, y1, x2, y2);
x1 := x1 - FSegWidth - FSegGap;
x2 := x1 - FSegWidth;
end;
end;
end;
procedure DoVerticalR;
var
i: Integer;
begin
x1 := 4;
x2 := Width - 4;
y1 := 4;
y2 := 4 + FSegWidth;
max := Height div (FSegWidth + FSegGap);
max := round(max * (FPercent / FMax));
for i := 1 to max do
begin
with canvas do
begin
if y1 >= 4 then
Rectangle(x1, y1, x2, y2);
y1 := y1 + (FSegWidth + FSegGap);
y2 := y1 + FSegWidth;
end;
end;
end;
begin
canvas.pen.color := FSegColor;
canvas.brush.color := FsegColor;
case FDirection of
dirForward:
begin
if Width > Height then
DoHorizontalF
else
DoVerticalF;
end;
dirReverse:
begin
if Width > Height then
DoHorizontalR
else
DoVerticalR;
end;
end;
end;
procedure TW95Meter.Paint;
begin
with Canvas do
begin
Brush.Color := FBackColor;
if FEdgeStyle = st95none then
begin
Pen.Width := 0;
Pen.Color := FBackColor;
Rectangle(0, 0, width, height);
if FPercent > 0 then
UpdateProgress;
exit;
end;
pen.Width := 2;
if FEdgeStyle = st95Lowered then
pen.color := clgray
else
pen.color := clWhite;
moveto(0, height);
lineto(0, 0);
lineto(width - 1, 0);
if FEdgeStyle = st95Lowered then
pen.color := clWhite
else
pen.color := clGray;
lineto(width - 1, height - 1);
lineto(0, height - 1);
Pen.Width := 0;
Brush.Color := FBackColor;
Pen.Color := FBackColor;
Rectangle(1, 1, Width - 1, Height - 1);
if FPercent > 0 then
UpdateProgress;
end;
end;
function TW95Meter.RealPercent(High, Low: Real): Integer;
begin
result := 0;
if High = 0.0 then
exit;
Result := Round((Low / High) * FMax);
end;
function TW95Meter.IntPercent(High, Low: Longint): Integer;
begin
result := 0;
if High = 0 then
exit;
Result := Round((low / high) * FMax);
end;
procedure TW95Meter.SetAlign(Value: TAlign);
var
OldAlign: TAlign;
begin
if FAlign <> Value then
begin
OldAlign := FAlign;
FAlign := Value;
if not (csLoading in ComponentState) and (not (csDesigning in ComponentState) or
(Parent <> nil)) then
if ((OldAlign in [alTop, alBottom]) = (Value in [alRight, alLeft])) and
not (OldAlign in [alNone, alClient]) and not (Value in [alNone, alClient]) then
SetBounds(Left, Top, Height, Width)
else
AdjustSize;
end;
end;
procedure TW95Meter.AdjustSize;
begin
if not (csLoading in ComponentState) then
SetBounds(Left, Top, Width, Height);
end;
procedure TW95Meter.RequestAlign;
begin
{ if Parent <> nil then Parent.AlignControl(Self); }
end;
procedure TW95Meter.SetDirection(Value: TDirection);
begin
if Value <> FDirection then
begin
FDirection := Value;
Invalidate;
end;
end;
end.
Feliratkozás:
Bejegyzések (Atom)