Как избежать наложения непрозрачных прямоугольников на graphics.drawrectangle()?

После нескольких неудачных поисков в Google, наконец, я подумал о том, чтобы попросить экспертов помочь мне в этой проблеме, поскольку этот сайт всегда мне помогал.

Чего я хочу?

Я хочу создать маркер для своего приложения для рисования. Я хочу, чтобы это было похоже на маркер, который вы видите в Windows Snipping Tool.

В чем моя проблема?

Проблема заключается в том, что хотя я и могу рисовать полупрозрачные или непрозрачные прямоугольники с помощью кода gfx.FillRectangle(New SolidBrush(Color.FromArgb(100, Colors.GreenYellow)), x, y, width, height), но если я рисую другой прямоугольник, перекрывающий любые предыдущие прямоугольники, цвета становятся темнее и уменьшают прозрачность прямоугольников в местах их перекрытия.

Код:

Public Class Form1
    Dim drag As Boolean
    Dim mouseX, mouseY As Integer
    Dim prev As Point
    Dim initi As Point
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        Dim grx As Graphics = Panel1.CreateGraphics
        grx.DrawString("+", New Font("Arial", 144, FontStyle.Regular), New SolidBrush(Color.FromArgb(100, Color.GreenYellow)), New Point(200, 200))
    End Sub

    Private Sub Panel1_MouseDown(sender As Object, e As MouseEventArgs) Handles Panel1.MouseDown
        drag = True
        mouseX = MousePosition.X - Me.Left - 8
        mouseY = MousePosition.Y - Me.Top - 34
        initi = New Point(mouseX, mouseY)
    End Sub

    Private Sub Panel1_MouseMove(sender As Object, e As MouseEventArgs) Handles Panel1.MouseMove
        If drag Then
            mouseX = MousePosition.X - Me.Left - 8
            mouseY = MousePosition.Y - Me.Top - 34
        End If
    End Sub

    Private Sub Panel1_MouseUp(sender As Object, e As MouseEventArgs) Handles Panel1.MouseUp
        drag = False
        prev = New Point(0, 0)
        Dim grx As Graphics = Panel1.CreateGraphics
        grx.FillRectangle(New SolidBrush(Color.FromArgb(100, Color.GreenYellow)), initi.X, initi.Y, (mouseX - initi.X), (mouseY - initi.Y))

    End Sub
End Class

Скриншот приложения (показывает проблему)

  • Левый "+" тот, который я хочу нарисовать.
  • Правильный "+" - это тот, который я получаю, когда рисую.

введите здесь описание изображения


person Mohammed Julfikar Ali Mahbub    schedule 26.09.2017    source источник
comment
Взгляните на эту ссылку о рисовании с альфа-смешением. Там может быть что-то, что работает для вас. docs.microsoft.com/ en-us/dotnet/framework/winforms/advanced/   -  person David Wilson    schedule 26.09.2017
comment
Привет Дэвид, Спасибо за эту замечательную ссылку, это было очень полезно. Я узнал о ComposingMode.SourceCopy. Но проблема в том, что он перезаписывает фон, выбирая один цвет, например, если я использую его поверх изображения, хотя нарисованные линии не изменят свой цвет для перекрытия и сохранения постоянного цвета нарисованных линий, но он выбирает только один цвет в качестве фона цвет с изображения и, наконец, перекрывает изображение, делая его одним цветом, или вы можете сказать, стирая изображение на цветном фоне или стирая изображение с помощью цветных ластиков. :P Есть еще предложения?   -  person Mohammed Julfikar Ali Mahbub    schedule 26.09.2017


Ответы (2)


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

Добавьте это в объявления переменных вашей формы

Dim highlightsList As New List(Of Rectangle)
Dim bmp1 As Bitmap

измените ваше событие form_show на

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    bmp1 = New Bitmap(Panel1.Width, Panel1.Height)
End Sub 

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

Private Sub addRectangle(gr As Graphics, x As Integer, y As Integer, v1 As Integer, v2 As Integer)
    Dim newRectangle As New Rectangle(x, y, v1, v2)
    highlightsList.Add(newRectangle)
    Using G As Graphics = Graphics.FromImage(bmp1)
        G.Clear(Color.White)
    End Using
    bmp1.MakeTransparent(Color.White)
    For Each rect As Rectangle In highlightsList
        For i As Integer = rect.X To rect.X + rect.Width - 1
            For j As Integer = rect.Y To rect.Y + rect.Height - 1
                bmp1.SetPixel(i, j, Color.FromArgb(100, Color.GreenYellow))
            Next
        Next
    Next
    Panel1.Refresh()
End Sub

добавить обработчик события рисования панели, чтобы при обновлении панели растровое изображение рисовалось на ней

Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
    e.Graphics.DrawImage(bmp1, 0, 0)
End Sub

и измените событие mouse_up, чтобы использовать приведенный выше подраздел для рисования

Private Sub Panel1_MouseUp(sender As Object, e As MouseEventArgs) Handles Panel1.MouseUp
    drag = False
    prev = New Point(0, 0)
    Dim grx As Graphics = Panel1.CreateGraphics
    'grx.Clear(Panel1.BackColor)
    addRectangle(grx, initi.X, initi.Y, (mouseX - initi.X), (mouseY - initi.Y))
End Sub

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

person David Wilson    schedule 27.09.2017
comment
Ваш подход кажется хорошим. Я планировал что-то подобное, но не получил код bmp1.MakeTransparent(Color.White), но проблема в том, что я не буду использовать прямоугольники, вместо этого я собираюсь использовать FillEllipse. Здесь я использовал прямоугольник, чтобы показать чистую визуализацию. Но в любом случае я попытаюсь реализовать вашу идею со своей, чтобы проверить, смогу ли я решить эту проблему. Благодарю вас! - person Mohammed Julfikar Ali Mahbub; 27.09.2017

Я попробовал это, и это работает: границ нет, вы даже не можете различить разные поля: я изменил следующее:

New SolidBrush(Color.FromArgb(100, Color.GreenYellow)), New Point(200, 200))

В это:

New SolidBrush(Color.GreenYellow), New Point(200, 200))

В ОБОИХ случаях: для объявлений и для Panel1_MouseDown Это потому, что это устанавливает альфа-канал равным 1, по умолчанию также делая неизменяемым, поэтому перекрытие не изменит ни цвета, ни слои, ни видимость.

Вы должны использовать FromArgb только тогда, когда собираетесь управлять альфой цвета, но в этом случае вы позволяете компьютеру сделать это за вас.

person TGamer    schedule 26.09.2017
comment
Возможно, вы неправильно поняли мой вопрос, потому что использование вашего кода не приведет к ошибке «изменение цвета при перекрытии», но это потому, что он будет рисовать сплошные линии, а не полупрозрачную ** линию, которая в моем случае мне нужна. Потому что я хочу, чтобы он действовал как маркер, как я уже упоминал в вопросе. И, пожалуйста, поправьте меня, если я неправильно понимаю ваш ответ и концепцию. - person Mohammed Julfikar Ali Mahbub; 26.09.2017
comment
Я думаю, что есть небольшое недоразумение. В вашем вопросе никогда не говорилось, что вам нужен триггер ошибки любого типа, и я протестировал свой код, чтобы дать то, что вы просили, на картинке. Прочитайте мой ответ еще раз, пожалуйста. - person TGamer; 30.09.2017
comment
Я имел в виду, что ваш код New SolidBrush(Color.GreenYellow), New Point(200, 200)) никогда не будет давать полупрозрачный рисунок, насколько мне известно (поправьте меня, если я ошибаюсь). Но в своем вопросе я просил полупрозрачные рисунки. - person Mohammed Julfikar Ali Mahbub; 30.09.2017