Мерцание панели с помощью Pictureboxes

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

... Ничего из этого на самом деле не работает, как ожидалось, лучший "Flicker-Reducer", который я нашел, - это переопределитель "Createparams", но этот метод делает любую форму / приложение в 20 раз медленнее любой операции формы, я не хотите потерять мерцание, если это также означает потерю производительности приложения (по крайней мере, если это тот же отрицательный момент производительности CreateParams).

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

http://www.youtube.com/watch?v=zIBDTMjrDd4&feature=youtu.be

Я использую метод "CreateParams", на самом деле вы не увидите, что происходит с мерцанием моей панели, если я не использую "CreateParams", очень страшно.

Это панель, когда не мигает:

И это панель в тот момент, когда она Flickered:

Вот полный класс:

It is a Windows Form proyect
VS2012
Framework 3.5
On Windows 7 x64
Application Visual Styles is ON
Double Buffer is ON
Panel and pictureboxes are default controls

(Думаю, нет необходимости говорить, что я перепробовал все возможные визуальные конфигурации и конфигурации среды, которые, как говорили люди, меня навсегда забыли о мерцании.)

Public Class Form1

    Dim Scroll_Position As Int32 = 0
    Dim Button_Down_Is_Pressed As Boolean = False
    Dim Button_Up_Is_Pressed As Boolean = False
    Dim WithEvents Progressive_Scroll_Timer As New Timer
    Dim SmallChange As Int32 = 5
    Dim Largechange As Int32 = 10

    ' Sub which reduces the Flickering, but this sub makes x20 times slower any operation of any Form/Application.
    Protected Overrides ReadOnly Property CreateParams() As CreateParams
        Get
            Dim cp As CreateParams = MyBase.CreateParams
            cp.ExStyle = cp.ExStyle Or &H2000000
            Return cp
        End Get
    End Property 'CreateParams

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Me.BackColor = Color.FromArgb(255, 0, 0, 0)
        ' Me.TransparencyKey = Color.FromArgb(255, 0, 0, 0)
        Panel1.VerticalScroll.Maximum = 999999999
        Progressive_Scroll_Timer.Interval = 50
        Panel1.BackColor = Color.FromArgb(150, 0, 0, 0)
    End Sub

    Private Sub Panel_MouseHover(sender As Object, e As EventArgs) Handles Panel1.MouseHover
        sender.focus()
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Progressive_Scroll_Timer.Tick
        If Button_Down_Is_Pressed Then
            Scroll_Down(SmallChange)
        ElseIf Button_Up_Is_Pressed Then
            Scroll_Up(SmallChange)
        Else
            sender.stop()
        End If
    End Sub

    Private Sub Scroll_Up(ByVal Change As Int32)
        Scroll_Position -= Change
        Panel1.SuspendLayout()
        Try : Panel1.VerticalScroll.Value = Scroll_Position : Catch : Scroll_Position += Change : End Try
        Panel1.ResumeLayout()
    End Sub

    Private Sub Scroll_Down(ByVal Change As Int32)
        Scroll_Position += Change
        Try : Panel1.VerticalScroll.Value = Scroll_Position : Catch : Scroll_Position -= Change : End Try
    End Sub

    Private Sub Button_Down_MouseDown(sender As Object, e As MouseEventArgs) Handles Button2.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Button_Down_Is_Pressed = True
            Progressive_Scroll_Timer.Start()
        End If
    End Sub

    Private Sub Button_Up_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Button_Up_Is_Pressed = True
            Progressive_Scroll_Timer.Start()
        End If
    End Sub

    Private Sub Button_Down_MouseUp(sender As Object, e As MouseEventArgs) Handles Button2.MouseUp
        Button_Down_Is_Pressed = False
    End Sub

    Private Sub Button_Up_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp
        Button_Up_Is_Pressed = False
    End Sub

    Private Sub Form_MouseWheel(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Panel1.MouseWheel
        If Panel1.Focused Then
            Select Case Math.Sign(e.Delta)
                Case Is > 0 : Scroll_Up(Largechange)
                Case Is < 0 : Scroll_Down(Largechange)
            End Select
        End If
    End Sub

End Class

4 ответа

Решение

Установить Panel"s AutoScroll собственность на true, Без этого прокрутка не работает. Добавить DoubleBufferedPanel класс, который наследует от Panel класс и устанавливает .DoubleBuffered свойство к истине:

Public Class DoubleBufferedPanel
    Inherits Panel

    Public Sub New()
        DoubleBuffered = True
    End Sub
End Class

Теперь иди к скрытому InitializeComponent суб (щелкните правой кнопкой мыши на Panel1 переменная и нажмите Go To Definition). замещать Panel введите с DoubleBufferedPanel где необходимо (два места):

Me.Panel1 = New WindowsApplication4.DoubleBufferedPanel()
....
Friend WithEvents Panel1 As WindowsApplication4.DoubleBufferedPanel

Мерцание должно прекратиться (хотя есть еще некоторые другие эффекты). Удалить CreateParams увеличить скорость.

PS В целом, это не очень хорошая идея (перемещение сложных полупрозрачных изображений). Почему бы тебе не использовать что-то вроде ListView? Почему бы вам не переместить изображения самостоятельно, не используя Panel? Если вы хотите лучшую скорость, просто нарисуйте изображения на форме (.BackgroundImage) с помощью Bitmap а также Graphics классы.

PPS Кажется, есть некоторая серьезная ошибка с программной прокруткой Panel с .AutoScroll = true, Мне пришлось дважды назначить значения прокрутки, чтобы избежать серьезного дрожания. Я выделил случай и отправлю отчет об ошибке в Microsoft.

Вы можете установить формы DoubleBuffered Недвижимость в True

Редактировать:

Я думаю, что вам не нужен таймер. Итак, ваш модифицированный код будет выглядеть примерно так:

Public Class Form1

    Dim Scroll_Position As Int32 = 0
    Dim SmallChange As Int32 = 5
    Dim Largechange As Int32 = 10

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Me.BackColor = Color.FromArgb(255, 0, 0, 0)
        ' Me.TransparencyKey = Color.FromArgb(255, 0, 0, 0)
        Panel1.VerticalScroll.Maximum = 999999999
        Panel1.BackColor = Color.FromArgb(150, 0, 0, 0)
    End Sub

    Private Sub Panel_MouseHover(sender As Object, e As EventArgs) Handles Panel1.MouseHover
        sender.focus()
    End Sub

    Private Sub Scroll_Up(ByVal Change As Int32)
        Try
            Scroll_Position -= Change
            Panel1.VerticalScroll.Value = Scroll_Position 
        End Try
    End Sub

    Private Sub Scroll_Down(ByVal Change As Int32)
        Try
            Scroll_Position += Change
            Panel1.VerticalScroll.Value = Scroll_Position 
        End Try
    End Sub

    Private Sub Button_Down_MouseDown(sender As Object, e As MouseEventArgs) Handles Button2.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            scrollDown(smallChange)
        End If
    End Sub

    Private Sub Button_Up_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            scrollUp(SmallChange)
        End If
    End Sub

    Private Sub Form_MouseWheel(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Panel1.MouseWheel
        If Panel1.Focused Then
            Select Case Math.Sign(e.Delta)
                Case Is > 0 : Scroll_Up(Largechange)
                Case Is < 0 : Scroll_Down(Largechange)
            End Select
        End If
    End Sub

End Class

Это не может быть решением, но это усилие с моей стороны.

Используйте комплекс class это представляет panel а то контент, то покрасим (GDI+) это на Picturebox будет делать хорошо. Я сделал несколько таких проектов.

Положить это в вашей форме загрузки

' to remove flick
Dim aProp As PropertyInfo = GetType(Panel).GetProperty("DoubleBuffered", BindingFlags.NonPublic Or BindingFlags.Instance)
        aProp.SetValue(Panel7, True, Nothing)

замените Panel7 именем элемента управления на фоновое изображение.

Другие вопросы по тегам