| Bug # | Delphi versions | Description |
| 37 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TCustomListView See TListView |
| 38 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TDateTimePicker Problems with Year=00..09 and with property MinDate |
| 39 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TDateTimePicker The TDateTimePicker component in Delphi 3.0 has no TabOrder property |
| 40 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TDateTimePicker If you choose any date of the year 1899 or backwards, the day that you chose is incremented by one. |
| 469 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TDateTimePicker Can't get the TDateTimePicker.OnUserInput event to fire. |
| 47 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
THeaderControl Using a THeaderControl you cannot change the color of the font but you can change everything else about the font. (Maybe black is a standard but why not the font NOT being bold or italic etc). Please read the comments from Martin Scott on this. |
| 49 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TImageList TImageLists in form templates are not loaded properly in inherited forms. |
| 50 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TImageList TImageList drag & drop does not finish |
| 57 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TListItem/TListView If the EditCaption method is called when the list view is not focused, the in-place editing does not take place. |
| 58 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TListItem/TTreeView There is a bug in TListView and TTreeView concerning drag & drop operations. |
| 59 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TListItem/TTreeView The bug in TListView and TTreeView concerning drag & drop operations. can also be fixed by fixing TCustomListView.Delete. |
| 409 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TListView If you select an item (in code) which is not visible, the TListView does not scroll that item into view. |
| 443 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TListView When you add an item to a ListView which has checkboxes, all checkboxes are cleared. |
| 480 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TPageControl TPageControl's Tabsheets do not respond to accelerator keys |
| 75 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit The default value of zero for the MaxLength property limits the number of characters to 65536, while the Help promises 'no limit'. Setting it to a high number (e.g. 200000000) works as expected. |
| 76 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit In some cases when loading RTF files into TRichEdit, FirstIndents of paragraphs disappear or display incorrectly |
| 77 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit Exception or wrong return value on EM_POSFROMCHAR message. |
| 78 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit After resizing (enlarging), part of the client area will not be painted anymore. This seems to occur under NT 3.51 only. |
| 79 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit TRichEdit.Visible := False fails if the RichEdit contains text at design-time |
| 80 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TRichEdit Documentation bug: the PageRect property contains co-ordinates in pixels, not twips |
| 83 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TStatusBar TStatusBar seems to ignore color changes in the font (both at design time and at run time. |
| 84 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TStatusBar Setting Bevel to None does not redraw the control immediatly |
| 474 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TToolBar The TToolButton.Visible property is not persisted between sessions. Specifically, it gets reset back to "True" when a project gets reloaded. |
| 482 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TToolBar Captions of buttons on TToolBar don't get the ToolBar's font color |
| 93 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TToolBar/TToolButton Buttons classes derived from TToolButton don't display properly on a TToolBar. |
| 94 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TToolBar/TToolButton A button on a TToolBar disabled in the parent form's OnCreate event causes all the toolbar buttons to be invisible |
| 95 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView DoEndDrag in TTreeView does not seem to be executed. |
| 96 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView Having nodes that are wider than the window may cause nasty problems |
| 97 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView The Help button does nothing. |
| 98 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView You cannot change the color of the font. Please read the comments from Martin Scott on this. |
| 99 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView If you change 'Color' property (background) to anything besides white you will see that the text background is ALWAYS white. |
| 100 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView Bug when editing the Items |
| 101 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView Bug in MoveTo method Only occurred in Delphi 2.0 |
| 487 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView The TTreeNode.MoveTo procedure does not work if you specify naAddChild or naAddChildFirst. |
| 404 | 1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 |
TTreeView/TListView TTreeView's OnDeletion event occurs "too late": it may occur AFTER form's OnDestroy |
Bug #38; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Unknown | Unknown | Unknown | Unknown | Fixed | Fixed |
Chuck Garvey:
Meade is correct. I have the same problem. I also have a problem with the
MinDate property of this component. It returns an error whenever I enter a
year other than 12/31/99. HELP!!
Bug #39; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Unknown | Unknown | Fixed | Fixed | Fixed |
property TabOrder;Alternatively you can create a new component derived from TDateTimePicker:
type
TDateTimePicker2 = class(TDateTimePicker)
published
property TabOrder;
end;
Bug #40; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Exists | Unknown | Unknown | Unknown | Unknown |
procedure TForm1.DateTimePicker1CloseUp(Sender: TObject);
begin
if DateTimePicker1.Date < -1.0 then
DateTimePicker1.Date := DateTimePicker1.Date - 1;
end;
Bug #469; last modified: 27-Dec-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Exists | Exists | Exists | Exists | Exists |
To reproduce the bug
Bug #49; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown |
My first sign that something was wrong was when I noticed that the TImageList in the inherited form had extra images in it. This behavior couldn't be reproduced.
For example:
If you have a parent form with a TImageList containing 10 images, at
run-time, the child form that inherits from this form will have 20 images.
Bug #50; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Exists | Unknown | Unknown | Unknown | Unknown | Unknown |
DragMode := dmAutomatic
LargeImages := ImageList1
MultiSelect := True (very important!)
ViewStyle := vsIcon (that is the default)
Add the following code to the Button's OnClick handler:
procedure TForm1.Button1Click(Sender: TObject); var NewItem: TListItem; begin NewItem := ListView1.Items.Add; NewItem.Caption := 'Item!'; NewItem.ImageIndex := ImageList1.AddIcon(Application.Icon) end;
Controls.pas:
procedure DragDone(Drop: Boolean);
var
...
begin
DragSave := nil;
DragControl := nil;
try
DragObject.ReleaseCapture(DragCapture);
DragSave := DragObject;
if DragImageList <> nil then
DragImageList.EndDrag
else
begin
{$IFDEF FixImagelistDDBug}
ImageList_EndDrag;
{$ENDIF}
Windows.SetCursor(DragSaveCursor)
end;
try
...
end;
A possible work around is to add a corresponding line to the TImageView's
EndDrag event handler:
procedure TForm1.ListView1EndDrag(...); begin ImageList_EndDrag; end;after manually adding "ComCtrl" to the uses clause.
Bug #57; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Unknown | Unknown | Unknown | Unknown | Fixed | Fixed |
ListView1.Selected.EditCaption;The above code starts the editing only if the list view has the focus. If the method was called for example from a button OnClick handler, nothing would happen. This is true even if HideSelection is False.
I'm sorry that I cannot decide if this is a TListItem or a TListView bug: the two classes are linked too strongly to be sure. ;-) Because EditCaption is a method of TListItem, I think it should be listed as such.
ListView1.SetFocus; { set focus first }
ListView1.Selected.EditCaption;
Please note that the current EditCaption implementation simply sends a
Windows message to the list view, and thus this is not a real VCL bug.
Still, this bug would be very easy to avoid, if the VCL developers would
have included the SetFocus call in the implementation.
Bug #58; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Fixed | Fixed | Fixed | Fixed | Fixed | Fixed |
To reproduce the bug:
procedure TCustomListView.SetDropTarget(Value: TListItem);
Good news: Borland applied the patch that's given below to Delphi 3
FDeleting := True;
If self = Owner.Owner.FLastDropTarget then
Owner.Owner.FLastDropTarget := nil;
procedure TCustomListView.Delete(Item: TListItem);
begin
if (Item <> nil) and not Item.FProcessedDeleting then
begin
if Assigned(FOnDeletion) then FOnDeletion(Self, Item);
{ADD THIS LINE TO FIX BUG}
if Item = FLastDropTarget then FLastDropTarget := nil;
Item.FProcessedDeleting := True;
Item.Delete;
end;
end;
Bug #409; last modified: 7-May-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Gotcha | Gotcha | Gotcha | Gotcha | Gotcha | Gotcha | Gotcha |
I've done TListView.Selected and TListView.ItemFocused together, and sure enough the item has been selected and given a focus box, but if the item is out of view, the TListView doesn't scroll to show it.
Bug #443; last modified: 17-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Absent | Absent | Absent | Exists | Exists | Fixed |
procedure TForm1.Button1Click(Sender: TObject); var NewItem: TListItem; begin Newitem := ListView1.Items.Add; NewItem.Caption := 'new item' end;
Cause:
The cause is a change to the VCL between Delphi 3 and Delphi 4. The
offending routine in ComCtrls.pas is:
constructor TListItem.Create(AOwner: TListItems);
begin
FOwner := AOwner;
FSubItems := TSubItems.Create(Self);
FOverlayIndex := -1;
FStateIndex := -1;
if Owner.Owner.Checkboxes and Owner.Owner.HandleAllocated then
SetChecked(False);
end;
The last two lines are new in Delphi 4. The problem is that SetChecked
sets the item's checked state by
ListView_SetCheckState(LV.Handle, Index, Value);but the item hasn't yet been added to the collection and so Index is -1. Thus this call clears the checked state of all existing items.
Note:
I've reported this to Borland. It was acknowledged as
bug report 20690.
TExtListView = class(TListView)
protected
function CreateListItem: TListItem; override;
end;
{...}
function TExtListView.CreateListItem: TListItem;
{$IFDEF VER120}
var SaveHandle: HWnd;
begin
SaveHandle:= WindowHandle;
WindowHandle:= 0;
try
Result:= inherited CreateListItem;
finally
WindowHandle:= SaveHandle;
end;
end;
{$ELSE}
begin
Result:= inherited CreateListItem;
end;
{$ENDIF}
Then the call in TListItem.Create to Owner.Owner.HandleAllocatd will return
false.
I'm not sure why Inprise tries to explicitly set the check-state in the constructor. It may be because calling ListView_InsertItem results in immediate LVN_ITEMCHANGING/CHANGED notifications specifying the unchecked box as the stateImage (at least in my version of COMCTRL32.DLL -- 4.72.3110.1). I think Inprise might have been trying to suppress these notifications since in fact the TListItem hasn't really changed (new items are unchecked by default). At any rate, people should be aware that they will get these notifications. Changing the parameters to ListView_InsertItem so that they specify the unchecked box as the StateImage does not suppress the notifications; they get sent anyway with the TNMListView's uNewState = uOldState.
One other note, this bug can have a drastic impact on performance when adding a large number of items to a ListView because, with each item added, the ListView has to iterate through all its items and uncheck them. If your ListViews under D4 are mysteriously slow, this could be the cause.
Bug #480; last modified: 17-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Exists | Exists | Exists | Fixed | Fixed | Fixed |
Causes:
Looking through the VCL source, it is evident that both TPageControl
and its ancestor TCustomTabControl, do not implement the CMDialogChar
message to process the accelerator key for Tabsheet changes - as other
TWinControls do. It seems the Delphi development team has completely
overlooked accelerator keys for TPageControl, even though TTabsheet
captions will be shown to have an accelerator if the caption contains
an ampersand.
TNewPageControl = class(TPageControl);
private
procedure CMDialogChar(var Message : TCMDialogChar); message
CM_DialogChar;
end;
procedure TNewPageControl.CMDialogChar(var Message : TCMDialogChar);
var
i : integer;
begin
if ssAlt in KeyDataToShiftState(Message.KeyData) then
for i := 0 to PageCount - 1 do
if IsAccel(Message.CharCode, Pages[i].Caption) and (CanChange)
and (Pages[i].TabVisible) then
begin
ActivePage := Pages[i];
Message.result := 1;
Change;
exit;
end;
inherited;
end;
Bug #76; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown |
In other words: if the first line of a paragraph is indented 1 cm, then the RichEdit will display the entire paragraph indented by 1 cm. I think there are two mistakes here:
Bug #77; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown |
var I, J: Longint; P: TPoint; begin P.X := X; P.Y := Y; I := LongInt(@P); J := SendMessage(RichEdit1.Handle, Messages.em_CharFromPos, 0, I); end;
2. If you don't have the VCL sources:
Check your sources for EM_POSFROMCHAR and make sure the proper value
and parameters are used. Many times one can just leave the RichEdit unit
out of the uses clause.
Bug #78; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Exists | Unknown | Unknown | Unknown | Unknown | Unknown |
procedure TForm1.Button1Click(Sender: TObject); begin RichEdit1.Height := RichEdit1.Height + 10; end;
Bug #79; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Exists | Unknown | Unknown | Unknown | Fixed | Fixed |
The problem doesn't so much lie in TRichEdit as in TRichEditStrings, and possibly Windows 95. When TRichEditStrings calls its SetUpdateState() method, it sends a WM_SETREDRAW message. When Windows processes this message it (somehow) sets the WS_VISIBLE bit in the TRichEdit's Window-Style. However, because this happens behind Delphi's back, the TRichEdit.Visible property is still False. This is why an explicit Visible := False;
// WM_SETREDRAW causes visibility side effects in memo controls Memo.Perform(CM_SHOWINGCHANGED,0,0); // This reasserts the visibility we want
...
if not Updating then begin
{
This is the missing line of code to make TRichEdit visible/invisible
}
RichEdit.Perform(CM_SHOWINGCHANGED,0,0);
RichEdit.Refresh;
...
Bug #80; last modified: 28-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Gotcha | Exists | Exists | Exists | Exists | Exists | Exists |
else begin
rc.left := PageRect.Left * 1440 div LogX;
rc.top := PageRect.Top * 1440 div LogY;
rc.right := PageRect.Right * 1440 div LogX;
rc.bottom := PageRect.Bottom * 1440 div LogY;
end;
What this does is convert from pixels *TO* twips.
The bug is in Delphi 3.0 (3.01 could not be checked yet) and Delphi 2.01, although in 2.01, PageRect was undocumented, so it's not really a bug there.
To reproduce the bug:
Try to manually set PageRect to a know value of twips, say for 2" margins:
MyRichEdit.PageRect := Rect(2*1440, 2*1440, round(6.5*1440), 9*1440);
MyRichEdit.Print('test');
It won't work. But if you use pixels, it will:
var
LogX, LogY: integer;
begin
LogX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
LogY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
MyRichEdit.PageRect := Rect(2*LogX, 2*LogY, round(6.5*LogX), 9*LogY);
MyRichEdit.Print('test');
end;
Also, it might be good to note that you have to manually adjust for the
non-printable area, too. If you use the above, and your printer has a
non-printable area of 1/2" on the left, you will really get a left margin
of 2 1/2" inches. I left that out in the example to make the code a little
more clear.
Bug #474; last modified: 6-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| Unknown | Unknown | Unknown | Unknown | Exists | Unknown | Fixed | Fixed |
Interestingly enough, after closing the project, the .DFM shows the correct values for the Visible property: False. For some reason, the error occurs during the reload of the project.
Bug #482; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Exists | Exists | Exists | Exists | Exists |
However, this is not the case. Try it! If you set Toolbar1.ShowCaptions to true and Toolbar1.Font.Color equal to clWhite, then add a TLabel to the toolbar, the label will be white (as expected). If you then right-click and add a new TToolButton, it's caption will be clWindowText (usually black)!!!
Erik Berry commented on this:
Since TToolButton doesn't have a ParentFont or a font property, this
might be a limitation of the Win32 control, and not a Delphi bug.
Bug #93; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Unknown | Unknown | Unknown | Unknown | Unknown |
Bug #94; last modified: 25-Oct-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | N/A | Exists | Unknown | Unknown | Unknown | Fixed | Fixed |
Bug #95; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Fixed | Fixed | Fixed | Fixed | Fixed | Fixed |
Possible cause
The problem might be that TTreeView uses the DoEndDrag method of TCustomTreeView,
which is dynamic. The TCustom.DoEndDrag calls inherited DoEndDrag of TControl,
which also is dynamic. The TCustom.DoEndDrag hooks on to the OnEndDrag
event. I think the DoEndDrag of TCustomTreeView should have been declared
with 'override' instead of with 'dynamic'. The odd thing is, if I add an
event handler to the OnEndDrag event of "st", the event handler is executed
while the DoEndDrag of "st" does not seem to be executed. I would expect
it the other way around.
===============================================================
The unit ComCtrls in the Delphi VCL library:
===============================================================
interface
TCustomTreeView = class(TTreeView)
...
protected
procedure DoEndDrag(Target: TObject; X, Y: Integer); dynamic;
...
end;
implementation
procedure TCustomTreeView.DoEndDrag(Target: TObject; X, Y: Integer);
begin
inherited DoEndDrag(Target, X, Y);
FLastDropTarget := nil;
end;
===============================================================
The unit Controls in the Delphi VCL library:
===============================================================
interface
TControl
...
protected
procedure DoEndDrag(Target: TObject; X, Y: Integer); dynamic;
...
end;
implementation
procedure TControl.DoEndDrag(Target: TObject; X, Y: Integer);
begin
if Assigned(FOnEndDrag) then FOnEndDrag(Self, Target, X, Y);
end;
Bug #96; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Unknown | Unknown | Unknown | Unknown | Unknown | Unknown |
Bug #100; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Exists | Fixed | Fixed | Fixed | Fixed | Fixed | Fixed |
Bug #101; last modified: before April 1998| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| N/A | Fixed | Fixed | Fixed | Fixed | Fixed | Fixed | Fixed |
procedure TForm1.TreeView1DblClick(Sender: TObject);
var
TN1, TN2, TN3: TTreeNode;
begin
{Label1.Caption := TreeView1.Selected.Text}
with TreeView1
do begin
TN1 := Items.Add(nil, 'A');
TN2 := Items.Add(nil, 'B');
TN3 := Items.Add(nil, 'C');
TN3.MoveTo(TN2, naAddChild);
TN1.MoveTo(TN3, naAddChild);
end;
end;
Bug #487; last modified: 27-Dec-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| Absent | Absent | Absent | Absent | Absent | Exists | Exists | Fixed |
procedure TTreeNode.InternalMove(ParentNode, Node: TTreeNode;
HItem: HTreeItem; AddMode: TAddMode);
var
I: Integer;
NodeId: HTreeItem;
TreeViewItem: TTVItem;
Children: Boolean;
IsSelected: Boolean;
begin
// Commented out because it makes MoveTo not work.
// if ParentNode = Node then Exit;
Owner.ClearCache;
if (AddMode = taInsert) and (Node <> nil) then
NodeId := Node.ItemId else
NodeId := nil;
Children := HasChildren;
IsSelected := Selected;
if (Parent <> nil) and (Parent.CompareCount(1)) then
begin
Parent.Expanded := False;
Parent.HasChildren := False;
end;
with TreeViewItem do
begin
mask := TVIF_PARAM;
hItem := ItemId;
lParam := 0;
end;
TreeView_SetItem(Handle, TreeViewItem);
with Owner do
HItem := AddItem(HItem, NodeId, CreateItem(Self), AddMode);
if HItem = nil then
raise EOutOfResources.Create(sInsertError);
for I := Count - 1 downto 0 do
Item[I].InternalMove(Self, nil, HItem, taAddFirst);
TreeView_DeleteItem(Handle, ItemId);
FItemId := HItem;
Assign(Self);
HasChildren := Children;
Selected := IsSelected;
end;
procedure TTreeNode.MoveTo(Destination: TTreeNode; Mode:
TNodeAttachMode);
var
AddMode: TAddMode;
Node: TTreeNode;
HItem: HTreeItem;
OldOnChanging: TTVChangingEvent;
OldOnChange: TTVChangedEvent;
begin
//Made by KFP to fix the MoveTo bug introduced by borland in D4.
if Self = Destination then exit;
//End Insert
OldOnChanging := TreeView.OnChanging;
OldOnChange := TreeView.OnChange;
TreeView.OnChanging := nil;
TreeView.OnChange := nil;
try
if (Destination = nil) or not Destination.HasAsParent(Self) then
begin
AddMode := taAdd;
if (Destination <> nil) and not (Mode in [naAddChild, naAddChildFirst]) then
Node := Destination.Parent else
Node := Destination;
case Mode of
naAdd,
naAddChild: AddMode := taAdd;
naAddFirst,
naAddChildFirst: AddMode := taAddFirst;
naInsert:
begin
Destination := Destination.GetPrevSibling;
if Destination = nil then AddMode := taAddFirst
else AddMode := taInsert;
end;
end;
if Node <> nil then
HItem := Node.ItemId else
HItem := nil;
InternalMove(Node, Destination, HItem, AddMode);
Node := Parent;
if Node <> nil then
begin
Node.HasChildren := True;
Node.Expanded := True;
end;
end;
finally
TreeView.OnChanging := OldOnChanging;
TreeView.OnChange := OldOnChange;
end;
end;
Bug #404; last modified: 5-May-98| 1.02 | 2.01 | 3.0 | 3.01 | 3.02 | 4.0 | 4.01 | 4.02 |
| Unknown | Unknown | Unknown | Unknown | Gotcha | Gotcha | Gotcha | Gotcha |
Comment from checker:
I've looked at this bug report and can verify that the reported
behavior is seen. The same problem also applies to TListView, BTW.
However, I wouldn't call this a bug, but a documentation omission. In
the documentation for OnDeletion, Borland should have mentioned that
the event could be fired after the Form's OnDestroy event has run.
Example code
When you run the code you will see that FormDestroy runs before both
TreeView1Deletion and ListView1Deletion. The reason for this is:
In TCusomForm.Destroy you have this logic:
destructor TCustomForm.Destroy;
begin
// ...
if Assigned(FOnDestroy) then
try
FOnDestroy(Self);
except
Application.HandleException(Self);
end;
if HandleAllocated then DestroyWindowHandle;
//...
inherited Destroy;
end;
The FOnDestroy calls the user defined FormDestroy event handler. Then
the DestroyWindowHandle will destroy the Windows handle of the form
and all other handles owned by the form, including the handles for
TreeView and ListView. This will trigger notification messages that
will eventually call the OnDeletion events. Finally the VCL components
owned by the form will be freed in the inherited destructor.
As Sergey says, this behavior can cause problems if the OnDeletion event handler depends on a resource freed by the OnDestroy event handler. In addition to his workaround (below), we could add a sanity check in the OnDeletion event handler. Either:
if Assigned(MyResource) then
....
or
if not (csDestroying in ComponentState) then
...
I wouldn't call this a bug, because there is no good way to fix it at
the VCL level. The problem is rather that we see unexpected and
undocumented behavior. Fixing this in VCL (by not calling OnDeletion
after the forms OnDestroy has run) could be worse than the current
behavior, depending on the needs of the programmer.
procedure TForm1.FormDestroy(Sender: TObject);
begin
{ ... }
TreeView1.Free;
TreeView1 := nil;
{ ... }
end;