Drag and drop text into SynEdit control
-
15-06-2021 - |
Вопрос
I have a TSynEdit control on a form and I want to drag and drop the focused node text from a TVirtualStringTree. I would like it to behave in the same way as when you drag and drop the highlighted text within the TSynEdit control:
- As you drag over the TSynEdit, the caret should mark the current drop position.
- When the text is dropped, it should replace any text that is currently highlighted.
- The drop position should handle tabs correctly.
I have looked at the code in the TSynEdit DragOver event, but it uses several variables and procedures that I can't access in a descendant class as they are declared private.
I have checked all the TSynEdit demos and can't find one that addresses my needs.
Anybody managed to do this successfully?
Решение
I think that you can manage to reach your goal by assigning two events to your editor: DragOver/DragDrop.
1/ you test the validity in the DragOver event, you also move the caret by calling GetPositionOfMouse
Procedure TForm1.EditorDragOver(Sender,Source: TObject;X,Y: Integer; State: TDragState; Var Accept: Boolean);
Var
LCoord: TBufferCoord;
LMemo: TSynMemo;
Begin
LMemo := TSynMemo(Sender);
// In your case you would rather test something with your tree...
Accept := Clipboard.AsText <> '';
// "As you drag over the TSynEdit, the caret should mark the current drop position": OK
If LMemo.GetPositionOfMouse(LCoord) Then
LMemo.CaretXY := LCoord;
End;
2/ You use the editor commands in the DragDrop event, to clear the selection and to insert chars
Procedure TForm1.EditorDragDrop(Sender, Source: TObject; X,Y: Integer);
Var
LMemo: TSynMemo;
Begin
LMemo := TSynMemo(Sender);
// "When the text is dropped, it should replace any text that is currently highlighted." : OK
If LMemo.SelAvail Then
LMemo.ExecuteCommand( ecDeleteChar , #0, Nil );
// Paste, same comment as previously, here it's just an example...
LMemo.ExecuteCommand( ecPaste, #0, Nil );
End;
This would have to be a bit tweaked according to your context.
Другие советы
AZ01's answer didn't do exactly what I wanted, but it did point me in the correct direction. Here's the code I eventually used:
procedure TfrmTemplateEdit.memTemplateDragDrop(Sender, Source: TObject; X,
Y: Integer);
var
InsertText: String;
ASynEdit: TSynEdit;
OldSelStart, DropIndex: Integer;
LCoord: TBufferCoord;
begin
// Set the Insert Text
InsertText := 'The text to insert';
// Set the SynEdit memo
ASynEdit := TSynEdit(Sender);
// Get the position on the mouse
ASynEdit.GetPositionOfMouse(LCoord);
// Find the index of the mouse position
DropIndex := ASynEdit.RowColToCharIndex(LCoord);
// Delete any selected text
If (ASynEdit.SelAvail) and
(DropIndex >= ASynEdit.SelStart) and
(DropIndex <= ASynEdit.SelEnd) then
begin
// Store the old selection start
OldSelStart := ASynEdit.SelStart;
// Delete the text
ASynEdit.ExecuteCommand(ecDeleteChar, #0, Nil);
// Move the caret
ASynEdit.SelStart := OldSelStart;
end
else
begin
// Position the caret at the mouse location
ASynEdit.CaretXY := LCoord;
end;
// Insert the text into the memo
ASynEdit.ExecuteCommand(ecImeStr, #0, PWideChar(InsertText));
// Set the selection start and end points to selected the dropped text
ASynEdit.SelStart := ASynEdit.SelStart - length(InsertText);
ASynEdit.SelEnd := ASynEdit.SelStart + length(InsertText);
// Set the focus to the SynEdit
ASynEdit.SetFocus;
end;
The code seems to work correctly with selections, tabs and undo.