Recent

Author Topic: [SOLVED] How to implement "AutoEdit" in VirtualTreeView?  (Read 538 times)

mtrsoft

  • New Member
  • *
  • Posts: 28
[SOLVED] How to implement "AutoEdit" in VirtualTreeView?
« on: June 06, 2019, 09:00:41 pm »
System: Win7 /32
Lazarus: v2.0.2
virtualtreeview: v5.5.3-R1

I am using the VTV in "grid mode" and trying to have an alphanumeric key press do two things:

1. Create and start the Edit control. -- This works.

2. Automatically enter the alphanumeric character into the edit control without having to press the key a second time. -- This is not working.

I have tried four code variations, none of which have accomplished my goal #2.

In the following KeyDown event code look at the statements close to the "ERROR" comments.

Code: Pascal  [Select]
  1. procedure TPgCtrlChildVST1Grid.vstKeyDown(Sender: TObject; var Key: Word;
  2.   Shift: TShiftState);
  3. Var
  4.   ANode      :PVirtualNode;
  5.   OldNode    :PVirtualNode;
  6.   I          :Integer;
  7.   AKey       :Word;
  8.   AShift     :TShiftState;
  9.   SavedKey   :Word;
  10.   SavedShift :TShiftState;
  11.   AMessage   :TLMessage;
  12. begin
  13. SavedKey := 0;
  14. SavedShift := [];
  15. If (NOT TVirtualStringTree(Sender).IsEditing) then
  16.   begin
  17.   If b_GridEnterAdvances and (Key = vk_Return) and (Shift = [])
  18.     then  begin
  19.           {Code to move to the next column when the Return key is pressed}          
  20.           end
  21.     else  begin
  22.           If b_GridAtoZStartsEditing
  23.              AND
  24.              (
  25.                ((Shift = []) and (Char(Key) in ['0'..'9', 'A'..'Z']))
  26.                OR
  27.                ((Shift = [ssShift]) and (Char(Key) in ['A'..'Z']))
  28.              )
  29.             then  begin
  30.                   (*****
  31.                   {This invokes the Edit control but does NOT enter the character into the Edit control}
  32.                   If NOT TVirtualStringTree(Sender).IsEditing then
  33.                     begin
  34.                     AKey := VK_F2;
  35.                     AShift := [];
  36.                     vstKeyDown(Sender, AKey, AShift);
  37.                     end;
  38.                   *****)
  39.  
  40.                   (*******)
  41.                   {Save the key, enter edit mode then ? re-post/re-send key to the edit control}
  42.                   SavedKey := Key;
  43.                   SavedShift := Shift;
  44.                   Key := 0; {So that nothing is done when this procedure exits unless Key is set to its original value.}
  45.  
  46.                   {Start editing the Node then try to re-send the
  47.                    same character / message to the editor.}
  48.  
  49.                   If TVirtualStringTree(Sender).EditNode(
  50.                       TVirtualStringTree(Sender).FocusedNode
  51.                       , TVirtualStringTree(Sender).FocusedColumn) then
  52.                     begin
  53.  
  54.                     {After the editor is started pass the original key through.}
  55.                     //Key := SavedKey;
  56.                     //Shift := SavedShift;
  57.                     {
  58.                     NO ERROR, BUT the character is NOT entered into the editor / edit control.
  59.                     }
  60.  
  61.                     {After the editor is started post original message the the VST.}
  62.                     //PostMessage(TVirtualStringTree(Sender).Handle, LM_KEYDOWN, SavedKey, ShiftStateToKeys(SavedShift));
  63.                     {
  64.                     NO ERROR, BUT the character is NOT entered into the editor / edit control.
  65.                     Debugger indicates the VirtualStringTree does not have a "Handle" property,
  66.                     BUT VST is a TCustomControl descendant which is a TWinControl descendant so it should have a Handle propery.
  67.                     }
  68.  
  69.                     {After editor started have the EditLink process the original message.}
  70.                     //AMessage.Msg := LM_KEYDOWN;
  71.                     //AMessage.WParam := SavedKey;
  72.                     //AMessage.LParam := ShiftStateToKeys(SavedShift);
  73.                     //TmtrsVTELBase(TVirtualStringTree(Sender).EditLink).ProcessMessage(AMessage);
  74.                     {
  75.                     ERROR IS: "External SIGSEGV", which occurs in the EditLink's
  76.                     ProcessMessages procedure shown below.
  77.                     procedure TmtrsVTELBase.ProcessMessage(var Message: TLMessage); stdcall;
  78.                     begin
  79.                     >>>>>> FEdit.WindowProc(Message); <<<<<<<
  80.                     end;
  81.                     }
  82.  
  83.                     {After editor started post original message the the Editor / Edit control.}
  84.                     //PostMessage(TmtrsVTELBase(TVirtualStringTree(Sender).EditLink).Edit.Handle, LM_KEYDOWN, SavedKey, ShiftStateToKeys(SavedShift));
  85.                     {
  86.                     ERROR IS: "External SIGSEGV"
  87.                     }
  88.  
  89.                     {In all four cases above the Editlink and the Edit have been
  90.                     assigned valid values after the EditNode procedure is executed.}
  91.  
  92.                     end;
  93.                   (******)
  94.                   end;
  95.           end;
  96.   end;
  97.  
  98. //Inherited;
  99.  
  100. end;
  101.  

Does anyone have a suggestion as to how I can resolve this?

« Last Edit: June 09, 2019, 07:01:01 pm by mtrsoft »

jamie

  • Hero Member
  • *****
  • Posts: 2162
Re: How to implement "AutoEdit" in VirtualTreeView?
« Reply #1 on: June 07, 2019, 02:36:02 am »
You can add to or set the initial text in an edit control..

MyEditControl.Text := My_VK_CODE;
Number 1 at blue screen app creations!

mtrsoft

  • New Member
  • *
  • Posts: 28
Re: How to implement "AutoEdit" in VirtualTreeView?
« Reply #2 on: June 07, 2019, 07:38:29 am »
Unfortunately, trying to assign text to the edit control results in the same SIGSEGV error.

Although the edit control seems to have a valid value, the debugger indicates that its memory location is not accessible.

This seems odd to me because when I DON'T try to re-send the character or assign a value to its text property I can then edit its contents in the normal way.

jamie

  • Hero Member
  • *****
  • Posts: 2162
Re: How to implement "AutoEdit" in VirtualTreeView?
« Reply #3 on: June 07, 2019, 11:10:10 pm »
I don't understand, it should work.

You first ensure the control is created then you can add text to it...

You must be over looking something.

Either that you need to do this in a KeyUp instead.
Number 1 at blue screen app creations!

mtrsoft

  • New Member
  • *
  • Posts: 28
Re: How to implement "AutoEdit" in VirtualTreeView?
« Reply #4 on: June 09, 2019, 07:00:30 pm »
I have not been able to determine why the Edit control's memory is not accessible and referencing its methods or properties results in a SIGSEGV error.

HOWEVER, I have found a way to make it work by using the "MouseAndKeyInput" unit that comes with Lazarus.
(In the Windows version of Lazarus its located at C:\Lazarus\components\mouseandkeyinput\).)

I have included several code snippets below that illustrate the solution.

Things to note about the implementation:

1. The SendAKey procedure MUST be a form method.

2. Besides starting the editing process by pressing an alphanumeric key and then sending that key to the edit control I also want to send an Alt+Down keypress instead of the original key if the edit control has a dropdown, such as a DateTimePicker.

Because I was not able to determine the type of the edit control at runtime I decided to use a variable, SendAKeyDataAltDownCols, to identify the grid columns that use such an edit control. The values in this variable should be set when the form is created or whenever the VirtualStringTree's column count is changed.

Code: Pascal  [Select]
  1. {The form definition}
  2. TPgCtrlChildVST1Grid = class(TPgCtrlChildForm)
  3. .
  4. .
  5.   public
  6.     { Public declarations }
  7.     SendAKeyDataKey   :Word;
  8.     SendAKeyDataShift :TShiftState;
  9.     SendAKeyDataAltDownCols :Set Of Byte;
  10.     Procedure SendAKey( Data :PtrInt);
  11.     Procedure DoSendAKey( AKey :Word; AShift :TShiftState);
  12. .
  13. .
  14. .
  15. end;
  16.  
  17.  
  18. implementation
  19.  
  20. uses
  21. .
  22. .
  23. .
  24.   , MouseAndKeyInput {Located in c:\lazarus\components\mouseandkeyinput}
  25.   ;
  26.  
  27.  
  28. Var
  29.   SavedEditKey         :Word;
  30.   SavedEditShift       :TShiftState;
  31.  
  32.  
  33. Procedure TPgCtrlChildVST1Grid.SendAKey( Data :PtrInt);
  34. Begin
  35. If (SendAKeyDataShift <> []) then KeyInput.Apply( SendAKeyDataShift);
  36. KeyInput.Press(SendAKeyDataKey);
  37. If (SendAKeyDataShift <> []) then KeyInput.UnApply( SendAKeyDataShift);
  38. end;
  39.  
  40. Procedure TPgCtrlChildVST1Grid.DoSendAKey( AKey :Word; AShift :TShiftState);
  41. begin
  42. SendAKeyDataKey := AKey;
  43. SendAKeyDataShift := AShift;
  44. Application.QueueAsyncCall(@SendAKey, 0);
  45. end;
  46.  
  47.  
  48. procedure TPgCtrlChildVST1Grid.vstKeyDown(Sender: TObject; var Key: Word;
  49.   Shift: TShiftState);
  50. Var
  51.   ANode      :PVirtualNode;
  52.   I          :Integer;
  53.  
  54. begin
  55.  
  56. If (NOT TVirtualStringTree(Sender).IsEditing) then
  57.   begin
  58.   If b_GridEnterAdvances and (Key = vk_Return) and (Shift = [])
  59.     then  begin
  60.                 {Code to move to the next column.}     
  61.           end
  62.     else  begin
  63.           If b_GridAtoZStartsEditing
  64.              AND
  65.              (
  66.                ((Shift = []) and (Char(Key) in ['0'..'9', 'A'..'Z']))
  67.                OR
  68.                ((Shift = [ssShift]) and (Char(Key) in ['A'..'Z']))
  69.              )
  70.             then  begin
  71.                                                
  72.                   {Save the key, enter edit mode then simulate a second keypress}
  73.                   SavedEditKey := Key;
  74.                   SavedEditShift := Shift;
  75.                   Key := 0; {So that nothing is done when this procedure exits}
  76.  
  77.                   {Start editing the Node then simulate a keypress which will be sent
  78.                    to the control that has the focus.}
  79.                   If TVirtualStringTree(Sender).EditNode(
  80.                       TVirtualStringTree(Sender).FocusedNode
  81.                       , TVirtualStringTree(Sender).FocusedColumn) then
  82.                     begin
  83.                                                                                
  84.                     {Set when vst created or number of colums changed}
  85.                     {Identifies columns that have editors with dropdowns}
  86.                     //SendAKeyDataAltDownCols := [4, 6, 7];
  87.  
  88.                     If (TVirtualStringTree(Sender).FocusedColumn IN SendAKeyDataAltDownCols)
  89.                        then  DoSendAKey( VK_DOWN, [ssAlt])
  90.                        else  DoSendAKey( SavedEditKey, SavedEditShift);
  91.                    
  92.                                                                                 end;
  93.                                                                                
  94.                   end;
  95.           end;
  96.   end;
  97. end;
  98.  
  99.  

I hope others find this solution useful.