C# Winform ArgumentException 未处理

问题描述 投票:0回答:1

我只是想在桌面的副本上显示鼠标位置。

我有一个无边框、最大化的表单,并包含一个带 DockStyle.Fill 的 PictureBox。在表单构造函数中,我从 PrimaryScreen 创建位图来设置 PictureBox 的图像并为 PictureBox.MouseMove 事件添加处理程序。如果事件处理程序被注释掉,此代码将起作用。

    public partial class Form1 : Form
    {
        // The original image.
        Bitmap ScreenCaptureBitmap = null;

        public Form1()
        {
            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;
            this.WindowState = FormWindowState.Maximized;
            picDesktop.Dock = DockStyle.Fill;
            Graphics graphics = null;
            picDesktop.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PictureBox_MouseMove);

            try
            {
                ScreenCaptureBitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                graphics = Graphics.FromImage(ScreenCaptureBitmap);
                graphics.CopyFromScreen(0, 0, 0, 0, ScreenCaptureBitmap.Size);
                picDesktop.Image = ScreenCaptureBitmap;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                graphics.Dispose();
            }
        }

这是 MouseMove 事件处理程序的代码:

private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
    try
    {
        // Make a Bitmap to display the location text.
        using (Bitmap bmTemp = new Bitmap(ScreenCaptureBitmap))
        {
            // Draw the location text on the bitmap.
            using (Graphics gr = Graphics.FromImage(bmTemp))
            {
                Brush theBrush =
                     SystemBrushes.FromSystemColor(SystemColors.WindowText);
                gr.DrawString(String.Format("({0}, {1})", e.X, e.Y),
                    this.Font, theBrush, e.X + 10, e.Y - 30);
                // Display the temporary bitmap.
                picDesktop.Image = bmTemp;
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

当我编译和调试时,Application.Run(new Form1());行得到“ArgumentException 未处理”。详细信息是“{System.ArgumentException:参数无效。 在 System.Drawing.Image.get_Width()}"。

c# winforms bitmap mousemove argumentexception
1个回答
0
投票

此处提供的代码的主要问题是 MoouseMove 事件处理程序中生成的 Bitmap 对象是使用

using
语句声明的。
using
块退出时,Bitmap 就会被释放。这是游戏的终结者。 此时可能会生成不同类型的异常,具体取决于其他代码之后尝试执行的操作。

  • 基于评论:当您将 Bitmap 对象分配给 PictureBox 的
    Image
    属性时,该位图不会被复制或以任何方式 cached 。仅存储对指定 Bitmap 对象的引用。

无论如何,在每次鼠标移动事件上生成一个新的位图(以全屏显示),只是为了绘制一些文本,是一个非常昂贵的过程,必然会产生相当明显的卡顿(并且可能会产生其他形式的异常)。

我的建议是复制屏幕的内容,将生成的位图设置为

BackgroundImage
属性(Image 属性也可以),然后在 PictureBox 的
Paint
事件处理程序中绘制文本。
文本渲染到控件的表面上,它不会影响位图。

需要注意的是,BackgrounImage、Image 和 Control 的表面(其设备上下文)构成了三个不同的、独立的层。您可以修改其中一个而不影响其他。

Screen.PrimaryScreen
返回的Screen对象可以为null

根据这些建议修改代码

GetTextBoundingBox()
方法用于剪辑可见屏幕捕获的边界内的文本,因此当鼠标指针(可能)移出这些边界时,文本不会移出屏幕。

public partial class Form1 : Form {
    Bitmap screenCaptureBitmap = null;
    Point mousePosition = Point.Empty;

    public Form1() {
        InitializeComponent();

        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;
        picDesktop.Dock = DockStyle.Fill;

        try {
            if (Screen.PrimaryScreen != null) {
                Size imageSize = Screen.PrimaryScreen.Bounds.Size;
                screenCaptureBitmap = new Bitmap(imageSize.Width, imageSize.Height);
                using (var g = Graphics.FromImage(screenCaptureBitmap)) {
                    g.CopyFromScreen(0, 0, 0, 0, imageSize);
                    picDesktop.BackgroundImage = screenCaptureBitmap;
                }
            }
        }
        catch (Exception ex) {
            Debug.WriteLine(ex.Message);
        }

        picDesktop.MouseMove += PicDesktop_MouseMove;
        picDesktop.Paint += PicDesktop_Paint;
    }

    private void PicDesktop_MouseMove(object? sender, MouseEventArgs e) {
        mousePosition = e.Location;
        picDesktop.Invalidate();
    }

    private void PicDesktop_Paint(object sender, PaintEventArgs e) {
        string positionText = $"(x: {mousePosition.X}, y: {mousePosition.Y})";
        var textBounds = GetTextBoundingBox(
            e.Graphics, Font, positionText, new Point(mousePosition.X + 10, mousePosition.Y - 10));

        TextRenderer.DrawText(e.Graphics, positionText, Font, textBounds, SystemColors.WindowText);
    }

    private Rectangle GetTextBoundingBox(Graphics g, Font font, string text, Point location) {
        Rectangle textBox = new Rectangle(location, TextRenderer.MeasureText(g, text, font));
        var screenBox = g.VisibleClipBounds;

        textBox.Location = new Point(
            Math.Max(Math.Min((int)screenBox.Width - textBox.Width, location.X), 0),
            Math.Max(Math.Min((int)screenBox.Height - textBox.Height, location.Y), 0));
        return textBox;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.