窗口最大化时图像重复

时间:2016-02-09 17:29:07

标签: c# winforms

我正在设计一个HangMan游戏,以学习如何在DevExpress中使用C#。 我的问题是我正在绘制相对于我正在绘制它的面板大小的大小的帖子,以便在调整窗口大小时重新计算其大小。我的代码如下所示:

<DllImport("kernel32.dll")> _
Private Shared Function GetCurrentThreadId() As UInteger
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As Integer
End Function

<DllImport("user32.dll")> _
Private Shared Function SetDlgItemText(ByVal hWnd As IntPtr, ByVal nIDDlgItem As Integer, ByVal lpString As String) As Boolean
End Function

Private Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

Shared dlgHookProc As HookProc

Private Const WH_CBT As Long = 5
Private Const HCBT_ACTIVATE As Long = 5

Private Const ID_BUT_OK As Integer = 1
Private Const ID_BUT_CANCEL As Integer = 2
Private Const ID_BUT_ABORT As Integer = 3
Private Const ID_BUT_RETRY As Integer = 4
Private Const ID_BUT_IGNORE As Integer = 5
Private Const ID_BUT_YES As Integer = 6
Private Const ID_BUT_NO As Integer = 7

Private Const BUT_OK As String = "Save"
Private Const BUT_CANCEL As String = "Cancelar"
Private Const BUT_ABORT As String = "Stop"
Private Const BUT_RETRY As String = "Continue"
Private Const BUT_IGNORE As String = "Ignore"
Private Const BUT_YES As String = "Si"
Private Const BUT_NO As String = "No"

Private Shared _hook As Integer = 0

Private Shared Function DialogHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
  If nCode < 0 Then
    Return CallNextHookEx(_hook, nCode, wParam, lParam)
  End If

  If nCode = HCBT_ACTIVATE Then
    SetDlgItemText(wParam, ID_BUT_OK, BUT_OK)
    SetDlgItemText(wParam, ID_BUT_CANCEL, BUT_CANCEL)
    SetDlgItemText(wParam, ID_BUT_ABORT, BUT_ABORT)
    SetDlgItemText(wParam, ID_BUT_RETRY, BUT_RETRY)
    SetDlgItemText(wParam, ID_BUT_IGNORE, BUT_IGNORE)
    SetDlgItemText(wParam, ID_BUT_YES, BUT_YES)
    SetDlgItemText(wParam, ID_BUT_NO, BUT_NO)
  End If

  Return CallNextHookEx(_hook, nCode, wParam, lParam)
End Function

Private Sub btn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn.Click
  dlgHookProc = New HookProc(AddressOf DialogHookProc)

  _hook = SetWindowsHookEx(CInt(WH_CBT), dlgHookProc, IntPtr.op_Explicit(0), CInt(GetCurrentThreadId()))

  Dim dlgEmptyCheck As DialogResult = MessageBox.Show("Text", "Caption", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3)


  If dlgEmptyCheck = DialogResult.Abort Then
  End If

  UnhookWindowsHookEx(_hook)
End Sub

这对我来说很完美,后期绘图也会调整大小。但是,当我手动调整窗口大小时,每个步骤都会绘制一个新帖子,因此会显示许多帖子。如果我最大化窗口,则会出现两个不同大小的帖子。

然而,当我最小化窗口并再次打开窗口时,只需保留适当的绘图。有没有办法在绘制新图纸时擦除以前的图纸?

我应该在 InitializeComponent()之后加入某种擦除命令吗?

2 个答案:

答案 0 :(得分:4)

因此,问题的主要部分是您对表格的绘画事件做出回应,然后绘制到控件上,该控件可能已经失效,也可能没有失效。

相反,您应该订阅面板的绘制事件,然后使用传递给事件参数的Graphics对象进行绘制。此外,您还需要处理面板的resize事件以使其无效。我假设您在调整表单大小时使用锚点或停靠来自动调整面板大小。如果不是,则需要更改它,以便在表单调整时调整面板大小。

    public Form1()
    {
        InitializeComponent();

        pnlHang.Paint += PnlHangPaint;
        pnlHang.Resize += (sender, args) => pnlHang.Invalidate();
    }

    private void pnlHang_Paint(object sender, PaintEventArgs paintEventArgs)
    {
        drawHangPost(paintEventArgs.Graphics);
    }

    void drawHangPost(Graphics g)
    {
        //Use panel size percentages to draw the post
        double dWidth = pnlHang.Width;
        double dHeight = pnlHang.Height;

        int x1 = (int)Math.Round(0.8 * dWidth);
        int x2 = (int)Math.Round(0.45 * dWidth);
        int y1 = (int)Math.Round(dHeight);
        int y2 = (int)Math.Round(0.23 * dHeight);
        int xInit = x1;
        int xFinal = x1 - x2;
        int yInit = y1;
        int yMiddle = 10;
        int yFinal = y2;

        //Paint Post
        using (Pen p = new Pen(Color.Brown, 10))
        {
            g.DrawLine(p, new Point(xInit, yInit), new Point(xInit, yMiddle));
            g.DrawLine(p, new Point(xInit, yMiddle), new Point(xFinal, yMiddle));
            g.DrawLine(p, new Point(xFinal, yMiddle), new Point(xFinal, yFinal));
        }
    }

此外,无论何时创建像笔或画笔这样的GDI资源,请务必处置它们! C#using block可以很好地为您完成。

答案 1 :(得分:-1)

你的问题是你一遍又一遍地使用同一个控件。一个简单的解决方案是填充一个绘制在前一个图像上的矩形。这将使帧经常闪烁,所以我要解决的是创建一个新的Bitmap并在其上绘制。然后我在面板上绘制编译的位图。

public void Draw(Graphics g){
Bitmap canvas = new Bitmap(pnlHang.Width, pnlHang.Height);
Graphics canvg = Graphics.FromImage(canvas);
canvg.FillRectangle(Brushes.Black, new Rectangle(new Point(0, 0), pnlHang.Size);
//Draw using canvg
canvg.Dispose();
g.DrawImage(canvas, new Rectangle(new Point(0, 0), pnlHang.Size));
}