我正在尝试创建像这样的https://app.prntscr.com/en/index.html这样的剪切工具。我能够修改一些代码,并设法显示调整大小句柄与选定的矩形(剪辑),句柄工作正常,我可以移动选定的矩形并调整大小。但是,当我将它与上面提到的工具进行比较时,它非常慢,有人可以指出我的代码中的一些问题,以使其快速?
/*
* Credit for this portion of Imgur Snipping Tool goes to Hans Passant from stackoverflow.com
* http://stackoverflow.com/questions/3123776/net-equivalent-of-snipping-tool
*
* Modified to work with multiple monitors.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Free_Snipping_Tool.Classes;
namespace Free_Snipping_Tool
{
public partial class SnippingTool2 : Form
{
public enum ScreenshotType
{
FULL, ACTIVE, DEFINED
}
private int oldX;
private int oldY;
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Rectangle topLeft = new Rectangle();
Rectangle topMiddle = new Rectangle();
Rectangle topRight = new Rectangle();
Rectangle bottomLeft = new Rectangle();
Rectangle bottomMiddle = new Rectangle();
Rectangle bottomRight = new Rectangle();
Rectangle leftMiddle = new Rectangle();
Rectangle rightMiddle = new Rectangle();
bool topLeftSelected = false;
bool topMiddleSelected = false;
bool topRightSelected = false;
bool bottomLeftSelected = false;
bool bottomMiddleSelected = false;
bool bottomRightSelected = false;
bool leftMiddleSelected = false;
bool rightMiddleSelected = false;
bool rectangleSelected = false;
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern int GetForegroundWindow();
SnipSizeControl lbl = new SnipSizeControl();
floatingControlRight fcR = new floatingControlRight();
floatingControlBottom fcB = new floatingControlBottom();
public static Image Snip(ScreenshotType type)
{
switch (type)
{
case ScreenshotType.FULL:
return CreateScreenshot(0, 0, SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height);
case ScreenshotType.DEFINED:
SnippingTool2 snipper = new SnippingTool2(CreateScreenshot(0, 0, SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height), new Point(SystemInformation.VirtualScreen.Left, SystemInformation.VirtualScreen.Top));
if (snipper.ShowDialog() == DialogResult.OK)
{
return snipper.Image;
}
break;
case ScreenshotType.ACTIVE:
RECT windowRectangle;
GetWindowRect((System.IntPtr)GetForegroundWindow(), out windowRectangle);
return CreateScreenshot(windowRectangle.Left, windowRectangle.Top, windowRectangle.Right - windowRectangle.Left, windowRectangle.Bottom - windowRectangle.Top);
}
return null;
}
private static Bitmap CreateScreenshot(int left, int top, int width, int height)
{
Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(left, top, 0, 0, new Size(width, height));
g.Dispose();
return bmp;
}
public SnippingTool2(Image screenShot, Point startPos)
{
InitializeComponent();
lbl.Text = "0x0";
lbl.Visible = true;
lbl.BackColor = Color.Black;
lbl.ForeColor = Color.White;
lbl.Visible = false;
this.Controls.Add(lbl);
this.BackgroundImage = screenShot;
Size s = screenShot.Size;
this.ShowInTaskbar = false;
this.FormBorderStyle = FormBorderStyle.None;
this.StartPosition = FormStartPosition.Manual;
this.Size = s;
this.Location = startPos;
this.DoubleBuffered = true;
}
public Image Image { get; set; }
private Rectangle rcSelect = new Rectangle();
private Point pntStart;
bool handleSelected = false;
protected override void OnMouseDown(MouseEventArgs e)
{
if ((e.X > topLeft.X) && (e.X < topLeft.X + topLeft.Width) && (e.Y > topLeft.Y) && (e.Y < topLeft.Y + topLeft.Height))
{
this.Cursor = Cursors.SizeNWSE;
topLeftSelected = true;
handleSelected = true;
}
else if ((e.X > topMiddle.X) && (e.X < topMiddle.X + topMiddle.Width) && (e.Y > topMiddle.Y) && (e.Y < topMiddle.Y + topMiddle.Height))
{
this.Cursor = Cursors.SizeNS;
topMiddleSelected = true;
handleSelected = true;
}
else if ((e.X > topRight.X) && (e.X < topRight.X + topRight.Width) && (e.Y > topRight.Y) && (e.Y < topRight.Y + topRight.Height))
{
this.Cursor = Cursors.SizeNESW;
topRightSelected = true;
handleSelected = true;
}
else if ((e.X > bottomLeft.X) && (e.X < bottomLeft.X + bottomLeft.Width) && (e.Y > bottomLeft.Y) && (e.Y < bottomLeft.Y + bottomLeft.Height))
{
this.Cursor = Cursors.SizeNESW;
bottomLeftSelected = true;
handleSelected = true;
}
else if ((e.X > bottomMiddle.X) && (e.X < bottomMiddle.X + bottomMiddle.Width) && (e.Y > bottomMiddle.Y) && (e.Y < bottomMiddle.Y + bottomMiddle.Height))
{
this.Cursor = Cursors.SizeNS;
bottomMiddleSelected = true;
handleSelected = true;
}
else if ((e.X > bottomRight.X) && (e.X < bottomRight.X + bottomRight.Width) && (e.Y > bottomRight.Y) && (e.Y < bottomRight.Y + bottomRight.Height))
{
this.Cursor = Cursors.SizeNWSE;
bottomRightSelected = true;
handleSelected = true;
}
else if ((e.X > leftMiddle.X) && (e.X < leftMiddle.X + leftMiddle.Width) && (e.Y > leftMiddle.Y) && (e.Y < leftMiddle.Y + leftMiddle.Height))
{
this.Cursor = Cursors.SizeWE;
leftMiddleSelected = true;
handleSelected = true;
}
else if ((e.X > rightMiddle.X) && (e.X < rightMiddle.X + rightMiddle.Width) && (e.Y > rightMiddle.Y) && (e.Y < rightMiddle.Y + rightMiddle.Height))
{
this.Cursor = Cursors.SizeWE;
rightMiddleSelected = true;
handleSelected = true;
}
else if ((e.X > rcSelect.X) && (e.X < rcSelect.X + rcSelect.Width) && (e.Y > rcSelect.Y) && (e.Y < rcSelect.Y + rcSelect.Height))
{
this.Cursor = Cursors.SizeAll;
rectangleSelected = true;
handleSelected = true;
}
else
{
this.Cursor = Cursors.Cross;
topLeftSelected = false;
topMiddleSelected = false;
topRightSelected = false;
bottomLeftSelected = false;
bottomMiddleSelected = false;
bottomRightSelected = false;
leftMiddleSelected = false;
rightMiddleSelected = false;
rectangleSelected = false;
handleSelected = false;
}
// Start the snip on mouse down
if (e.Button != MouseButtons.Left) return;
if (handleSelected == true) return;
pntStart = e.Location;
rcSelect = new Rectangle(e.Location, new Size(0, 0));
lbl.Visible = true;
lbl.Location = new Point(e.X + 10, e.Y + 10); ;
lbl.Value = string.Format("0x0");
lbl.Refresh();
fcR.Visible = false;
oldX = e.X;
oldY = e.Y;
this.Refresh();
}
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
// Modify the selection on mouse move
if ((e.X > topLeft.X) && (e.X < topLeft.X + topLeft.Width) && (e.Y > topLeft.Y) && (e.Y < topLeft.Y + topLeft.Height))
{
this.Cursor = Cursors.SizeNWSE;
}
else if ((e.X > topMiddle.X) && (e.X < topMiddle.X + topMiddle.Width) && (e.Y > topMiddle.Y) && (e.Y < topMiddle.Y + topMiddle.Height))
{
this.Cursor = Cursors.SizeNS;
}
else if ((e.X > topRight.X) && (e.X < topRight.X + topRight.Width) && (e.Y > topRight.Y) && (e.Y < topRight.Y + topRight.Height))
{
this.Cursor = Cursors.SizeNESW;
}
else if ((e.X > bottomLeft.X) && (e.X < bottomLeft.X + bottomLeft.Width) && (e.Y > bottomLeft.Y) && (e.Y < bottomLeft.Y + bottomLeft.Height))
{
this.Cursor = Cursors.SizeNESW;
}
else if ((e.X > bottomMiddle.X) && (e.X < bottomMiddle.X + bottomMiddle.Width) && (e.Y > bottomMiddle.Y) && (e.Y < bottomMiddle.Y + bottomMiddle.Height))
{
this.Cursor = Cursors.SizeNS;
}
else if ((e.X > bottomRight.X) && (e.X < bottomRight.X + bottomRight.Width) && (e.Y > bottomRight.Y) && (e.Y < bottomRight.Y + bottomRight.Height))
{
this.Cursor = Cursors.SizeNWSE;
}
else if ((e.X > leftMiddle.X) && (e.X < leftMiddle.X + leftMiddle.Width) && (e.Y > leftMiddle.Y) && (e.Y < leftMiddle.Y + leftMiddle.Height))
{
this.Cursor = Cursors.SizeWE;
}
else if ((e.X > rightMiddle.X) && (e.X < rightMiddle.X + rightMiddle.Width) && (e.Y > rightMiddle.Y) && (e.Y < rightMiddle.Y + rightMiddle.Height))
{
this.Cursor = Cursors.SizeWE;
}
else if ((e.X > rcSelect.X) && (e.X < rcSelect.X + rcSelect.Width) && (e.Y > rcSelect.Y) && (e.Y < rcSelect.Y + rcSelect.Height))
{
this.Cursor = Cursors.SizeAll;
}
else
{
this.Cursor = Cursors.Cross;
}
if (e.Button == MouseButtons.Left && handleSelected == true)
{
Rectangle backupRect = rcSelect;
if (topLeftSelected == true)
{
rcSelect.X += e.X - oldX;
rcSelect.Width -= e.X - oldX;
rcSelect.Y += e.Y - oldY;
rcSelect.Height -= e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (topRightSelected == true)
{
rcSelect.Width += e.X - oldX;
rcSelect.Y += e.Y - oldY;
rcSelect.Height -= e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (topMiddleSelected == true)
{
rcSelect.Y += e.Y - oldY;
rcSelect.Height -= e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (bottomLeftSelected == true)
{
rcSelect.Width -= e.X - oldX;
rcSelect.X += e.X - oldX;
rcSelect.Height += e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (bottomMiddleSelected == true)
{
rcSelect.Height += e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (bottomRightSelected == true)
{
rcSelect.Width += e.X - oldX;
rcSelect.Height += e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (rightMiddleSelected == true)
{
rcSelect.Width += e.X - oldX;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (leftMiddleSelected == true)
{
rcSelect.X += e.X - oldX;
rcSelect.Width -= e.X - oldX;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
else if (rectangleSelected == true)
{
rcSelect.X = rcSelect.X + e.X - oldX;
rcSelect.Y = rcSelect.Y + e.Y - oldY;
lbl.Location = new Point(rcSelect.X, rcSelect.Y - 25);
lbl.Value = string.Format("{0}x{1}", rcSelect.Width, rcSelect.Height);
this.Refresh();
}
}
else if (e.Button == MouseButtons.Left)
{
int x1 = Math.Min(e.X, pntStart.X);
int y1 = Math.Min(e.Y, pntStart.Y);
int x2 = Math.Max(e.X, pntStart.X);
int y2 = Math.Max(e.Y, pntStart.Y);
rcSelect = new Rectangle(x1, y1, x2 - x1, y2 - y1);
this.Refresh();
lbl.Location = new Point(x1, y1 - 25);
lbl.Value = string.Format("{0}x{1}", x2 - x1, y2 - y1);
lbl.Refresh();
}
oldX = e.X;
oldY = e.Y;
}
protected override void OnMouseUp(MouseEventArgs e)
{
// Complete the snip on mouse-up
if (rcSelect.Width <= 0 || rcSelect.Height <= 0) return;
Image = new Bitmap(rcSelect.Width, rcSelect.Height);
using (Graphics gr = Graphics.FromImage(Image))
{
gr.DrawImage(this.BackgroundImage, new Rectangle(0, 0, Image.Width, Image.Height),
rcSelect, GraphicsUnit.Pixel);
}
topLeftSelected = false;
topMiddleSelected = false;
topRightSelected = false;
bottomLeftSelected = false;
bottomMiddleSelected = false;
bottomRightSelected = false;
leftMiddleSelected = false;
rightMiddleSelected = false;
rectangleSelected = false;
handleSelected = false;
//DialogResult = DialogResult.OK;
}
protected override void OnPaint(PaintEventArgs e)
{
// Draw the current selection
using (Brush br = new SolidBrush(Color.FromArgb(30, Color.Black)))
{
int x1 = rcSelect.X; int x2 = rcSelect.X + rcSelect.Width;
int y1 = rcSelect.Y; int y2 = rcSelect.Y + rcSelect.Height;
e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, this.Height));
e.Graphics.FillRectangle(br, new Rectangle(x2, 0, this.Width - x2, this.Height));
e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1));
e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, this.Height - y2));
}
using (Pen pen = new Pen(Color.Red, 1))
{
e.Graphics.DrawRectangle(pen, rcSelect);
}
//Resize Controls
//Top left
topLeft = new Rectangle(rcSelect.X - 3, rcSelect.Y - 3, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, topLeft);
}
//Top middle
topMiddle = new Rectangle((rcSelect.X - 3) + (rcSelect.Width) / 2, rcSelect.Y - 3, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, topMiddle);
}
//Top right
topRight = new Rectangle((rcSelect.X - 3) + rcSelect.Width, rcSelect.Y - 3, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, topRight);
}
//Bottom left
bottomLeft = new Rectangle(rcSelect.X - 3, (rcSelect.Y - 3) + rcSelect.Height, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, bottomLeft);
}
//Bottom middle
bottomMiddle = new Rectangle((rcSelect.X - 3) + (rcSelect.Width) / 2, (rcSelect.Y - 3) + rcSelect.Height, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, bottomMiddle);
}
//Bottom right
bottomRight = new Rectangle((rcSelect.X - 3) + rcSelect.Width, (rcSelect.Y - 3) + rcSelect.Height, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, bottomRight);
}
//Left middle
leftMiddle = new Rectangle(rcSelect.X - 3, (rcSelect.Y - 3) + (rcSelect.Height) / 2, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, leftMiddle);
}
//Right middle
rightMiddle = new Rectangle((rcSelect.X - 3) + rcSelect.Width, (rcSelect.Y - 3) + (rcSelect.Height) / 2, 6, 6);
using (Brush br = new SolidBrush(Color.FromArgb(200, Color.Red)))
{
e.Graphics.FillRectangle(br, rightMiddle);
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
// Allow canceling the snip with the Escape key
if (keyData == Keys.Escape) this.DialogResult = DialogResult.Cancel;
return base.ProcessCmdKey(ref msg, keyData);
}
}
}
修改 项目文件:https://www.dropbox.com/s/k1afggj6inye4kp/Free%20Snipipng%20Tool-project.rar?dl=0
答案 0 :(得分:1)
我会引用官方Windows documentation。尽管该文档是关于Native API的,但Winforms使用相同的基础技术:
应用程序使窗口的一部分无效并设置更新 使用InvalidateRect或InvalidateRgn函数的区域。这些 函数将指定的矩形或区域添加到更新区域, 将矩形或区域与系统或任何系统相结合 应用程序可能先前已添加到更新区域。
不会生成InvalidateRect和InvalidateRgn函数 WM_PAINT消息。相反,系统会累积所做的更改 这些功能和它自己的变化。通过累积变化,一个窗口 一次处理所有更改,而不是更新一点一点 一步一步。
调用.NET Refresh()
相当于调用InvalidateAll()
+ Update()
。 InvalidateAll
将整个屏幕标记为无效,Update()
强制重绘其无效的过程,因此整个屏幕都是如此。
如果您只是手动&#34;无效,您可以优化您的程序。你所知道的已经改变了。
这就是我在修改过的样本中所做的。我没有调用Refresh(),而是添加了一个新的oldRcRect
变量,以便能够使旧的状态和新状态无效,以及像这样的RefreshOnMove()方法(我通过RefreshOnMove调用替换了大多数Refresh调用): / p>
private void RefreshOnMove()
{
// invalidate the old rect (+ size of red box)
var rc = oldRcSelect;
rc.Inflate(3, 3);
Invalidate(rc);
// invalidate the new rect (+ size of red box)
// note you can almost omit this second one, but if you move the mouse really fast, you'll see some red box not fully displayed
// but the benefit is small, something like a 3 x width/height rectangle
rc = rcSelect;
rc.Inflate(3, 3);
Invalidate(rc);
// each time you call invalidate, you just accumulate a change
// to the change region, nothing actually changes on the screen
// now, ask Windows to process the combination of changes
Update();
}
PS:关于我对内部区域的评论,我只是说每次都可以避免使白盒内容无效,但它更复杂。