C#使用OnMouseMove中的froms OnPaint方法绘制图形时出现大延迟



我的目标是在表单上绘制一张图像(屏幕截图(,并使用橡皮筋矩形突出显示所选区域。我希望图像变得更暗,选择的区域是正常的
我试图通过使用鼠标事件获得用户选择的区域,在表单上绘制图像,然后使用一个区域(用于变暗/高亮效果(在图像上绘制不透明的黑色覆盖层来实现这一点,除了使用以下代码选择的区域:

class ExampleForm : Form {
private Bitmap screenshot;
private Rectangle r;
private Region reg;
private SolidBrush brush;
public ExampleForm() {
r = Screen.PrimaryScreen.Bounds;
screenshot = new Bitmap(r.Width, r.Height);
Graphics.FromImage(screenshot).CopyFromScreen(r.Left, r.Top, 0, 0, r.Size);
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
TopMost = true;
DoubleBuffered = true;
ShowInTaskbar = false;
reg = new Region(r);
brush = new SolidBrush(Color.FromArgb(200, Color.Black));
}
private Point startDrag, endDrag;
private bool mouseDown;
protected override void OnMouseDown(MouseEventArgs e) {
mouseDown = true;
startDrag = e.Location;
}
protected override void OnMouseUp(MouseEventArgs e) {
mouseDown = false;
}
protected override void OnMouseMove(MouseEventArgs e) {
if (!mouseDown) return;
endDrag = e.Location;
UpdatePaint();
}
private void UpdatePaint() {
Rectangle window = new Rectangle(
Math.Min(startDrag.X, endDrag.X),
Math.Min(startDrag.Y, endDrag.Y),
Math.Abs(startDrag.X - endDrag.X),
Math.Abs(startDrag.Y - endDrag.Y)
);
reg = new Region(ClientRectangle);
reg.Xor(window);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
Graphics g = e.Graphics;
g.DrawImage(screenshot, r);
g.FillRegion(brush, reg);
}
}

然而,当这样做时,在我移动鼠标和";突出显示";区域更新到鼠标位置
我尝试过在没有图像的情况下进行区域高亮显示,甚至只是在没有图像和区域的情况下绘制一个矩形,而且延迟较小,但是,与windows资源管理器高亮显示或亮显(这是我试图重新创建的功能(相比,移动鼠标和表单中显示的内容之间仍然有更多的延迟。
我甚至尝试使用了两种形式:一种用于图像,另一种用于暗显/高亮效果,这样图像就不必重新绘制每次,但无法使窗体透明,同时在顶部绘制不透明的颜色
我也尝试过OnPaintBackground,使用标签或图像框,但都有相同的延迟。

那么,有没有更有效的方法来绘制和/或突出显示我使用的效果呢?

在Taw的评论基础上,我们将Form的BackgroundImage设置为屏幕截图的深色版本,并且我们只在当前选择所在的OnPaint()中绘制原始版本("浅色"版本,而不是真正的(。我还将代码简化为完成任务所需的最低限度:

public partial class ExampleForm : Form
{
private Point startDrag;
private SolidBrush brush;
private Rectangle selectionRc;
private Bitmap originalScreenShot;
public ExampleForm()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.TopMost = true;
this.DoubleBuffered = true;
this.ShowInTaskbar = false;
this.brush = new SolidBrush(Color.FromArgb(200, Color.Black));
Rectangle screenRc = Screen.PrimaryScreen.Bounds;
this.originalScreenShot = new Bitmap(screenRc.Width, screenRc.Height);
using (Graphics G = Graphics.FromImage(this.originalScreenShot))
{
G.CopyFromScreen(screenRc.Left, screenRc.Top, 0, 0, screenRc.Size);
}
Bitmap darkenedScreenshot = new Bitmap(this.originalScreenShot);
using (Graphics G = Graphics.FromImage(darkenedScreenshot))
{
G.FillRectangle(this.brush, screenRc);
}
this.BackgroundImageLayout = ImageLayout.None;
this.BackgroundImage = darkenedScreenshot;                       
}        
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.startDrag = e.Location;
}            
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// ... do something with "selectionRc" in here? ...
}            
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.selectionRc = new Rectangle(
Math.Min(this.startDrag.X, e.Location.X),
Math.Min(this.startDrag.Y, e.Location.Y),
Math.Abs(this.startDrag.X - e.Location.X),
Math.Abs(this.startDrag.Y - e.Location.Y)
);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawImage(this.originalScreenShot, this.selectionRc, this.selectionRc, GraphicsUnit.Pixel);
}
}

最新更新