.NET图形重影

时间:2009-11-04 21:48:41

标签: .net vb.net winforms graphics drawing

我正在为我们正在开发的新应用程序制作示例GUI。该语言已经为我决定,但我可以使用任何第三方DLL或加载项或我需要的任何东西,以使GUI尽可能无缝地工作。

他们想要它非常像mac / ubuntu / vista / Windows 7,所以我想出了一些非常有趣的控件和漂亮的GUI功能。其中一个是屏幕顶部附近的一些增长/缩小按钮,当您将鼠标悬停在屏幕上方时会增加尺寸(它使用距离公式来计算需要增加的尺寸)。当您将鼠标从控件上移开时,它们会缩小。效果看起来非常专业和华丽,除了有一个重影效果,因为按钮缩小(和按钮右侧的按钮,因为它们固定在臀部)。

这是按钮在设计器中的样子:

alt text

以下是我用来执行此操作的一些代码段:

当父母悬停时,

会弹出下面的子按钮

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. 如果这只是我正在画的普通按钮,我可能不会有重影问题。
  3. 我做了什么,以及我是如何尝试解决的:

    1. 确保表单的双重缓冲已打开(确实如此)
    2. 使用bufferedGraphics类手动双重缓冲(没有帮助或使情况变得更糟)
    3. 说服设计师不需要背景图片或漂亮的玻璃按钮(不去)
    4. 在包含表单的矩形上运行Invalidate()(没有帮助)
    5. 在表单上运行Refresh()(修复重影,但现在整个屏幕在重新加载图像时闪烁)
    6. 坐在我隔间的一角,轻轻地对自己哭泣(帮助压力,但也没有解决问题)
    7. 我正在寻找的是这些问题的答案:

      1. 有谁知道如何摆脱我所描述的重影?我应该专注于不经常改变尺寸吗?我应该专注于缓冲背景图像吗?
      2. 我应该在这里使用其他技术吗?是否有比ActiveX用户继承的ActiveX控件更好?是否可以让DirectX用户控件使用图形卡自行绘制?
      3. 我还有其他想法吗?
      4. ~~~~~~~~~~~~~~~~~~~~~~~~~更新1:11/17/2009 9:21 AM ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

        我已经提高了绘制方法的效率,首先通过检查新值与已有的值(上面的代码更改)来检查它们是否需要重新绘制。这修复了一些鬼影,但核心问题仍有待解决。

2 个答案:

答案 0 :(得分:3)

可以快速解决您的问题。将此代码粘贴到表单中:

  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及更高版本。它可以对整个表单进行双重缓冲,而不仅仅是每个单独的控件,并且应该消除您看到的重影效果。

答案 1 :(得分:1)

我在代码中没有看到任何错误。您可以尝试以下方法:

在图片框上绘制背景图片,而不是表单本身。您可以将按钮保持在它前面,它应该看起来一样。然后,您可以使用绘图事件中的图形对象或使用带有图片框的持久图像来控制背景图像的重绘。为了防止闪烁,您只能重绘图像中位于按钮范围内的部分(或修改后的按钮及其右侧)。

这不太理想,但它可能是一种有用的解决方法。