.NET графика Ghosting

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

Они хотят, чтобы он был очень похож на mac/ubuntu/vista/Windows 7, поэтому я предложил несколько очень интересных элементов управления и красивые функции графического интерфейса. Одной из них являются некоторые растущие / уменьшающиеся кнопки в верхней части экрана, которые увеличиваются в размере при наведении на них курсора (она использует формулу расстояния для вычисления размера, на который нужно увеличить). Когда вы убираете мышь с органов управления, они снова уменьшаются. Эффект выглядит очень профессионально и броско, за исключением того, что появляется эффект ореола, когда кнопка сжимается назад (и кнопки справа от нее, поскольку они зафиксированы на бедре).

Вот как выглядят кнопки в дизайнере:

альтернативный текст

Вот некоторые фрагменты кода, которые я использую для этого:

выдвигает дочерние кнопки внизу, когда родитель наведен

Private Sub buttonPop(ByVal sender As Object, ByVal e As System.EventArgs)
    For Each control As System.Windows.Forms.Control In Me.Controls
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.Y > sender.Location.Y AndAlso control.Location.X >= sender.Location.X AndAlso control.Width < sender.Width AndAlso control.Location.X + control.Width < sender.Location.X + sender.Width Then
            control.Visible = True
        End If
    Next
End Sub

размер больших кнопок возвращается в нормальное состояние после ухода мыши

Private Sub shrinkpop(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim oldSize As Size = sender.Size
    sender.Size = New Size(60, 60)
    For Each control As System.Windows.Forms.Control In Me.Controls
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.X > sender.Location.X AndAlso (Not control.Location.X = control.Location.X + (sender.size.width - oldSize.Width)) Then

            control.Location = New Point(control.Location.X + (sender.size.width - oldSize.Width), control.Location.Y)

        End If
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.Y > sender.Location.Y AndAlso control.Location.X = sender.Location.X AndAlso control.Width < sender.Width Then
            control.Location = New Point(control.Location.X, control.Location.Y + (sender.size.height - oldSize.Height))
            If Windows.Forms.Control.MousePosition.X < control.Location.X Or Windows.Forms.Control.MousePosition.X > control.Location.X + control.Width Then
                control.Visible = False
            End If
        End If
    Next
End Sub

увеличение размера больших командных кнопок в зависимости от положения мыши в кнопке, происходит при перемещении мыши

    Private Sub buttonMouseMovement(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
    Dim oldSize As Size = sender.Size
    Dim middle As Point = New Point(30, 30)
    Dim adder As Double = Math.Pow(Math.Pow(middle.X - e.X, 2) + Math.Pow(middle.Y - e.Y, 2), 0.5)
    Dim total As Double = Math.Pow(1800, 0.5)

    adder = (1 - (adder / total)) * 20

    If Not (sender.size.width = 60 + adder And sender.size.height = 60 + adder) Then
        sender.Size = New Size(60 + adder, 60 + adder)
    End If
    For Each control As System.Windows.Forms.Control In Me.Controls
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.X > sender.Location.X AndAlso (Not control.Location.X = control.Location.X + (sender.size.width - oldSize.Width)) Then
            control.Location = New Point(control.Location.X + (sender.size.width - oldSize.Width), control.Location.Y)
        End If
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.Y > sender.Location.Y AndAlso control.Location.X >= sender.Location.X AndAlso control.Width < sender.Width AndAlso control.Location.X + control.Width < sender.Location.X + sender.Width AndAlso (Not control.Location.Y = control.Location.Y + (sender.size.height - oldSize.Height)) Then
            control.Location = New Point(control.Location.X, control.Location.Y + (sender.size.height - oldSize.Height))
        End If
    Next
End Sub

увеличить размер меньших командных кнопок

Private Sub SmallButtonMouseMovement(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
    Dim oldSize As Size = sender.Size
    Dim middle As Point = New Point(22.5, 22.5)
    Dim adder As Double = Math.Pow(Math.Pow(middle.X - e.X, 2) + Math.Pow(middle.Y - e.Y, 2), 0.5)
    Dim total As Double = Math.Pow(1012.5, 0.5)

    adder = (1 - (adder / total)) * 15

    If Not (sender.size.Width = 45 + adder And sender.size.height = 45 + adder) Then
        sender.Size = New Size(45 + adder, 45 + adder)
    End If
    For Each control As System.Windows.Forms.Control In Me.Controls
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.Y > sender.Location.Y AndAlso control.Location.X = sender.location.X AndAlso (Not control.Location.Y = control.Location.Y + (sender.size.height - oldSize.Height)) Then
            control.Location = New Point(control.Location.X, control.Location.Y + (sender.size.height - oldSize.Height))
        End If
    Next
End Sub

уменьшение переводит кнопки команд в правильное положение и при необходимости скрывает их

    Private Sub SmallShrinkPop(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim oldsize As Size = sender.Size
    If Not (sender.size.width = 45 AndAlso sender.size.height = 45) Then
        sender.size = New Size(45, 45)
    End If

    Dim ChildCounter As Integer = 0

    For Each control As System.Windows.Forms.Control In Me.Controls
        If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.X = sender.location.X AndAlso control.Width = sender.width AndAlso control.Location.Y > sender.location.y Then
            ChildCounter += 1
            control.Location = New Point(control.Location.X, control.Location.Y + (sender.size.height - oldsize.Height))
            If Windows.Forms.Control.MousePosition.X < control.Location.X Or Windows.Forms.Control.MousePosition.X > control.Location.X + control.Width Then
                sender.visible = False
                control.Visible = False
            End If
        End If
    Next
    If (ChildCounter = 0 AndAlso Windows.Forms.Control.MousePosition.Y > sender.Location.Y + sender.Height) Or (Windows.Forms.Control.MousePosition.X < sender.Location.X Or Windows.Forms.Control.MousePosition.X > sender.Location.X + sender.Width) Then
        sender.visible = False
        For Each control As System.Windows.Forms.Control In Me.Controls
            If control.GetType.ToString = "Glass.GlassButton" AndAlso control.Location.X = sender.location.x AndAlso control.Width = sender.width Then
                control.Visible = False
            End If
        Next
    End If
End Sub

Что я знаю:

  1. Если бы у формы не было фонового изображения, у меня не было бы проблемы с ореолом.
  2. Если бы это была обычная кнопка, которую я рисую, у меня, вероятно, не было бы проблемы с ореолом.

Что я сделал и как я пытался это исправить:

  1. Обеспечение включения двойной буферизации формы (было)
  2. Двойная буферизация вручную с использованием класса bufferedGraphics (не помогло или сделало его хуже)
  3. Убедите дизайнеров, что им не нужны фоновые изображения или красивые стеклянные кнопки (не ходите)
  4. Запустите Invalidate() на прямоугольнике, содержащем форму (не помогло)
  5. Запустите Refresh() в форме (исправлено двоение, но теперь весь экран мигает при перезагрузке изображения)
  6. Сядьте в угол моей кабинки и тихо плачьте себе (помогали от стресса, но также не решали проблему)

Что я ищу, так это ответы на эти вопросы:

  1. У кого-нибудь есть идеи, как избавиться от призраков, которые я описываю? Должен ли я сосредоточиться на изменении размера реже? я должен сосредоточиться на буферизации фонового изображения?
  2. Есть ли другие технологии, которые я должен использовать здесь? Существуют ли элементы управления ActiveX, которые были бы лучше в этом, чем унаследованные пользователем.NET? Можно ли заставить пользовательский элемент управления DirectX использовать графическую карту для рисования?
  3. Есть ли что-то еще, о чем я не думаю здесь?

~~~~~~~~~~~~~~~~~~~~~~~~~ Обновление 1: 17.11.2009 9:21 ~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~

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

2 ответа

Решение

Возможно быстрое решение вашей проблемы. Вставьте этот код в вашу форму:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      this.IsMdiContainer = true; 
      foreach (Control ctl in this.Controls) {
        if (ctl is MdiClient) {
          ctl.BackgroundImage = Properties.Resources.SampleImage;
          break;
        }
      }
    }
    protected override CreateParams CreateParams {
      get {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
      }
    }
  }

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

Я не вижу ничего плохого в коде. Вот что вы можете попробовать:

Нарисуйте фоновое изображение на картинке размером с форму, а не саму форму. Вы можете держать кнопки перед ним, и он должен выглядеть одинаково. Затем вы можете управлять перерисовкой фонового изображения, используя графический объект в событии рисования или используя постоянное изображение с графическим блоком. Чтобы предотвратить мерцание, вы можете перерисовать только ту часть изображения, которая находится в пределах кнопок (или измененной кнопки и тех, которые находятся справа).

Это не идеально, но это может быть полезным обходным путем.

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