在表格外使用放大镜
Using Magnifying Glass Outside the Form
下午好!有一个表格(镜头),用作放大镜(在表格内部)。我需要摆脱 TargetForm 属性 以便表单(Lens)作为一个独立的控件在不绑定到表单的情况下工作。用什么代码代替,请告诉我。
Main_Form
的代码
private void button1_Click(object sender, EventArgs e) {
new Lens_Form() { TargetForm = this }.Show(this);
Cursor.Hide();
}
Lens_Form
的代码
public partial class Lens_Form : Form {
public Form TargetForm { get; set; }
public new float Scale { get; set; }
private Bitmap tmpBmp;
public Lens_Form() {
InitializeComponent();
// Drawing the Ellipse
GraphicsPath path = new GraphicsPath();
path.AddEllipse(ClientRectangle);
Region = new Region(path);
// Set Scale
Scale = 2; // 2-4-6-8
}
protected override void OnPaint(PaintEventArgs e) {
Point pos = TargetForm.PointToClient(Cursor.Position);
Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2);
Rectangle screenRectangle = TargetForm.RectangleToScreen(TargetForm.ClientRectangle);
int dY = screenRectangle.Top - TargetForm.Top;
int dX = screenRectangle.Left - TargetForm.Left;
e.Graphics.TranslateTransform(Width / 2, Height / 2);
e.Graphics.ScaleTransform(Scale, Scale);
e.Graphics.TranslateTransform(-pos.X - dX, -pos.Y - dY);
if (tmpBmp != null) e.Graphics.DrawImage(tmpBmp, 0, 0);
}
// Timer
private void Main_Timer_Tick(object sender, EventArgs e) {
tmpBmp = new Bitmap(TargetForm.Size.Width, TargetForm.Size.Height);
TargetForm.DrawToBitmap(tmpBmp, new Rectangle(0, 0, TargetForm.Width, TargetForm.Height));
Invalidate();
}
}
您需要按比例放大并使用更大的边界,屏幕的边界而不是表单的边界。通过 Graphics.CopyFromScreen
方法捕获屏幕而不是表单。
这是一个使用相同方法的一些附加功能的工作示例。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Lens_Form : Form
{
private readonly Timer timer;
private Bitmap scrBmp;
private Graphics scrGrp;
private bool mouseDown;
public Lens_Form() : base()
{
SetStyle(
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.Opaque |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);
UpdateStyles();
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
TopMost = true;
Width = 150;
Height = 150;
timer = new Timer() { Interval = 55, Enabled = true };
timer.Tick += (s, e) => Invalidate();
}
public int ZoomFactor { get; set; } = 2;
public bool HideCursor { get; set; } = true;
public bool AutoClose { get; set; } = true;
public bool NearestNeighborInterpolation { get; set; }
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var gp = new GraphicsPath();
gp.AddEllipse(0, 0, Width, Height);
Region = new Region(gp);
CopyScreen();
SetLocation();
Capture = true;
mouseDown = true;
if (HideCursor) Cursor.Hide();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
if (HideCursor) Cursor.Hide();
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
mouseDown = false;
if (HideCursor) Cursor.Show();
if (AutoClose) Dispose();
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Escape) Dispose();
}
protected override void OnPaint(PaintEventArgs e)
{
if (mouseDown) SetLocation();
else CopyScreen();
var pos = Cursor.Position;
var cr = RectangleToScreen(ClientRectangle);
var dY = cr.Top - Top;
var dX = cr.Left - Left;
e.Graphics.TranslateTransform(Width / 2, Height / 2);
e.Graphics.ScaleTransform(ZoomFactor, ZoomFactor);
e.Graphics.TranslateTransform(-pos.X - dX, -pos.Y - dY);
e.Graphics.Clear(BackColor);
if (NearestNeighborInterpolation)
{
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
}
if (scrBmp != null) e.Graphics.DrawImage(scrBmp, 0, 0);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
timer.Dispose();
scrBmp?.Dispose();
scrGrp?.Dispose();
}
base.Dispose(disposing);
}
private void CopyScreen()
{
if (scrBmp == null)
{
var sz = Screen.FromControl(this).Bounds.Size;
scrBmp = new Bitmap(sz.Width, sz.Height);
scrGrp = Graphics.FromImage(scrBmp);
}
scrGrp.CopyFromScreen(Point.Empty, Point.Empty, scrBmp.Size);
}
private void SetLocation()
{
var p = Cursor.Position;
Left = p.X - Width / 2;
Top = p.Y - Height / 2;
}
}
主窗体中的调用者:
private void SomeButton_MouseDown(object sender, MouseEventArgs e)
{
var f = new Lens_Form()
{
Size = new Size(150, 150),
AutoClose = true,
HideCursor = true,
ZoomFactor = 2,
NearestNeighborInterpolation = false
};
f.Show();
}
备注
在构造函数中调用SetStyle
方法,将此上下文中的一些有用的样式应用到控件中。接管绘制程序,减少闪烁,防止绘制背景。
重写OnShown
方法获取调用方设置的大小并设置区域,截图,设置Form位置
覆盖鼠标方法以应用属性并刷新视图。
覆盖 OnPaint
方法以在按下鼠标左键时移动窗体,否则重新复制屏幕。这是为您提供两个选项,如果您禁用 AutoClose
属性,则在拖动表单时放大或在不按下任何按钮的情况下移动鼠标时放大。对于转换部分,使用当前Cursor.Position
和Form的屏幕坐标(而不是主要的From)来做数学运算。
- 最后,覆盖
Dispose
方法进行清理。
演示
下午好!有一个表格(镜头),用作放大镜(在表格内部)。我需要摆脱 TargetForm 属性 以便表单(Lens)作为一个独立的控件在不绑定到表单的情况下工作。用什么代码代替,请告诉我。
Main_Form
的代码private void button1_Click(object sender, EventArgs e) {
new Lens_Form() { TargetForm = this }.Show(this);
Cursor.Hide();
}
Lens_Form
的代码public partial class Lens_Form : Form {
public Form TargetForm { get; set; }
public new float Scale { get; set; }
private Bitmap tmpBmp;
public Lens_Form() {
InitializeComponent();
// Drawing the Ellipse
GraphicsPath path = new GraphicsPath();
path.AddEllipse(ClientRectangle);
Region = new Region(path);
// Set Scale
Scale = 2; // 2-4-6-8
}
protected override void OnPaint(PaintEventArgs e) {
Point pos = TargetForm.PointToClient(Cursor.Position);
Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2);
Rectangle screenRectangle = TargetForm.RectangleToScreen(TargetForm.ClientRectangle);
int dY = screenRectangle.Top - TargetForm.Top;
int dX = screenRectangle.Left - TargetForm.Left;
e.Graphics.TranslateTransform(Width / 2, Height / 2);
e.Graphics.ScaleTransform(Scale, Scale);
e.Graphics.TranslateTransform(-pos.X - dX, -pos.Y - dY);
if (tmpBmp != null) e.Graphics.DrawImage(tmpBmp, 0, 0);
}
// Timer
private void Main_Timer_Tick(object sender, EventArgs e) {
tmpBmp = new Bitmap(TargetForm.Size.Width, TargetForm.Size.Height);
TargetForm.DrawToBitmap(tmpBmp, new Rectangle(0, 0, TargetForm.Width, TargetForm.Height));
Invalidate();
}
}
您需要按比例放大并使用更大的边界,屏幕的边界而不是表单的边界。通过 Graphics.CopyFromScreen
方法捕获屏幕而不是表单。
这是一个使用相同方法的一些附加功能的工作示例。
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Lens_Form : Form
{
private readonly Timer timer;
private Bitmap scrBmp;
private Graphics scrGrp;
private bool mouseDown;
public Lens_Form() : base()
{
SetStyle(
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.Opaque |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);
UpdateStyles();
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
TopMost = true;
Width = 150;
Height = 150;
timer = new Timer() { Interval = 55, Enabled = true };
timer.Tick += (s, e) => Invalidate();
}
public int ZoomFactor { get; set; } = 2;
public bool HideCursor { get; set; } = true;
public bool AutoClose { get; set; } = true;
public bool NearestNeighborInterpolation { get; set; }
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var gp = new GraphicsPath();
gp.AddEllipse(0, 0, Width, Height);
Region = new Region(gp);
CopyScreen();
SetLocation();
Capture = true;
mouseDown = true;
if (HideCursor) Cursor.Hide();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
if (HideCursor) Cursor.Hide();
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
mouseDown = false;
if (HideCursor) Cursor.Show();
if (AutoClose) Dispose();
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Escape) Dispose();
}
protected override void OnPaint(PaintEventArgs e)
{
if (mouseDown) SetLocation();
else CopyScreen();
var pos = Cursor.Position;
var cr = RectangleToScreen(ClientRectangle);
var dY = cr.Top - Top;
var dX = cr.Left - Left;
e.Graphics.TranslateTransform(Width / 2, Height / 2);
e.Graphics.ScaleTransform(ZoomFactor, ZoomFactor);
e.Graphics.TranslateTransform(-pos.X - dX, -pos.Y - dY);
e.Graphics.Clear(BackColor);
if (NearestNeighborInterpolation)
{
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
}
if (scrBmp != null) e.Graphics.DrawImage(scrBmp, 0, 0);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
timer.Dispose();
scrBmp?.Dispose();
scrGrp?.Dispose();
}
base.Dispose(disposing);
}
private void CopyScreen()
{
if (scrBmp == null)
{
var sz = Screen.FromControl(this).Bounds.Size;
scrBmp = new Bitmap(sz.Width, sz.Height);
scrGrp = Graphics.FromImage(scrBmp);
}
scrGrp.CopyFromScreen(Point.Empty, Point.Empty, scrBmp.Size);
}
private void SetLocation()
{
var p = Cursor.Position;
Left = p.X - Width / 2;
Top = p.Y - Height / 2;
}
}
主窗体中的调用者:
private void SomeButton_MouseDown(object sender, MouseEventArgs e)
{
var f = new Lens_Form()
{
Size = new Size(150, 150),
AutoClose = true,
HideCursor = true,
ZoomFactor = 2,
NearestNeighborInterpolation = false
};
f.Show();
}
备注
在构造函数中调用
SetStyle
方法,将此上下文中的一些有用的样式应用到控件中。接管绘制程序,减少闪烁,防止绘制背景。重写
OnShown
方法获取调用方设置的大小并设置区域,截图,设置Form位置覆盖鼠标方法以应用属性并刷新视图。
覆盖
OnPaint
方法以在按下鼠标左键时移动窗体,否则重新复制屏幕。这是为您提供两个选项,如果您禁用AutoClose
属性,则在拖动表单时放大或在不按下任何按钮的情况下移动鼠标时放大。对于转换部分,使用当前Cursor.Position
和Form的屏幕坐标(而不是主要的From)来做数学运算。
- 最后,覆盖
Dispose
方法进行清理。
演示