如何在WinForms / C#中选择区域时消除 Flink

hgtggwj0  于 2023-04-12  发布在  C#
关注(0)|答案(1)|浏览(108)

我正在使用WinForms/C#开发简单的应用程序。经过大量研究,我无法摆脱显着的 Flink 。下面是我正在尝试做的事情:

  • 在背景面板中添加图像(图像在加载后不会更改)
  • 通过在图像顶部的第二个面板上拖动矩形区域来选择图像的一个区域。图像面板是窗体的子面板,拖动面板是图像面板的子面板。提供的示例是我需要选择/拖动对象的两个面板方法的简化。

我对这个主题做了广泛的研究,虽然我能够最小化基于计时器/双缓冲区方法的问题,但我不明白为什么我不能使用双面板方法。任何帮助都非常感谢。例如,我只是使用刷新/Paint事件来绘制,在表单上设置“DoubleBuffered”并重写“CreateParams”,就像其他一些用户建议的那样。
以下是演示该问题的独立程序(注:在本地计算机上设置要显示的图像的正确路径“_image_filename”);如果你创建了一个新的项目,只需要用下面的内容覆盖默认的cs程序。2调整大小的方法是为了防止窗口被调整大小。3谢谢你的帮助。

using System;
using System.Windows.Forms;
using System.Drawing;
using System.IO;

namespace TESTING
{
  
  public class TEST_PROGRAM
  {
    [STAThread]
    static void Main(string[] args)
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      try { Application.Run(new TEST_FORM()); }
      catch { }
    }
  }

  public class TEST_FORM : Form
  {
    // Client area definition.
    private Size _minimum_client_size = new Size(800, 600);
    private Size _client_size_offset;
    // Application font.
    private Font _font;
    // Drawing panels.
    private System.Windows.Forms.Panel _image_panel;
    private System.Windows.Forms.Panel _drag_panel;
    // Image.
    private string _image_filename = "C:\\image.jpg";
    private Bitmap _image_bitmap;
    // Dragging support.
    private Rectangle _drag_selection_area;
    private Point _drag_initial_mouse_location;
    private bool _drag_is_ongoing;

    //===========================================================================
    public TEST_FORM()
    {
      // Start building form.
      this.SuspendLayout();
      this._client_size_offset = this.Size - this.ClientSize;
      this.ClientSize = this._minimum_client_size;
      this.Resize += this._OnResizeHandler;
      this.MaximizeBox = false;
      this.MinimizeBox = true;
      this.Name = "TestForm";
      this.Text = "Test Form";
      this._font = new Font("Arial", 12, FontStyle.Regular);
      this.Font = this._font;
      this.BackColor = System.Drawing.Color.Honeydew;
      this.StartPosition = FormStartPosition.CenterScreen;
      // Enable doublebuffering.
      this.DoubleBuffered = false;
      this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
      this.ResumeLayout(true);
      this.PerformLayout();
      // Add image panel
      this._image_panel = new System.Windows.Forms.Panel();
      if (this._image_panel == null)
        throw new Exception("Unable to create image panel");
      this._image_panel.Left = this.ClientRectangle.X + 4;
      this._image_panel.Top = this.ClientRectangle.Y + 4;
      this._image_panel.Width = this.ClientRectangle.Width - 8;
      this._image_panel.Height = this.ClientRectangle.Height - 8;
      this._image_panel.Font = this.Font;
      this._image_panel.BorderStyle = System.Windows.Forms.BorderStyle.None;
      this._image_panel.Text = "";
      this._image_panel.Paint += this._ImagePanelPaintHandler;
      // Add drag panel.
      this._drag_panel = new System.Windows.Forms.Panel();
      if (this._drag_panel == null)
        throw new Exception("Unable to create drag panel");
      this._drag_panel.Left = this.ClientRectangle.X + 4;
      this._drag_panel.Top = this.ClientRectangle.Y + 4;
      this._drag_panel.Width = this.ClientRectangle.Width - 8;
      this._drag_panel.Height = this.ClientRectangle.Height - 8;
      this._drag_panel.Font = this.Font;
      this._drag_panel.BorderStyle = System.Windows.Forms.BorderStyle.None;
      this._drag_panel.BackColor = System.Drawing.Color.Transparent;
      this._drag_panel.Paint += this._DragPanelPaintHandler;
      this._drag_panel.MouseDown += this._OnMouseDownDragHandler;
      this._drag_panel.MouseMove += this._OnMouseMoveDragHandler;
      this._drag_panel.MouseUp += this._OnMouseUpDragHandler;
      // Add image panel to form.
      this.Controls.Add(this._image_panel);
      this._image_panel.Show();
      // Add drag panel to image panel.
      this._image_panel.Controls.Add(this._drag_panel);
      this._drag_panel.Show();
      // Define image file.
      if (!File.Exists(this._image_filename))
        throw new Exception("Selected image does not exists");
      // Display image.
      this._image_panel.Refresh();
    }
    protected override CreateParams CreateParams
    {
      get
      {
        CreateParams handleParam = base.CreateParams;
        handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED       
        return handleParam;
      }
    }
    private void _ImagePanelPaintHandler(Object source, System.Windows.Forms.PaintEventArgs e)
    {
      if (this._image_bitmap == null)
      {
        // Load image file into bitmap.
        System.Drawing.Image image = Image.FromFile(this._image_filename);
        if (image == null) throw new Exception("Unable to load image");
        double x_ratio = (double)image.Width / (double)this._image_panel.Width;
        double y_ratio = (double)image.Height / (double)this._image_panel.Height;
        double ratio = (x_ratio > y_ratio) ? x_ratio : y_ratio;
        this._image_bitmap = new Bitmap(image,
          new Size((int)((double)image.Width / ratio), (int)((double)image.Height / ratio)));
        if (this._image_bitmap == null) throw new Exception("Unable to create bitmap");
        image.Dispose();
      }
      if (this._image_bitmap != null)
      {
        // Paint bitmap.
        e.Graphics.DrawImage(this._image_bitmap,
          (this._image_panel.ClientRectangle.Width - this._image_bitmap.Width) / 2,
          (this._image_panel.ClientRectangle.Height - this._image_bitmap.Height) / 2,
          this._image_bitmap.Width, this._image_bitmap.Height);
      }
    }
    private void _DragPanelPaintHandler(Object source, System.Windows.Forms.PaintEventArgs e)
    {
      if ((this._drag_selection_area.Width > 0) && (this._drag_selection_area.Height > 0))
      {
        SolidBrush highlight_brush = new SolidBrush(Color.FromArgb(100, 255, 255, 255));
        e.Graphics.FillRectangle(highlight_brush, this._drag_selection_area);
      }
    }
    private void _OnMouseDownDragHandler(object sender, MouseEventArgs e)
    {
      Point mouse_location = new System.Drawing.Point(e.X, e.Y);
      this._drag_selection_area = new Rectangle(e.X, e.Y, 0, 0);
      this._drag_initial_mouse_location = mouse_location;
      this._drag_is_ongoing = true;
      this._drag_panel.Refresh();
    }
    private void _OnMouseMoveDragHandler(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      if (this._drag_is_ongoing)
      {
        Point mouse_location = new System.Drawing.Point(e.X, e.Y);
        this._drag_selection_area.Width = mouse_location.X - this._drag_initial_mouse_location.X;
        this._drag_selection_area.Height = mouse_location.Y - this._drag_initial_mouse_location.Y;
        this._drag_panel.Refresh();
      }
    }
    private void _OnMouseUpDragHandler(object sender, MouseEventArgs e)
    {
      if (this._drag_is_ongoing)
      {
        Point mouse_location = new System.Drawing.Point(e.X, e.Y);
        this._drag_selection_area.Width = mouse_location.X - this._drag_initial_mouse_location.X;
        this._drag_selection_area.Height = mouse_location.Y - this._drag_initial_mouse_location.Y;
        this._drag_panel.Refresh();
        this._drag_is_ongoing = false;
      }
    }
    private void _OnResizeHandler(Object sender, EventArgs e)
    {
      Control control = sender as Control;
      if (control.ClientSize != this._minimum_client_size)
        control.Size = this._minimum_client_size + this._client_size_offset;
    }
    protected override void OnLayout(LayoutEventArgs e)
    {
      base.OnLayout(e);
      this.MinimumSize = this.MinimumClientSize + this._client_size_offset;
    }
    public Size MinimumClientSize
    {
      get { return this._minimum_client_size; }
      set
      {
        this._minimum_client_size = value;
        this.PerformLayout();
      }
    }
  }
}
k3fezbri

k3fezbri1#

派生您自己的面板,并在构造函数中将DoubleBuffer属性设置为true:

public class MyPanel : Panel
{
    public MyPanel()
    {
        DoubleBuffered = true;
    }
}

然后将此面板用于_image_panel和_drag_panel:

this._image_panel = new MyPanel();
// ...
this._drag_panel = new MyPanel();

应该可以了。
然而,你的代码效率很低-你总是重绘整个图像。你应该尽可能避免渲染。首先,用Invalidate()替换Refresh()。然后,计算真正需要重绘的区域(矩形),并用Invalidate(Rectangle)替换Invalidate(),只使它们无效。
您还可以移除CreateParams覆盖和以“this.SetStyle(”开头的行。

相关问题