kkdxghlctlcxxtidyuum Ответов: 1

Почему этот код глючит? - [Отображение количества строк рядом с RTB]


Привет,

Я уже несколько дней пытаюсь заставить этот код работать, но до сих пор не нашел решения. Я пытаюсь отобразить количество строк (в RichTxtBx) на picturebox (как это видно в большинстве редакторов кода и ide).

Это текущий код:

Option Strict On
Public Class Form1

    Dim total_lines As Integer
    Private Sub DrawRichTextBoxLineNumbers(ByRef g As Graphics)

        With RichTextBox1
            Dim font_height As Single
            font_height = .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(2)).Y _
            - .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(1)).Y
            If font_height = 0 Then Exit Sub

            Dim first_index As Integer
            Dim first_line As Integer
            Dim first_line_y As Integer
            first_index = .GetCharIndexFromPosition(New Point(0, CInt(g.VisibleClipBounds.Y + font_height / 3)))
            first_line = .GetLineFromCharIndex(first_index)
            first_line_y = .GetPositionFromCharIndex(first_index).Y
            total_lines = RichTextBox1.GetLineFromCharIndex(Int32.MaxValue) + 1

            Dim i As Integer = first_line + 1
            Dim y As Single
            Do While y < g.VisibleClipBounds.Y + g.VisibleClipBounds.Height
                y = first_line_y + 2 + font_height * (i - first_line - 1)
                If total_lines >= i Then
                    g.DrawString((i).ToString, .Font, Brushes.White, PictureBox1.Width _
               - g.MeasureString((i).ToString, .Font).Width, y)
                Else
                    Exit Do
                End If
                i += 1
            Loop
        End With
    End Sub

    Private Sub r_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.Resize
        PictureBox1.Invalidate()
    End Sub

    Private Sub r_VScroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.VScroll
        PictureBox1.Invalidate()
    End Sub

    Private Sub p_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        DrawRichTextBoxLineNumbers(e.Graphics)
    End Sub

    Private Sub MyRichTextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RichTextBox1.TextChanged
        If RichTextBox1.GetLineFromCharIndex(Int32.MaxValue) + 1 <> total_lines Then PictureBox1.Invalidate()
    End Sub
End Class


Вот GIF, показывающий эти проблемы:

Image - TinyPic - бесплатный хостинг изображений, обмен фотографиями и видеохостинг[^]

Кто-нибудь знает решение этой проблемы? У меня нет идей (у меня не так много опыта, поэтому мои идеи довольно ограничены).

Заранее большое вам спасибо - для меня было бы очень важно наконец решить эту проблему, чтобы взяться за остальную часть моего проекта; яааай!!!

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

Меняя цифры, глядя на код, пытаясь понять его. Я особенно сосредоточился на модификации:
first_index = .GetCharIndexFromPosition(New Point(0, CInt(g.VisibleClipBounds.Y + font_height / 3)))

1 Ответов

Рейтинг:
4

Member 13587529

Я не могу быть уверен, но следующий код выглядит подозрительно:

Dim font_height As Single
font_height = .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(2)).Y _
            - .GetPositionFromCharIndex(.GetFirstCharIndexFromLine(1)).Y


Он опирается на существование третьей (индекс = 2) и второй (индекс = 1) строки в текстовом поле в качестве части его расчета. Линейные индексы основаны на нуле.

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

Это объясняет, почему, когда есть только одна строка, номер строки не рисуется(потому что переменная высоты шрифта устанавливается в (-1 - -1), что равно 0.

Когда есть две строки, я не хочу спекулировать, каковы фактические числа, но результаты вычисления, вероятно, будут чем - то вроде (-1-11), то есть -12. Ясно, что это неправильно.

Вы можете проверить это, введя следующий код: If .GetFirstCharIndexFromLine(2) = -1 Then Stop. Он должен проникнуть в отладчик.

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

Чтобы дать вам представление, лучшим подходом, вероятно, было бы установить переменную font_height просто равной высоте шрифта (доступной через свойство Font?). Я бы также предложил вам узнать, сколько строк находится в RichTextBox, позвонив по телефону .Линии.Рассчитывать.

Затем сгенерируйте строку, которую нужно нарисовать, зацикливаясь и вставляя vbCrLf между каждым номером строки. Например:
Dim line_number_string как строка
Для i = 1 to .Линии.Рассчитывать
line_number_string = line_number_string &амп; функция cstr(я) &ампер; vbCrLf
Следующий


Чтобы нарисовать номера линий, то просто вызовите DrawString, начиная с координат 0,0.

Если затем вы хотите исправить положение Y с учетом прокрутки (чтобы номера строк совпадали со строками при прокрутке вниз), позвоните по телефону:
first_line_y_coordinate = .GetPositionFromCharIndex(0).Y

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

Я думаю, что это даст вам Y-позицию первой строки, и вызовите drawstring с этим значением. Итак, где вы в настоящее время называете DrawString следующим образом:
g.DrawString((i).ToString, .Font, Brushes.White, PictureBox1.Width _
               - g.MeasureString((i).ToString, .Font).Width, y)


Вместо этого назовите его следующим образом:
g.DrawString(line_number_string, .Font, Brushes.White, 0, first_line_y_coordinate)