Member 10974007 Ответов: 3

Как переместить линию вверх / вниз с помощью alt + arrow_up и alt + arrow_down


Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
       If e.KeyCode = Keys.Down Then
          movelineup()
       ElseIf e.KeyCode = Keys.Up Then
           movelinedown()
       End If
   End Sub

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       Me.KeyPreview = True
   End Sub


Что я уже пробовал:

теперь что я должен сделать прямо в функции, чтобы она могла работать с многострочным текстовым полем

Код заимствован, но не может приступить к работе:
'' Duplicates the current line (or selection of lines) and places the copy
'' one line below or above the current cursor position (based upon the parameter)
Sub CopyLine(ByVal movingDown As Boolean)
    DTE.UndoContext.Open("CopyLine")
    Dim objSel As TextSelection = DTE.ActiveDocument.Selection

    ' store the original selection and cursor position
    Dim topPoint As TextPoint = objSel.TopPoint
    Dim bottomPoint As TextPoint = objSel.BottomPoint
    Dim lTopLine As Long = topPoint.Line
    Dim lTopColumn As Long = topPoint.LineCharOffset
    Dim lBottomLine As Long = bottomPoint.Line
    Dim lBottomColumn As Long = bottomPoint.LineCharOffset()

    ' copy each line from the top line to the bottom line
    Dim readLine As Long = lTopLine
    Dim endLine As Long = lBottomLine + 1
    Dim selectionPresent As Boolean = ((lTopLine <> lBottomLine) Or (lTopColumn <> lBottomColumn))
    If (selectionPresent And (lBottomColumn = 1)) Then
        ' A selection is present, but the cursor is in front of the first character
        ' on the bottom line. exclude that bottom line from the copy selection.
        endLine = lBottomLine
    End If

    ' figure out how many lines we are copying, so we can re-position
    ' our selection after the copy is done
    Dim verticalOffset As Integer = 0
    If (movingDown) Then
        verticalOffset = endLine - lTopLine
    End If

    ' copy each line, one at a time.
    ' The Insert command doesn't handle multiple lines well, and we need
    ' to use Insert to avoid autocompletions
    Dim insertLine As Long = endLine
    While (readLine < endLine)
        ' move to read postion, and read the current line
        objSel.MoveToLineAndOffset(readLine, 1)
        objSel.EndOfLine(True) 'extend to EOL
        Dim lineTxt As String = objSel.Text.Clone
        ' move to the destination position, and insert the copy
        objSel.MoveToLineAndOffset(insertLine, 1)
        objSel.Insert(lineTxt)
        objSel.NewLine()
        ' adjust the read & insertion points
        readLine = readLine + 1
        insertLine = insertLine + 1
    End While

    ' restore the cursor to original position and selection
    objSel.MoveToLineAndOffset(lBottomLine + verticalOffset, lBottomColumn)
    objSel.MoveToLineAndOffset(lTopLine + verticalOffset, lTopColumn, True)
    DTE.UndoContext.Close()
End Sub

'' Duplicates the current line (or selection of lines) and places the copy
'' one line below the current cursor position
Sub CopyLineDown()
    CopyLine(True)
End Sub

'' Duplicates the current line (or selection of lines) and places the copy
'' one line above the current cursor position
Sub CopyLineUp()
    CopyLine(False)
End Sub


'' Moves the selected lines up one line. If no line is
'' selected, the current line is moved.
''
Sub MoveLineUp()
    DTE.UndoContext.Open("MoveLineUp")
    Dim objSel As TextSelection = DTE.ActiveDocument.Selection
    ' store the original selection and cursor position
    Dim topPoint As TextPoint = objSel.TopPoint
    Dim bottomPoint As TextPoint = objSel.BottomPoint
    Dim lTopLine As Long = topPoint.Line
    Dim lTopColumn As Long = topPoint.LineCharOffset
    Dim lBottomLine As Long = bottomPoint.Line
    Dim lBottomColumn As Long = bottomPoint.LineCharOffset()

    Dim textLineAbove As TextSelection = DTE.ActiveDocument.Selection
    textLineAbove.MoveToLineAndOffset(lTopLine - 1, 1, False)
    textLineAbove.MoveToLineAndOffset(lTopLine, 1, True)
    Dim indentChange As Integer = CountIndentations(textLineAbove.Text) * -1

    ' If multiple lines are selected, but the bottom line doesn't
    ' have any characters selected, don't count it as selected
    Dim lEffectiveBottomLine = lBottomLine
    If ((lBottomColumn = 1) And (lBottomLine <> lTopLine)) Then
        lEffectiveBottomLine = lBottomLine - 1
    End If

    ' move to the line above the top line
    objSel.MoveToLineAndOffset(lTopLine - 1, 1)
    ' and move it down, until its below the bottom line:
    Do
        DTE.ExecuteCommand("Edit.LineTranspose")
    Loop Until (objSel.BottomPoint.Line >= lEffectiveBottomLine)
    ' Since the line we are on has moved up, our location in the file has changed:
    lTopLine = lTopLine - 1
    lBottomLine = lBottomLine - 1

    IndentBlockAndRestoreSelection(objSel, lBottomLine, lBottomColumn, lTopLine, lTopColumn, indentChange)

    DTE.UndoContext.Close()
End Sub

'' Moves the selected lines down one line. If no line is
'' selected, the current line is moved.
''
Sub MoveLineDown()
    DTE.UndoContext.Open("MoveLineDown")
    Dim objSel As TextSelection = DTE.ActiveDocument.Selection
    ' store the original selection and cursor position
    Dim topPoint As TextPoint = objSel.TopPoint
    Dim bottomPoint As TextPoint = objSel.BottomPoint
    Dim lTopLine As Long = topPoint.Line
    Dim lTopColumn As Long = topPoint.LineCharOffset
    Dim lBottomLine As Long = bottomPoint.Line
    Dim lBottomColumn As Long = bottomPoint.LineCharOffset()

    ' If multiple lines are selected, but the bottom line doesn't
    ' have any characters selected, don't count it as selected
    Dim lEffectiveBottomLine = lBottomLine
    If ((lBottomColumn = 1) And (lBottomLine <> lTopLine)) Then
        lEffectiveBottomLine = lBottomLine - 1
    End If

    Dim textLineBelow As TextSelection = DTE.ActiveDocument.Selection
    textLineBelow.MoveToLineAndOffset(lEffectiveBottomLine + 1, 1, False)
    textLineBelow.MoveToLineAndOffset(lEffectiveBottomLine + 2, 1, True)
    Dim indentChange As Integer = CountIndentations(textLineBelow.Text)


    ' move to the bottom line
    objSel.MoveToLineAndOffset(lEffectiveBottomLine, 1)
    ' and move it down, which effectively moves the line below it up
    ' then move the cursor up, always staying one line above the line
    ' that is moving up, and keep moving it up until its above the top line:
    Dim lineCount As Long = lEffectiveBottomLine - lTopLine
    Do
        DTE.ExecuteCommand("Edit.LineTranspose")
        objSel.LineUp(False, 2)
        lineCount = lineCount - 1
    Loop Until (lineCount < 0)
    ' Since the line we are on has moved down, our location in the file has changed:
    lTopLine = lTopLine + 1
    lBottomLine = lBottomLine + 1

    IndentBlockAndRestoreSelection(objSel, lBottomLine, lBottomColumn, lTopLine, lTopColumn, indentChange)

    DTE.UndoContext.Close()
End Sub

'' This method takes care of indenting the selected text by the indentChange parameter
'' It then restores the selection to the lTopLine:lTopColumn - lBottomLine:lBottomColumn parameter.
'' It will adjust these values according to the indentChange performed
Sub IndentBlockAndRestoreSelection(ByVal objSel As TextSelection, ByVal lBottomLine As Long, ByVal lBottomColumn As Long, ByVal lTopLine As Long, ByVal lTopColumn As Long, ByVal indentChange As Integer)
    ' restore the cursor to original position and selection
    objSel.MoveToLineAndOffset(lBottomLine, lBottomColumn)
    objSel.MoveToLineAndOffset(lTopLine, lTopColumn, True)
    If (indentChange = 0) Then
        ' If we don't change the indent, we are done
        Return
    End If

    If (lBottomLine = lTopLine) Then
        If (indentChange > 0) Then
            objSel.StartOfLine()
        Else
            objSel.StartOfLine()
            objSel.WordRight()
        End If
    End If
    objSel.Indent(indentChange)

    ' Since the selected text has changed column, adjust the columns accordingly:
    ' restore the cursor to original position and selection
    Dim lNewBottomColumn As Long = (lBottomColumn + indentChange)
    Dim lNewTopColumn As Long = (lTopColumn + indentChange)
    ' ensure that we we still on the page.
    ' The "or" clause makes it so if we were at the left edge of the line, we remain on the left edge.
    If ((lNewBottomColumn < 2) Or (lBottomColumn = 1)) Then
        ' Single line selections, or a bottomColumn that is already at 1 may still have a new BottomColumn of 1
        If ((lTopLine = lBottomLine) Or (lBottomColumn = 1)) Then
            lNewBottomColumn = 1
        Else
            ' If we have multiple lines selected, don't allow the bottom edge to touch the left column,
            ' or the next move will ignore that bottom line.
            lNewBottomColumn = 2
        End If
    End If
    If ((lNewTopColumn < 2) Or (lTopColumn = 1)) Then
        lNewTopColumn = 1
    End If

    ' restore the selection to the modified selection
    objSel.MoveToLineAndOffset(lBottomLine, lNewBottomColumn)
    objSel.MoveToLineAndOffset(lTopLine, lNewTopColumn, True)
End Sub


'' This method counts the indentation changes within the text provided as the paramter
Function CountIndentations(ByVal text As String) As Integer
    Dim indent As Integer = 0
    While (Text.Length > 0)
        If (Text.StartsWith("//")) Then
            Dim endOfLine As Integer = Text.IndexOf("\n", 2)
            If (Equals(endOfLine, -1)) Then
                ' The remaining text is all on one line, so the '//' terminates our search
                ' Ignore the rest of the text
                Exit While
            End If
            ' continue looking after the end of line
            Text = Text.Substring(endOfLine + 1)
        End If

        If (Text.StartsWith("/*")) Then
            Dim endComment As Integer = Text.IndexOf("*/", 2)
            If (Equals(endComment, -1)) Then
                ' This comment continues beyond the length of this line.
                ' Ignore the rest of the text
                Exit While
            End If
            ' continue looking after the end of this comment block
            Text = Text.Substring(endComment + 1)
        End If

        If (Text.StartsWith("{")) Then
            indent = indent + 1
        Else
            If (Text.StartsWith("}")) Then
                indent = indent - 1
            End If
        End If
        Text = Text.Substring(1)
    End While
    Return indent
End Function

Ralf Meier

Вы хотите переместить выделенную строку в текстовое поле ?
Сколько строк у вас внутри текстового поля ?
Знаете ли вы, что изначально вы даете только одну строку текстовому полю, а разные строки являются результатом CR-LF между частями строки ?

Member 10974007

интересно :)

я просто хочу двигать линию вверх и вниз
кратные строки он содержит ascii до 32 символов..

точно так же, как редактор кода Visual Studio :)
эта функция действительно великолепна :)

Ralf Meier

Если вы ответите на мой комментарий, я получу уведомление ...

Так... что именно вы хотите сделать ?
Я бы предложил создать настраиваемое текстовое поле, которое будет вести себя так, как вы хотите.
Вам это знакомо ?

3 Ответов

Рейтинг:
2

Ralf Meier

Потому что мы здесь, чтобы помочь ...

Если бы я правильно понял это требование, то это текстовое поле помогло бы :

Public Class Edit_MLTextbox
    Inherits TextBox

    Sub New()
        MyBase.Multiline = True
    End Sub

    Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
        Dim myKey As System.Windows.Forms.Keys = e.KeyCode
        Dim myAltPressed As Boolean = e.Alt
        Dim myLine As Integer = -1

        If myAltPressed AndAlso (Me.SelectionStart >= 0) Then
            myLine = Me.GetLineFromCharIndex(Me.SelectionStart)
            If myLine <> -1 Then
                If (myKey = Keys.Add) And (myLine < Me.Lines.Count - 1) Then
                    XChange(Me.Text, Me.Lines(myLine), Me.Lines(myLine + 1))
                    e.Handled = True
                ElseIf (myKey = Keys.Subtract) And (myLine > 0) Then
                    XChange(Me.Text, Me.Lines(myLine), Me.Lines(myLine - 1))
                    e.Handled = True
                End If
            End If
        End If

        MyBase.OnKeyDown(e)
    End Sub

    Private Sub XChange(ByRef sourceText As String, ByRef xchg1 As String, xchg2 As String)
        sourceText = sourceText.Replace(xchg1, Chr(1))
        sourceText = sourceText.Replace(xchg2, Chr(2))
        sourceText = sourceText.Replace(Chr(1), xchg2)
        sourceText = sourceText.Replace(Chr(2), xchg1)
    End Sub

End Class


Member 10974007

шрифт problesm в этом

Ralf Meier

Я не понимаю, что вы имеете в виду ...

Member 10974007

полные коды по запросу :)
как новичок в vb у меня есть полные ошибки
Сообщение 1

Дизайнер не может обработать код в строке 25:
Меня.AutoScaleDimensions = Новая Система.Рисование.SizeF(6.0!, 13.0!)
Код внутри метода "InitializeComponent" генерируется разработчиком и не должен быть изменен вручную.

Ralf Meier

Извините... Я не мог следовать за тобой ...
Это сообщение об ошибке не относится к моему контролю.
Я бы предложил следующее :
- создайте новое приложение и вставьте мой элемент управления (код из этого решения) и посмотрите, как он работает
- посмотрите, что происходит не так в вашем приложении
- интегрируйте мой контроль (если он работает так, как вы хотите) в ваше приложение

...

Рейтинг:
1

Patrice T

Цитата:
Как переместить линию вверх / вниз с помощью alt + arrow_up и alt + arrow_down

В текстовом поле последовательность состоит из выбора строки, вырезания выделения, перемещения курсора, вставки буфера обмена.

Когда вы не понимаете, что делает ваш код или почему он делает то, что делает, ответ таков: отладчик.
Используйте отладчик, чтобы увидеть, что делает ваш код. Просто установите точку останова и посмотрите, как работает ваш код, отладчик позволяет вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения, это невероятный инструмент обучения.

Отладчик-Википедия, свободная энциклопедия[^]
Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]

Отладчик здесь для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.
В отладчике нет никакой магии, он не находит ошибок, он просто помогает вам. Когда код не делает того, что ожидается, вы близки к ошибке.


Рейтинг:
0

Graeme_Grant

Я помогу тебе начать...

Получить индекс каретки в текстовом поле:

Dim caretIndex As Integer = textBox.SelectionStart
Получить номер строки из индекса каретки:
Dim lineNumber As Integer = textBox.GetLineFromCharIndex(caretIndex)
Получить индекс символа в текущей строке:
Dim characterXY As Point = textBox.GetPositionFromCharIndex(caretIndex)
Dim characterIndex As Integer = textBox.GetCharIndexFromPosition(characterXY)
Остальное зависит от вас.

Редактировать: Я немного помогу Вам с функцией поиска всех новых строк (или любого символа/текста)
Public Function AllIndexesOf(str As String, searchstring As String) As List(Of Integer)
    Dim index As Integer = str.IndexOf(searchstring)
    Dim indexes As List(Of Integer) = New List(Of Integer)()
    While index <> -1
        indexes.Add(index)
        index = str.IndexOf(searchstring, index + searchstring.Length)
    End While
    Return indexes
End Function
Использовать:
Dim text = "blah blah blah blah " + vbCrLf +
    "blah blah blah blah blah blah blah blah blah blah " + vbCrLf +
    "blah blah blah blah blah blah blah blah blah blah " + vbCrLf +
    "blah blah blah blah blah blah blah blah blah blah "
Dim indexes As List(Of Integer) = AllIndexesOf(text, vbCrLf)


Member 10974007

http://stackoverflow.com/questions/313462/visual-studio-hotkeys-to-move-line-up-down-and-move-through-recent-changes/313553#313553

вот это статья, но я вмятина понять
как исправить ?

Graeme_Grant

Знаете ли вы, как использовать Debbuger в Visual Studio?

При использовании чужого кода Вы не должны использовать его, пока не поймете, что он делает.

Если бы я работал над этим, я бы установил точки останова в коде и шагнул через каждую строку, чтобы увидеть, в чем может быть проблема. Это то, что вам нужно сделать, чтобы исправить это.

[edit:] когда я переместил ваш дополнительный код (пожалуйста, обновите вопрос и не вставляйте его в ответ), код оказался неполным. Пожалуйста, обновите свой вопрос с отсутствующим кодом, если вы хотите, чтобы другие посмотрели на него.

Graeme_Grant

Этот [url-адрес для ответа на переполнение стека] посвящен расширению среды разработки Visual Studio IDE, а не работе с элементом управления TextBox. Вот почему вы не можете заставить его работать.

Member 10974007

можете ли вы улучшить его ?

Graeme_Grant

Вы не можете улучшить его, он должен быть утилизирован, так как он не имеет отношения к VS IDE, а не к элементу управления TextBox, и переписан с нуля.

Ральф дал вам несколько советов, и я показал вам, как определить, на какой линии вы находитесь.

Кроме того, в вашем Form1_KeyDown вы не проверяете, удерживается ли клавиша ALT при использовании клавиш со стрелками. Кроме того, этот код должен существовать в TextBox1_KeyDown обработчик событий, а не форма.

Фу-у-у, программирование - это написание кода, а не то, чтобы кто-то другой писал его для вас бесплатно. Самое время получить хорошую книгу или записаться на курсы и учиться.

Member 10974007

что я должен сделать, чтобы это сработало

Graeme_Grant

Тогда ладно... Базовая логика:
1. найти начать подбор усилителя; amp; конечные положения & линия (код предоставляется)
2. найдите все новые индексы строк
3. отфильтруйте новые строки из индекса до и после выбора начальной и конечной позиций
4. Теперь вы готовы вырезать блок и перемещать его вверх/вниз по индексам новых строк

Graeme_Grant

Я написал вспомогательную функцию для вас, чтобы найти все индексы "новой строки" (или любой символ(ы), если на то пошло). Остальное зависит от вас.

Member 10974007

Система.Коллекции.Универсальный.Список`1[Система.Типа int32]
я получаю только не любой номер строки :)

Graeme_Grant

Я показал тебе, как им пользоваться. Может быть и так:
1. в введенном тексте нет новых строк (т. е. текст завернут)
2. текстовое поле выдает только символ новой строки (vbLF) или только возврат каретки (vbCR).
Таким образом, основная функция есть, вам просто нужно заставить ее работать.

Member 10974007

вы знаете, каждая вещь об этом
и откуда должен быть загружен отладчик

Graeme_Grant

отладчик встроен в visual studio. ppolymorphe дает вам ссылку на руководство для начинающих...