Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

ElTreeInplaceDateTimePicker on ElXTree raises Contol '' has no parent window. LMD ElPack 2018



If the DateTimePicker is editing, and you click outside it on the tree, it raises this error. I AM on the LMD ElPack 2018.0(22-01/2018).
On Rad Studio, Delphi, Tokyo 10.2, update 2.
An example with instructions is attached. 

Best regards,
Louis Kriel


Comments

  • 12 Comments sorted by Votes Date Added
  • Bug Fix PLEASE. I am trying to find a workaround, but unsuccessful so far.
  • <Removed>

  • I've checked more and can now confirm the issue (happen in 10.2 only).
    To workaround please add "if HandleAllocated then" before "inherited" in TElDateTimePicker.WMKillFocus method:

    procedure TElDateTimePicker.WMKillFocus(var Msg : TWMKillFocus);  { private }
    begin
      FFocused := false;
      if HandleAllocated then // <-------------
        inherited;
      if LMDSIWindowsVistaUp and IsThemed and HandleAllocated then
        DrawFlatBorder;
      if Flat then
        if HandleAllocated then
          UpdateFrame;
    ...
  • The same thing happened to me, but using TElTreeInplaceEdit.   I am using Delphi 10.2.2

    The fix for TElDateTimePicker that you give above doesn't work here since there is no WMKillFocus event in ElTreeStdEditors.

    Can you confirm this problem and suggest a fix please.
  • I connot reproduce this. For me simple text inplace editing (TElTreeInplaceEdit) works fine. Can you specify your setup and steps to reproduce more precisely.
  • Thanks, Eugene:

    I have a TElXTree on a form with 7 sections. The 2nd section is a Text field that is marked Editable. I have a TElTreeInplaceEdit on the form associated with the TElXTree.

    I use 3 events for the InplaceEdit:
    - InplaceEditBeforeOperation  
    - InplaceEditAfterOperation
    - InplaceEditEditorOnKeyUp

    The first two are harmless. I don't know if the 3rd is causing the problem, but I'll give you my code::

    procedure TOrganizePages.TagsDisplayInplaceEditEditorOnKeyUp(Sender: TObject;
      var Key: Word; Shift: TShiftState);
    begin
      DoEditorOnKeyUp(TagsList, TDisplayAsCol, TCustomElEdit(Sender), Key, Shift);
    end;

    I do this to allow processing of some special keys on your form:

    procedure DoEditorOnKeyUp(ElXTree: TElXTree; const EditColumn: integer; var ElEdit: TCustomElEdit;
          var Key: word; Shift: TShiftState);
    var
      CurItem: TElXTreeItem;
      INext: Integer;
    begin
    case Key of
      VK_F2:
        ElXTree.EndEdit(false);
      $41: { A part of Ctrl-A }
        if ssCtrl in Shift then { Ctrl part of Ctrl-A }
          ElEdit.SelectAll;
      $5a: { Z part of Ctrl-Z }
        if ssCtrl in Shift then { Ctrl part of Ctrl-Z }
          ElEdit.Undo;
      VK_PRIOR: begin
        ElXTree.Items.BeginUpdate;
       { Note: this isn't perfect from near the bottom of the tree, but it's close enough }
        INext := ElXTree.TopIndex -(ElXTree.BottomIndex - ElXTree.ItemFocused.AbsoluteIndex);
        if ElXTree.BottomIndex >= (ElXTree.Items.Count - 1) then
          INext := INext - 1;
        if INext < 0 then INext := 0;
        ElXTree.EndEdit(false);
        ElXTree.Perform(WM_VSCROLL, SB_PAGEUP, 0);
        ElXTree.ItemFocused := ElXTree.Items[INext];
        ElXTree.Items.EndUpdate;
      end;
      VK_NEXT: begin
        ElXTree.Items.BeginUpdate;
        INext := ElXTree.BottomIndex + ElXTree.ItemFocused.AbsoluteIndex - ElXTree.TopIndex;
        if INext > ElXTree.Items.Count then INext := ElXTree.Items.Count - 1;
        ElXTree.EndEdit(false);
        ElXTree.Perform(WM_VSCROLL, SB_PAGEDOWN, 0);
        ElXTree.ItemFocused := ElXTree.Items[INext];
        ElXTree.Items.EndUpdate;
      end;
      VK_HOME: begin
        if ssCtrl in Shift then { Ctrl part of Ctrl-Home } begin
          ElXTree.Items.BeginUpdate;
          ElXTree.EndEdit(false);
          ElXTree.ItemFocused := ElXTree.Items[0];
          ElXTree.Items.EndUpdate;
          ElXTree.ItemFocused.MakeVisible;
        end;
      end;
      VK_END: begin
        if ssCtrl in Shift then { Ctrl part of Ctrl-End } begin
          ElXTree.Items.BeginUpdate;
          ElXTree.EndEdit(false);
          ElXTree.ItemFocused := ElXTree.Items[ElXTree.Items.Count-1];
          ElXTree.Items.EndUpdate;
          ElXTree.ItemFocused.MakeVisible;
        end;
      end;
      VK_DOWN, VK_RETURN:
        begin
          ElXTree.Items.BeginUpdate;
          CurItem := ElXTree.ItemFocused;
          CurItem := CurItem.GetNext;
          while CurItem <> nil do begin
            ElXTree.ItemFocused := CurItem;
            if CurItem.IsVisible and CurItem.AllowEdit then begin
              ElXTree.EndEdit(false);
              ElXTree.EditItem(CurItem, EditColumn);
              break;
            end;
            CurItem := CurItem.GetNext;
          end;
          if CurItem = nil then { at the bottom }
            ElXTree.EditItem(ElXTree.ItemFocused, EditColumn);
          ElXTree.Items.EndUpdate;
          ElXTree.ItemFocused.MakeVisible;
          Key := 0;
        end;
      VK_UP:
        begin
          ElXTree.Items.BeginUpdate;
          CurItem := ElXTree.ItemFocused;
          CurItem := CurItem.GetPrev;
          while CurItem <> nil do begin
            ElXTree.ItemFocused := CurItem;
            if CurItem.IsVisible and CurItem.AllowEdit then begin
              ElXTree.EndEdit(false);
              ElXTree.EditItem(CurItem, EditColumn);
              break;
            end;
            CurItem := CurItem.GetPrev;
          end;
          if CurItem = nil then { at the top }
            ElXTree.EditItem(ElXTree.ItemFocused, EditColumn);
          ElXTree.Items.EndUpdate;
          ElXTree.ItemFocused.MakeVisible;
          Key := 0;
        end;
      end;
    end;

    If I change text in the field and just hit Enter, or any of the keys in the above routine (e.g. arrow up, Home, etc) , there is no problem and it works as it should.

    But if I change text in the field and then use the mouse to click on another field or any other window, when I'm in the Delphi debugger, it brings up a Debugger Exception Notification window that says: "Project raised exception class EInvalidOperation with message 'Control '' has no parent window' leading to the Windows exception "Control '' has no parent window."

    If I break the debugger a that exception, the line in ElTreeStdEditors it was at was the last line of EditorWndProc:
         SaveWndProc(Message);

    And now that you've got me to look, I see that I had to modify that routine so that I could catch the Return key myself.

    This is the routine I use:

    procedure TElTreeInplaceEdit.EditorWndProc(var Message : TMessage);
    var
      InputValid : boolean;
    begin
      if Message.Msg = WM_GETDLGCODE then
      begin
        inherited;
        Message.Result := Message.Result or DLGC_WANTCHARS or DLGC_WANTARROWS or DLGC_WANTALLKEYS;
      end
      else
      if Message.Msg = WM_KEYDOWN then
      begin
        TriggerKeyDown(TWMKey(Message));
        with TWMKey(Message) do
        begin
          if KeyDataToShiftState(KeyData) = [] then
          begin
    (* LK 31 May 2011 - Removed VK_RETURN so I can catch it myself
            if CharCode = VK_RETURN then
            begin
              InputValid := true;
              FEditing := false;
              TriggerValidateResult(InputValid);
              FEditing := true;
              if InputValid then
              begin
                CompleteOperation(true);
                CharCode := 0;
                exit;
              end
              else
                Editor.SetFocus;
              CharCode := 0;
            end
            else
    // LK 31 May 2011 - End of Removed VK_RETURN so I can catch it myself *)
            if CharCode = VK_ESCAPE then
            begin
              CompleteOperation(false);
              CharCode := 0;
              exit;
            end;
          end;
        end;
      end
      else
      if (Message.Msg = WM_CANCELMODE) or
         ((Message.Msg = CM_CANCELMODE) and
          (TObject(Pointer(Message.lParam)) <> Editor)) or
          (Message.Msg = WM_KILLFOCUS) then
        if FEditing then
        begin
          if THackElTree(Tree).FExplorerEditMode then
          begin
            EndEditWithInputChecked;
          end
          else
            CompleteOperation(false);

          if Message.Msg <> CM_CANCELMODE then
            SendMessage(THackElTree(Tree).View.Handle, CM_EXIT, 0, 0);
        end;
      SaveWndProc(Message);
    end;

    This worked without problem until recently, which I blame on Delphi 10.2.2.  When I saw this other post with the exact same problem, I thought there must be a simple solution.  Maybe 10.2.3 which just came out will fix the issue, but it's not nice when they make updates that breaks your (or my) code. 

    If you can see what might be causing this, or a possible patch for this, please let me know.   

    Also feel free to also give me any suggestions to capture keys like I'm doing if you think there's a better way.

    If you need more screenshots or code than I can supply here, please email me:  lkessler at lkessler dot com

    Thanks.

    Louis Kessler
    Winnipeg, Manitoba, Canada

  • Will issue occure without event handlers?
  • Good question.  

    I removed the handler, and yes, the issue still happens when editing the text and (without pressing Enter) clicking anywhere outside what was edited.

    And just to make sure, I added back the code that I removed, and the issue still happens.  So it does not appear to have anything to do with the handler I added or the changes I made.

    Everything was working fine less than a year ago with my handler and code changes. I am fairly certain it is a similar problem to DateTimePicker from the original post on this thread that you found a fix for, likely caused by Delphi 10.2.x.

    Louis
  • Eugene,

    The debug trace includes the following Elpack routines:

    ElXTree.TElXTreeView.WndProc - the last line:   inherited
    which calls a few vcl routines and then
    ElXTree.TElXTreeView.WMLButtonDown, and then 
    ElXTree.TElXTreeView.IntLButtonDown - the SetFocus at the 3rd line from the bottom, and then
    ElXTree.TElXTreeView.SetFocus - the "inherited SelfFocus" line

    I tried, as you suggestied to Louis Kriel above, to put "if HandleAllocated then" before any "inherited" lines in any of these routines. That did not fix the issue.

    I also went to ElXTree and tried the same, putting "if HandleAllocated then" before any "inherited" lines in:
    TElXTreeView.WMKillFocus,
    TCustomElXTree.WMKillFocus,
    TElXTreeView.WMSetFocus,
    TCustomElXTree.WMSetFocus

    but none of those fixed the issue either.

    Louis

  • I found it!!!!!!!!!!!!!!

    At the bottom of TElTreeInplaceEdit.EditorWndProc is:

      if (Message.Msg = WM_CANCELMODE) or
         ((Message.Msg = CM_CANCELMODE) and
          (TObject(Pointer(Message.lParam)) <> Editor)) or
          (Message.Msg = WM_KILLFOCUS) then
        if FEditing then
        begin
          if THackElTree(Tree).FExplorerEditMode then
          begin
            EndEditWithInputChecked;
          end
          else
            CompleteOperation(false);
          if Message.Msg <> CM_CANCELMODE then
            SendMessage(THackElTree(Tree).View.Handle, CM_EXIT, 0, 0);
        end;
      SaveWndProc(Message);

    I noticed similar code in:
    TElTreeInplaceMemo.EditorWndProc  and
    TElTreeInplaceCheckBox.EditorWndProc

    except the EditorWndProc procedure had a bit different code.
            CompleteOperation(false);

    It had:  
          begin
            CompleteOperation(false);
            exit;
          end;

    which exits without executing the SaveWndProc(Message) line.

    I did that in the EditorWndProc procedure, and my issue vanished.

    Please compare the 3 routines I list above and see if you agree that this is the correct fix. 

    Thanks.

    Louis


    So in 

  • I found another case where I still got the error.  So I changed my fix above, to this:

      if (Message.Msg = WM_CANCELMODE) or
         ((Message.Msg = CM_CANCELMODE) and
          (TObject(Pointer(Message.lParam)) <> Editor)) or
          (Message.Msg = WM_KILLFOCUS) then
        if FEditing then
        begin
          if THackElTree(Tree).FExplorerEditMode then
          begin
            EndEditWithInputChecked;
          end
          else
            CompleteOperation(false);
          if Message.Msg <> CM_CANCELMODE then
            SendMessage(THackElTree(Tree).View.Handle, CM_EXIT, 0, 0);
          exit:
        end;
      SaveWndProc(Message);

    I added that "exit" line near the bottom.  It now prevents the SaveWndProc line from being called whenever Canceling or Killing the focus.

    Louis
  • Thanks for report. Your modification has been incorporated.
Sign In or Register to comment.