在特定鼠标位置拖放到 TextBox - 显示插入符号或位置指示符

Posted

技术标签:

【中文标题】在特定鼠标位置拖放到 TextBox - 显示插入符号或位置指示符【英文标题】:Drag and drop an to TextBox in a specific mouse position - Show caret or position indicator 【发布时间】:2016-12-18 13:10:07 【问题描述】:

我正在将一个项目从 TreeView 粘贴到 TextBox,但我想将该项目粘贴到鼠标的当前位置,并显示如下图所示的插入符号。 带有插入符号的图像:

这是我的代码:

private void tvOperador_ItemDrag(object sender, ItemDragEventArgs e)

    var node = (TreeNode)e.Item;
    if (node.Level > 0)
    
        DoDragDrop(node.Text, DragDropEffects.Copy);
    

private void txtExpresion_DragEnter(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(string))) e.Effect = DragDropEffects.Copy;

private void txtExpresion_DragDrop(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(System.String)))
    
        string Item = (System.String)e.Data.GetData(typeof(System.String));
        string[] split = Item.Split(':');

        txtExpresion.Text += split[1];
    

【问题讨论】:

查看更新后的答案,它融合了我原来的最佳解决方案和@Reza 的解决方案! 【参考方案1】:

这很棘手,因为 Drag&Drop 操作会捕获鼠标,因此您不能使用鼠标事件..

一种方法是设置Timer 来完成这项工作..:

    Timer cursTimer = new Timer();

    void cursTimer_Tick(object sender, EventArgs e)
    
        int cp = txtExpresion.GetCharIndexFromPosition(
                 txtExpresion.PointToClient(Control.MousePosition));
        txtExpresion.SelectionStart = cp;
        txtExpresion.SelectionLength = 0; 
        txtExpresion.Refresh();
    

Timer 使用 Control.MousePosition 函数每 25 毫秒左右确定一次光标位置,设置插入符号并更新 TextBox

在您的事件中初始化它并确保TextBox 具有焦点;最后在当前选择处添加字符串:

    private void txtExpresion_DragEnter(object sender, DragEventArgs e)
    
        if (e.Data.GetDataPresent(typeof(string)))
        
            e.Effect = DragDropEffects.Copy;
            txtExpresion.Focus();
            cursTimer = new Timer();
            cursTimer.Interval = 25;
            cursTimer.Tick += cursTimer_Tick;
            cursTimer.Start();
        
    

    private void txtExpresion_DragDrop(object sender, DragEventArgs e)
    
        if (e.Data.GetDataPresent(typeof(System.String)))
        
            cursTimer.Stop();

            string Item = (System.String)e.Data.GetData(typeof(System.String));
            string[] split = Item.Split(':');

            txtExpresion.SelectedText = split[1]
        
    

解决此问题的另一种方法是不使用普通的拖放操作,而只对鼠标事件进行编码,但在我的第一次测试中这个工作正常。

更新

虽然上述解决方案确实有效,但使用Timer 似乎并不完全优雅。如 Reza 的回答所示,使用 DragOver 事件要好得多。但是,与其画一个光标,不如做真实的事情,即控制实际的工字梁..?

DragOver 事件在移动过程中一直被调用,所以它的工作方式与MousMove 非常相似:所以这是两种解决方案的合并,我认为这是最好的方法:

private void txtExpresion_DragDrop(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(System.String)))
    
        string Item = (System.String)e.Data.GetData(typeof(System.String));
        string[] split = Item.Split(':');
        txtExpresion.SelectionLength = 0;
        txtExpresion.SelectedText = split[1];
    


private void txtExpresion_DragEnter(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(string)))
    
        e.Effect = DragDropEffects.Copy;
        txtExpresion.Focus();
    


private void txtExpresion_DragOver(object sender, DragEventArgs e)

    int cp = txtExpresion.GetCharIndexFromPosition(
                          txtExpresion.PointToClient(Control.MousePosition));
    txtExpresion.SelectionStart = cp;
    txtExpresion.Refresh();


【讨论】:

【参考方案2】:

您可以在DragOver 事件中在TextBox 上画一个插入符号。还将SelectionStart 设置为从鼠标位置获得的字符索引。然后在DragDrop事件中,设置SelectedText

private void textBox1_DragOver(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(System.String)))
    
        var position = textBox1.PointToClient(Cursor.Position);
        var index = textBox1.GetCharIndexFromPosition(position);
        textBox1.SelectionStart = index;
        textBox1.SelectionLength = 0;
        textBox1.Refresh();
        using (var g = textBox1.CreateGraphics())
        
            var p = textBox1.GetPositionFromCharIndex(index);
            g.DrawLine(Pens.Black, p.X, 0, p.X, textBox1.Height);
        
    


private void textBox1_DragDrop(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(System.String)))
    
        string txt = (System.String)e.Data.GetData(typeof(System.String));
        textBox1.SelectedText = txt;
    

【讨论】:

这是一个非常好的选择! @Reza:你能告诉我你是用什么制作那个动画的吗? @TaW 感谢您的反馈 :) 我使用了ScreenToGif。此工具可让您记录屏幕的选定区域并将其保存为 Gif。 我在 gif 中看到了放置位置指示器的黑色阴影,但在执行时它在 TextBox 中不存在。这只是为了 gif 的质量或采样率。在运行时完全清楚。 嗯,我没看到影子。但后来我睡着了;-)

以上是关于在特定鼠标位置拖放到 TextBox - 显示插入符号或位置指示符的主要内容,如果未能解决你的问题,请参考以下文章

如何让人们将 LI 拖放到列表中的特定位置? (console.log 问题)

从一个表单拖放到另一个表单的任意位置

在 RecyclerView 中的特定位置拖放停止

将行动态添加到TableLayoutPanel会在不同的行号(位置)上显示

C#-WinForm-如何获取文本框(TextBox)中鼠标,光标位置

如何使用 Qt Designer 在菜单中插入操作?