I got a run-time error in my application when I had added two instances of the same TFrame on the same form. The error message looked like this:
Fair enough, but the thing was that only one of the frames was called 'MyFrame'. The other one was called 'MyFrame2'.
Apparently, the problem is that one of the two frames on my form using the default name as it is in unit that declares the frame TMyFrame.
So, if you only uses one frame of type TMyFrame on the form, it is okay to call it MyFrame, but if you have two ore more, none of them can be called MyFrame.
Lesson learned!
A place to track solutions to problems encountered during Delphi programming and other helpful hints, tips and comments.
test
progging - To wander about and beg; to seek food or other supplies by low arts; to seek for advantage by mean shift or tricks.
progging - Programmer slang for writing computer code.
Viser innlegg med etiketten Delphi. Vis alle innlegg
Viser innlegg med etiketten Delphi. Vis alle innlegg
mandag 21. januar 2013
Multiple TFrame's on a form
Etiketter:
already exists,
Delphi,
error,
frame,
multiple frames,
TFrame
fredag 4. mai 2012
Drag and drop files on to a Delphi application
Here is a good explanation about how to implement drag-an-drop in delphi:
http://www.delphidabbler.com/articles?article=11
http://www.delphidabbler.com/articles?article=11
søndag 11. september 2011
Delphi: General method to check if key is pressed
To check if a specific key is pressed you can use the
GetKeyState
method. type TUtility = class public class function CheckKeyPressed(key: Integer): Boolean; class function ShiftKeyPressed(): Boolean; class function CtrlKeyPressed(): Boolean; class function AltKeyPressed(): Boolean; endOne method can check any key you want using virtual key codes:
// Helper methods to check various key states class function TUtility.CheckKeyPressed(key: Integer): Boolean; begin //The return value of GetKeyState specifies the status of the specified virtual key, as follows: // //If the high-order bit is 1, the key is down; otherwise, it is up. //If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled //if it is turned on. // The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) // on the keyboard will be on when the key is toggled, and off when the key is untoggled. // // Check high-order of state Result := (GetKeyState(key) and $80) <> 0; end;...and specific methods for the most interesting keys can be made:
// Helper methods to check various key states class function TUtility.ShiftKeyPressed(): Boolean; begin Result := CheckKeyPressed(VK_SHIFT); end; class function TUtility.CtrlKeyPressed(): Boolean; begin Result := CheckKeyPressed(VK_CONTROL); end; class function TUtility.AltKeyPressed(): Boolean; begin Result := CheckKeyPressed(VK_MENU); end;
Etiketter:
Alt,
Ctrl,
Delphi,
GetKeyState,
KeyPressed,
Shift
tirsdag 6. september 2011
Define your custom TColor type in Delphi
Do define your own custom color in Delphi, do this:
So the color red would be:
const clChartRed = TColor($B3B3FF); // 70 % gradient Red on White clChartYellow = TColor($B3FFFF); // 70 % gradient Yellow on WhiteBut remember that Delphi defines the colors as BGR and not the usual RGB so remember to swap numbers.
So the color red would be:
const clRed = TColor($0000FF); // Red
tirsdag 30. august 2011
Delphi Enumerable List - example
Just an example of a list of a specific type in delphi.
unit MyUtility; interface uses Classes, {TList} Chart; {TChart} type TChartList = class; TChartListEnumerator = record private FIndex: Integer; FList: TChartList; public constructor Create(AList: TChartList); function MoveNext: Boolean; inline; function GetCurrent: TChart; inline; property Current: TChart read GetCurrent; end; TChartList = class(TList) public procedure Add(AChart: TChart); function GetItem(i:Integer): TChart; function GetEnumerator: TChartListEnumerator; property Items[i:Integer]: TChart read GetItem; default; end; implementation {TChartList} procedure TChartList.Add(AChart: TChart); begin inherited Add(AChart); end; function TChartList.GetItem(i:Integer): TChart; begin Result := List[i]; end; function TChartList.GetEnumerator: TChartListEnumerator; begin Result := TChartListEnumerator.Create(Self); end; { TChartListEnumerator } constructor TChartListEnumerator.Create(AList: TChartList); begin FIndex := -1; FList := AList; end; function TChartListEnumerator.GetCurrent: TChart; begin Result := FList.List[FIndex]; end; function TChartListEnumerator.MoveNext: Boolean; begin Result := FIndex < FList.Count - 1; if Result then Inc(FIndex); end; end.And it's use:
var Chart: TChart; begin for Chart in ChartList do begin Chart.DoSomeThing(); end;
mandag 29. august 2011
How to clone a Delphi Form
In Visual Studio 2005 it's pretty easy to make a copy of an existing from directly from the project manager in the IDE (simply copy-paste with Ctrl-C and Ctrl-V). This is of course very useful instead of starting from scratch when you have a form that looks a lot like your new form will do.
The trick to do this in Delphi is:
The trick to do this in Delphi is:
- Do a "Save As" of the form in the file menu (.pas and .dfm will be copied and the unit name will be changed)
- Edit the saved as form to change the class name (easiest to do it in the designer)
- Add back the old form using "Add to Project...(Shift + F11)
tirsdag 23. august 2011
Fun with Tooltip - Delphi THintWindow
On most occasions getting a tooltip on a control is as simple as clicking enable and typing a string.
In the case of TeeChart you can get a tooltip on a Series by adding a tool called "Mark Tips".
After assigning this to a series, a tooltip will automatically show up when you hold the mouse over the series. BUT, It will not show up when holding the mouse over the series' mark, which is what I needed. So then I had to implement the tooltip functionality my self.
I used the
I used this method to show tooltip on both the SeriesMarks and the Series, so I could skip using the "Mark Tips" tool from TeeChart.
The
Following is the code that is called on the
That's it!
In the case of TeeChart you can get a tooltip on a Series by adding a tool called "Mark Tips".
After assigning this to a series, a tooltip will automatically show up when you hold the mouse over the series. BUT, It will not show up when holding the mouse over the series' mark, which is what I needed. So then I had to implement the tooltip functionality my self.
I used the
THintWindow
class to show a tooltip that looks the same as the other tooltips, although I had to set the (background) color
property to clInfoBk
in order for it to look the same. To find out what part of the chart the mouse was in I used the TeeChart function procedure TCustomChart.CalcClickedPart(Pos: TPoint; Var Part: TChartClickedPart);
. This will return a TChartClickedPart
record that will give you a lot of useful information, like if its a Series or SeriesMarks etc. It will the also have a reference to the series itself as well as the index of the series.I used this method to show tooltip on both the SeriesMarks and the Series, so I could skip using the "Mark Tips" tool from TeeChart.
The
THintWindow
was okay to use after reading the documentation. It has methods for calculating it's necessary width and height. It was too tricky to to find the size of the cursor so that it could be positioned at the bottom of the mouse cursor (like is normally done) so I simply placed it on top of the mouse cursor.Following is the code that is called on the
MouseMove
event:procedure TFrame_Plot.ShowEventSeriesToolTip(); var point: TPoint; clickedPart: TChartClickedPart; labelString: string; rect: TRect; begin point := Chart.GetCursorPos(); Chart.CalcClickedPart(point, clickedPart); Case clickedPart.Part of cpSeriesMarks, cpSeries: begin if (clickedPart.ASeries = SeriesInfoEvent) or (clickedPart.ASeries = SeriesEvent) then begin if Assigned(CV_HintWindow) and (CV_HintWindow.Tag <> clickedPart.PointIndex) then begin // Hide and free it! CV_HintWindow.ReleaseHandle(); FreeAndNil(CV_HintWindow); end; if not Assigned(CV_HintWindow) then begin labelString := clickedPart.ASeries.Labels[clickedPart.PointIndex]; CV_HintWindow := THintWindow.Create(Self); CV_HintWindow.Color := clInfoBk; // Calculate the WIDHT of the rectangle rect := CV_HintWindow.CalcHintRect(200, labelString, nil); // Find the position on screen to place the tooltip rect.TopLeft := Chart.ClientToScreen(point); // Move position so that it's above mouse cursor rect.Top := rect.Top - rect.Bottom; // Adjust Right and Bottom considering position rect.Right := rect.Right + rect.Left; rect.Bottom := rect.Bottom + rect.Top; // Use the tag to remember which Event we are showing tooltip for CV_HintWindow.Tag := clickedPart.PointIndex; // Show it! CV_HintWindow.ActivateHint(rect, labelString); end end else if Assigned(CV_HintWindow) then begin // Hide and free it! CV_HintWindow.ReleaseHandle(); FreeAndNil(CV_HintWindow); end; end; else if Assigned(CV_HintWindow) then begin // Hide and free it! CV_HintWindow.ReleaseHandle(); FreeAndNil(CV_HintWindow); end; end; end;
The result looks like this:
That's it!
fredag 19. august 2011
Implementing enumerators on delphi records
Implementing enumerators are pretty easy in Delphi and many articles exist on the topic:
http://hallvards.blogspot.com/2007/10/more-fun-with-enumerators.html
http://www.thedelphigeek.com/2007/03/fun-with-enumerators.html
For some reason, I had a simple record to hold a small array of another type where the use was to loop round and do some action on every type. I used a record instead of a class to avoid the Create/Destroy and since it was just used to hold some simple data.
The first thing I noticed was that the Enumerator had to be a class (and not a record as recommended here) because I could not have a forward declaration to a record. Since my "list type" was a record I had to "forward declare" the enumerator before the record type.
http://hallvards.blogspot.com/2007/10/more-fun-with-enumerators.html
http://www.thedelphigeek.com/2007/03/fun-with-enumerators.html
For some reason, I had a simple record to hold a small array of another type where the use was to loop round and do some action on every type. I used a record instead of a class to avoid the Create/Destroy and since it was just used to hold some simple data.
The first thing I noticed was that the Enumerator had to be a class (and not a record as recommended here) because I could not have a forward declaration to a record. Since my "list type" was a record I had to "forward declare" the enumerator before the record type.
TLongTrendFieldsEnumerator = class; TLongTrendFields = record private { Private declarations } PlotList: array[0..MAX_LONG_TREND_FIELDS] of TPlot; function GetItem(index : Integer) : TPlot; public { Public declarations } property Items[i:Integer] : TPlot read GetItem; default; function GetEnumerator: TLongTrendFieldsEnumerator; end;The next thing to think of is that the list type is a record, so we don't want to copy the instance when we pass it to the enumerator. So we use pointer instead, beginning with declaring a pointer type
TLongTrendFieldsEnumerator = class;
TLongTrendFieldsPointer = ^TLongTrendFields;
TLongTrendFields = record
private
...
So then the enumerator class will look like this:
TLongTrendFieldsEnumerator = class
private
index: Integer;
fields: TLongTrendFieldsPointer;
public
constructor Create(aFields: TLongTrendFieldsPointer);
function MoveNext: Boolean;
function GetCurrent: TPlot;
property Current: TPlot read GetCurrent;
end;
The only difference in the implementation is that when the list type creates the enumerator it has to send a reference/pointer to the enumerator's constructor.
function TLongTrendFields.GetEnumerator: TLongTrendFieldsEnumerator;
begin
Result := TLongTrendFieldsEnumerator.Create(@Self);
end;
The rest of the implementation is identical to the other examples (without pointers) thanks to Delphi's nice pointer syntax handling!
fredag 5. august 2011
Dynamically adding a GRAPHIC field to an existing Paradox table
I wanted to add a few new fields to an existing Paradox database table. We already had a method for adding new fields. This is using SQL to add new fields kinda like:
so the

According to Embarcadero:
'ALTER TABLE ' + TableName + ' ADD COLUMN ' + Field + ' ' + FieldType
so the
FieldType
is a string and one of that parameters. So I thought GRAPHIC would be a valid type. But no, it complains with the message "Capability not supported":
According to Embarcadero:
"This error is returned by the BDE when the BDE parses an SQL string to be sent to a server and the syntax of the string is not supported by the BDE"So, as of now I still don't have a solution to this problem.
NOTE: Using BLOB as FieldName works just fine (but testing this caused other problems...)
EDIT: 2011-08-25
Using MEMO as the type gave the same error. Using BLOB works and actually creates a MEMO field! :)
Only workaround found was to delete the table and create a new one using Delphi
Useful link for simple SQL coding:
http://www.thedbcommunity.com/index.php?option=com_content&task=view&id=138&Itemid=46
This also mentions under "Unsupported Capabilities" that "There are a number of table modifications which cannot be performed using Local SQL, such as foreign key constraints, range limitations, picture settings, etc."
EDIT: 2011-08-25
Using MEMO as the type gave the same error. Using BLOB works and actually creates a MEMO field! :)
Only workaround found was to delete the table and create a new one using Delphi
TTable
class and field type ftGraphic
- FieldDefs.Add('Icon', ftGraphic, 0, False);
Useful link for simple SQL coding:
http://www.thedbcommunity.com/index.php?option=com_content&task=view&id=138&Itemid=46
This also mentions under "Unsupported Capabilities" that "There are a number of table modifications which cannot be performed using Local SQL, such as foreign key constraints, range limitations, picture settings, etc."
Getting an Image into QuickReport
The problem was that when I first configured the QReport, the database field was MEMO and not GRAPHIC. This information is stored in the .QR2 report file. And even though I corrected this field in the database using Database Manager, it would not be updated in the QuickReport.
The solution was to remove the dataset and add it again. This time the field correctly showed up as GRAPHIC, and the image showed up beautifully :-)
One possible solution could be to only remove the field in the dataset and then add it again.
The initial code for getting in image into the DB was:
Although this works fine, the image file has to be available on the disk when the program runs. A better solution is to get the images included in the .exe as an embedded resource. The simplest way to achieve this was to include a TImageList on a form, and populate this with the images I needed. Then use the following code to put them in the database:
The initial code for getting in image into the DB was:
(FieldByName('Icon') as TGraphicField).LoadFromFile('\path\to\image.bmp');
Although this works fine, the image file has to be available on the disk when the program runs. A better solution is to get the images included in the .exe as an embedded resource. The simplest way to achieve this was to include a TImageList on a form, and populate this with the images I needed. Then use the following code to put them in the database:
procedure InsertImageToDB(Field: TField; ImageIndex: Integer);
var
stream: TStream;
bmp: TBitmap;
begin
bmp := TBitmap.Create();
stream := Field.DataSet.CreateBlobStream(Field, bmWrite);
try
Frm.ImageList.GetBitmap(ImageIndex, bmp);
bmp.SaveToStream(stream);
finally
stream.Free;
bmp.Free;
end;
end;
This has to be included in a Edit()...Post() block to get it posted to the DB.
Abonner på:
Innlegg (Atom)