Reputation: 105
Good afternoon! There is a form (Lens), which serves as a magnifying glass (inside the form). I need to get rid of the TargetForm property so that the form (Lens) works without binding to the form, as an independent control. What code to replace it with, please tell me.
Code For Main_Form
private void button1_Click(object sender, EventArgs e) {
new Lens_Form() { TargetForm = this }.Show(this);
Cursor.Hide();
}
Code For 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();
}
}
Upvotes: 1
Views: 1335
Reputation: 4695
You need to scale up and work with bigger boundaries, the screen's instead of the Form's. Capture the screen instead of the Form by the Graphics.CopyFromScreen
method.
Here's a working example with some extras using the same approach.
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;
}
}
A caller in the main Form:
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();
}
Notes
The SetStyle
method is called in the constructor to apply some useful styles in this context to the control. To takeover the painting routine, reduce the flickering, and prevent painting the background.
Override the OnShown
method to get the size set by the caller and set the region, take a screenshot, and set the Form's location.
Override the mouse methods to apply the properties and refresh the view.
Override the OnPaint
method to move the Form while the mouse left button is pressed otherwise recopy the screen. This is to give you two options, magnifying while dragging the Form or while moving the mouse with no buttons pressed if you disable the AutoClose
property. For the transformation part, use the current Cursor.Position
and the screen coordinates of the Form (instead of the main From) to do the math.
Dispose
method to clean up.Demo
Upvotes: 1