1.效果展示
2 自定义翻页控件
public partial class PageManagemen : UserControl
{
/// <summary>
/// 当前页(从1开始计数)
/// </summary>
private int _currentPage = 1;
/// <summary>
/// 总数
/// </summary>
private static int _dataSum;
/// <summary>
///设置总数
/// </summary>
/// <param name="dataSum">总数</param>
public void SetDataSum(int dataSum)
{
_dataSum = dataSum;
btn_Click(null, null);
comboBox1.Items.Clear();
for (int i = 0; i < dataSum; i++)
{
comboBox1.Items.Add((i + 1).ToString());
}
comboBox1.SelectedIndex = _currentPage - 1;
}
public PageManagemen()
{
InitializeComponent();
}
//点击事件
public void btn_Click(object sender, EventArgs e)
{
try
{
Button btn = (Button)sender;
if (btn == btn_First)
{
_currentPage = 1;
}
else if (btn == btn_Up)
{
--_currentPage;
if (_currentPage < 1)
{
_currentPage = _dataSum;
}
}
else if (btn == btn_Down)
{
_currentPage = (_currentPage + 1) % _dataSum;
if (_currentPage == 0)
{
_currentPage = _dataSum;
}
}
else if (btn == btn_Last)
{
_currentPage = _dataSum;
}
lbl_info.Text = $"第{_currentPage}页,共{_dataSum}页";
comboBox1.SelectedIndex = _currentPage - 1;
Form1.CurrentPage = _currentPage;
}
catch (Exception)
{
}
}
}
3 主界面事件
/// <summary>
/// 声明委托,用于监控当前页变量
/// </summary>
delegate void CurrentPageDelegate();
public partial class Form1 : Form
{
/// <summary>
/// 指令目录的根目录下所有图片路径
/// </summary>
private List<string> _lstPath;
/// <summary>
/// 存储当前显示图像
/// </summary>
private Bitmap _bitmap;
/// <summary>
/// 当前显示图像的索引
/// </summary>
private static int _currentPage;
/// <summary>
/// 利用属性执行委托
/// </summary>
public static int CurrentPage
{
set
{
_currentPage = value - 1;
CurrentPageEvent?.Invoke();
}
}
/// <summary>
/// 记录鼠标移动时的位置
/// </summary>
private Point _mouseDown, _mouseLocation;
/// <summary>
/// 是否允许绘制管理
/// </summary>
private bool _banDraw = true;
/// <summary>
/// 绘图类型
/// </summary>
private DrawTool.DrawType _drawType;
/// <summary>
/// 存放猫猫的窝
/// </summary>
private readonly string _catDirectory = Application.StartupPath + @"\Cat";
/// <summary>
/// 定义委托
/// </summary>
private static event CurrentPageDelegate CurrentPageEvent;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
CurrentPageEvent += UpdataImage;//添加委托事件
var ret = DrawTool.DicDrawType.Keys;
foreach (var s in ret)
{
comboBox1.Items.Add(s);
}
comboBox1.SelectedIndex = 0;
//搭建猫窝
if (!Directory.Exists(_catDirectory))
{
Directory.CreateDirectory(_catDirectory);
}
GetFilesByDirectory();
}
catch (Exception)
{
}
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
pic_1.Refresh();
}
public void UpdataImage()
{
try
{
_bitmap?.Dispose();
pic_1.Focus();
_bitmap = (Bitmap)Image.FromFile(_lstPath[_currentPage], false);
pic_1.Image = _bitmap;
pic_1.Refresh();
}
catch (Exception)
{
}
}
/// <summary>
/// 获取文件信息,并设置相关参数
/// </summary>
private void GetFilesByDirectory()
{
try
{
var extension = new[] { "png", "jpg", "JPEG", "BMP" };
var di = new DirectoryInfo(_catDirectory);
const string start = "*";
var lst = extension.Select(s => start + s).ToList();
var fileInfos = lst.SelectMany(i => di.GetFiles(i.ToLower(), SearchOption.TopDirectoryOnly)).Distinct().ToArray();
_lstPath = fileInfos.Select(fileInfo => fileInfo.FullName).ToList();
page.SetDataSum(fileInfos.Length);
if (_lstPath.Count > 0)
{
_bitmap = null;//释放当前图像,以便加载新图像
_bitmap = (Bitmap)Image.FromFile(_lstPath[_currentPage], false);
}
}
catch (Exception)
{
}
}
#region [PictureBox事件管理]
//绘制类型选择
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
_drawType = DrawTool.DicDrawType[comboBox1.Text];
pic_1.Refresh();
}
//切换图像(在pictureBox鼠标移动事件中设置焦点)
private void pic_1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
switch ((Keys)e.KeyValue)
{
case Keys.Up:
case Keys.Left:
case Keys.W:
case Keys.A:
page.btn_Click(page.btn_Up, null);
break;
case Keys.Down:
case Keys.Right:
case Keys.S:
case Keys.D:
page.btn_Click(page.btn_Down, null);
break;
case Keys.End:
page.btn_Click(page.btn_Last, null);
break;
case Keys.Home:
page.btn_Click(page.btn_First, null);
break;
}
}
//鼠标按下开启绘图
private void pic_1_MouseDown(object sender, MouseEventArgs e)
{
if (MouseButtons.Left != e.Button) return;
_banDraw = false;
_mouseDown = e.Location;
}
//鼠标按下停止绘图
private void pic_1_MouseUp(object sender, MouseEventArgs e)
{
if (MouseButtons.Left != e.Button) return;
_banDraw = true;
}
//鼠标移动事件
private void pic_MouseMove(object sender, MouseEventArgs e)
{
try
{
pic_1.Focus();
if (_banDraw) return;
_mouseLocation = e.Location;
pic_1.Refresh();
}
catch (Exception)
{
}
}
//绘图事件
private void pic_Paint(object sender, PaintEventArgs e)
{
try
{
var pic = (PictureBox)sender;
e.Graphics.Clear(Color.SkyBlue);//清除整个绘图面并以指定背景色填充
ref int magnify = 0;
DrawTool.DrawImage(e.Graphics, _bitmap, ref magnify, pic.Size);
if (_mouseDown.X == 0) return;
switch (_drawType)
{
case DrawTool.DrawType.Rect:
DrawTool.DrawRect(e.Graphics, _mouseDown, _mouseLocation);
break;
case DrawTool.DrawType.Line:
DrawTool.DrawLine(e.Graphics, _mouseDown, _mouseLocation);
break;
case DrawTool.DrawType.Cross:
DrawTool.DrawCross(e.Graphics, _mouseLocation, pic.Size);
break;
case DrawTool.DrawType.EquicruralTriangle:
DrawTool.DrawEquicruralTriangle(e.Graphics, _mouseDown, _mouseLocation);
break;
case DrawTool.DrawType.RhombusUpToDown:
DrawTool.DrawRhombusUpToDown(e.Graphics, _mouseDown, _mouseLocation);
break;
case DrawTool.DrawType.RhombusLeftToRight:
DrawTool.DrawRhombusLeftToRight(e.Graphics, _mouseDown, _mouseLocation);
break;
case DrawTool.DrawType.Circle:
DrawTool.DrawCircle(e.Graphics, _mouseDown, _mouseLocation);
break;
}
}
catch (Exception)
{
}
}
#endregion
//捉猫猫
private void button1_Click(object sender, EventArgs e)
{
var dialog = new OpenFileDialog
{
Filter = "|*.png;*.jpg;*.JPEG;*.BMP",
Multiselect = true
};
if (dialog.ShowDialog() == DialogResult.OK)
{
int num = 0;
foreach (var filename in dialog.FileNames)
{
string path = _catDirectory + @"\" + Path.GetFileName(filename);
if (File.Exists(path)) continue;
num++;
File.Copy(filename, path, true);
}
MessageBox.Show($"恭喜您,已经捉住了{num}只猫猫。", "提示");
}
dialog.Dispose();
GetFilesByDirectory();
}
//放猫猫
private void button2_Click(object sender, EventArgs e)
{
try
{
var dialog = new OpenFileDialog
{
Filter = "|*.png;*.jpg;*.JPEG;*.BMP",
Multiselect = false,
InitialDirectory = _catDirectory
};
if (dialog.ShowDialog() == DialogResult.OK)
{
string path = dialog.FileName;
dialog.Dispose();
if (Path.GetDirectoryName(path) != _catDirectory)
return;
_bitmap?.Dispose();
File.Delete(path);
GetFilesByDirectory();
MessageBox.Show("恭喜您,已经放生了一只猫猫。", "提示");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
MessageBox.Show("猫猫被禁闭无法释放,试试放别的猫猫。", "提示");
}
}
}
4 绘制工具类
public class DrawTool
{
public static Dictionary<string, DrawType> DicDrawType;
public enum DrawType
{
Null,
/// <summary>
/// 清除整个绘图面并以指定背景色填充
/// </summary>
Clear,
/// <summary>
/// 绘制图像
/// </summary>
Image,
/// <summary>
/// 矩形
/// </summary>
Rect,
/// <summary>
/// 线段
/// </summary>
Line,
/// <summary>
/// 十字
/// </summary>
Cross,
/// <summary>
/// 等腰三角形
/// </summary>
EquicruralTriangle,
/// <summary>
/// 菱形
/// </summary>
Rhombus,
/// <summary>
/// 空心圆
/// </summary>
HollowCircle,
/// <summary>
/// 实心圆
/// </summary>
SolidCircle,
/// <summary>
/// 文字
/// </summary>
String,
}
static DrawTool()
{
DicDrawType = new Dictionary<string, DrawType>
{
{"矩形",DrawType.Rect},
{"线段",DrawType.Line},
{"十字",DrawType.Cross},
{"等腰三角形",DrawType.EquicruralTriangle},
{"菱形",DrawType.Rhombus},
{"空心圆",DrawType.HollowCircle},
{"实心圆",DrawType.SolidCircle},
{"文字",DrawType.String},
};
}
/// <summary>
/// 清除整个绘图面并以指定背景色填充
/// </summary>
/// <param name="e"></param>
public static void DrawClear(Graphics e)
{
e.Clear(Color.SkyBlue);
}
/// <summary>
/// 绘制图像
/// </summary>
/// <param name="e">绘画类</param>
/// <param name="bmp">图像</param>
/// <param name="magnify">图像放大倍率</param>
/// <param name="size">承载图像的父控件大小</param>
public static void DrawImage(Graphics e, Bitmap bmp, ref int magnify, Size size)
{
var rectBmpPos = new Rectangle();//获取图像显示的位置和宽、高信息
//父控件大小 和Bitmap 的宽高比
var picByBmpScale = Math.Min((float)size.Width / bmp.Width, (float)size.Height / bmp.Height);
rectBmpPos.Width = (int)(bmp.Width * picByBmpScale);
rectBmpPos.Height = (int)(bmp.Height * picByBmpScale);
rectBmpPos.X = (size.Width - rectBmpPos.Width) / 2;
rectBmpPos.Y = (size.Height - rectBmpPos.Height) / 2;
#region [根据放大倍率,计算图像显示区域]
int nMaxMagnify = Math.Min(bmp.Width, bmp.Height) / 2;//最大放大倍率
if (magnify >= nMaxMagnify)
{
magnify = nMaxMagnify - 1;
}
var pointMagnify = new Size(bmp.Width / 2 / nMaxMagnify, bmp.Height / 2 / nMaxMagnify);//每一倍放大的像素值
int x = magnify * pointMagnify.Width;
int y = magnify * pointMagnify.Height;
int width = bmp.Width - magnify * pointMagnify.Width * 2;
int height = bmp.Height - magnify * pointMagnify.Height * 2;
#endregion [根据放大倍率,计算图像显示区域]
var rectBmpSize = new Rectangle(x, y, width, height);//图像显示的区域
e.SmoothingMode = SmoothingMode.HighQuality;//指定抗锯齿的呈现
e.DrawImage(bmp, rectBmpPos, rectBmpSize, GraphicsUnit.Pixel);//绘制图像
//bmp.Dispose();
}
/// <summary>
/// 绘制矩形
/// </summary>
/// <param name="e"></param>
/// <param name="startPoint">起始点</param>
/// <param name="endPoint">终止点</param>
public static void DrawRect(Graphics e, Point startPoint, Point endPoint)
{
var pen = new Pen(Brushes.Brown, 3);
var x1 = startPoint.X;
var y1 = startPoint.Y;
var x2 = endPoint.X;
var y2 = endPoint.Y;
if (x1 > x2)
{
x1 = x1 + x2;
x2 = x1 - x2;
x1 = x1 - x2;
}
if (y1 > y2)
{
y1 = y1 + y2;
y2 = y1 - y2;
y1 = y1 - y2;
}
e.DrawRectangle(pen, x1, y1, x2 - x1, y2 - y1);
}
/// <summary>
/// 绘制线段
/// </summary>
/// <param name="e"></param>
/// <param name="startPoint">起始点</param>
/// <param name="endPoint">终止点</param>
public static void DrawLine(Graphics e, Point startPoint, Point endPoint)
{
var brush = new SolidBrush(Color.FromArgb(127, Color.Black));
var pen = new Pen(Brushes.Brown, 3);
var x1 = startPoint.X;
var y1 = startPoint.Y;
var x2 = endPoint.X;
var y2 = endPoint.Y;
e.FillEllipse(brush, x1 - 3, y1 - 3, 6, 6); //绘制一个椭圆,填充内部颜色,可以代表一个点
e.FillEllipse(brush, x2 - 3, y2 - 3, 6, 6); //绘制一个椭圆,填充内部颜色,可以代表一个点
e.DrawLine(pen, x1, y1, x2, y2); //绘制一条直线
}
/// <summary>
/// 绘制十字
/// </summary>
/// <param name="e"></param>
/// <param name="point">指定坐标点</param>
/// <param name="size">控件大小</param>
public static void DrawCross(Graphics e, Point point, Size size)
{
var pen = new Pen(Brushes.Yellow, 1);
int radius = Math.Min(size.Width, size.Height) / 2 - 4;
e.DrawLine(pen, point.X, point.Y - radius, point.X, point.Y + radius); //绘制垂直条
e.DrawLine(pen, point.X - radius, point.Y, point.X + radius, point.Y); //绘制水平线条
//DrawString(e, point, size);//绘制坐标文字信息
}
/// <summary>
/// 绘制等腰三角形
/// </summary>
/// <param name="e"></param>
/// <param name="point1">顶点</param>
/// <param name="point2">底边任意一点</param>
public static void DrawEquicruralTriangle(Graphics e, Point point1, Point point2)
{
var pen = new Pen(Brushes.Brown, 3);
Point[] points = new Point[4];
points[0] = point1;
points[1] = point2;
points[2] = new Point(point2.X + 2 * (point1.X - point2.X), point2.Y);
points[3] = point1;
e.DrawPolygon(pen, points);
}
/// <summary>
/// 绘制菱形
/// </summary>
/// <param name="e"></param>
/// <param name="startPoint">起始点</param>
/// <param name="endPoint">终止点</param>
public static void DrawRhombus(Graphics e, Point startPoint, Point endPoint)
{
int diff = endPoint.Y - startPoint.Y;
float x1 = startPoint.X;
float x2 = endPoint.X;
float y1 = startPoint.Y;
float y2 = endPoint.Y;
Calculate(ref x1, ref x2, ref y1, ref y2);
var pen = new Pen(Brushes.Brown, 3);
Point[] points = new Point[5];
points[0] = startPoint;
points[1] = new Point((int)x1, (int)y1);
points[2] = endPoint;
points[3] = new Point((int)x2, (int)y2);
points[4] = startPoint;
e.DrawPolygon(pen, points);
}
/// <summary>
/// 绘制空心圆
/// </summary>
/// <param name="e"></param>
/// <param name="point1">圆心</param>
/// <param name="point2">确定圆半径的第二个点</param>
public static void DrawHollowCircle(Graphics e, Point point1, Point point2)
{
var pen = new Pen(Brushes.Brown, 3);
float x1 = point1.X;
float x2 = point2.X;
float y1 = point1.Y;
float y2 = point2.Y;
float diameter = (float)Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));//半径
var rect = new RectangleF
{
X = point1.X - diameter,
Y = point1.Y - diameter,
Width = 2 * diameter,
Height = 2 * diameter
};
e.DrawEllipse(pen, rect);
//DrawSolidCircle(e, point1, 6);//画圆心
//DrawSolidCircle(e, new Point(point2.X - 3, point2.Y - 3), 6);//确定圆半径的第二个点
}
/// <summary>
/// 绘制实心圆
/// </summary>
/// <param name="e"></param>
/// <param name="point1">圆心</param>
/// <param name="nCircle">半径</param>
public static void DrawSolidCircle(Graphics e, Point point1, int nCircle)
{
var brush = new SolidBrush(Color.FromArgb(127, Color.Black));
e.FillEllipse(brush, point1.X, point1.Y, nCircle, nCircle); //绘制圆心
}
/// <summary>
/// 在指定坐标点绘制文字
/// </summary>
/// <param name="e"></param>
/// <param name="point">指定坐标点</param>
/// <param name="size">控件大小</param>
/// <param name="info">绘制文字的信息</param>
public static void DrawString(Graphics e, Point point, Size size, string info = null)
{
if (string.IsNullOrWhiteSpace(info))
{
info = $"({point.X},{point.Y})";
}
Font font = new Font("Arial", 12f, FontStyle.Bold);//设置字体
SizeF selPtStrSize = e.MeasureString(info, font); //获取文字的宽高
if (point.X > size.Width / 2 && point.Y < size.Height / 2) //右上角
{
point.X -= (int)selPtStrSize.Width;
}
else if (point.X > size.Width / 2 && point.Y > size.Height / 2) //右下角
{
point.X -= (int)selPtStrSize.Width;
point.Y -= (int)selPtStrSize.Height;
}
else if (point.X < size.Width / 2 && point.Y > size.Height / 2) //左下角
{
point.Y -= (int)selPtStrSize.Height;
}
e.DrawString(info, font, new SolidBrush(Color.Black), point); //绘制文字
}
/// <summary>
/// 已知两点(线段),求互相垂直平分两点(线段)。
/// </summary>
/// <param name="x1">传递值为已知坐标点x1,返回值为垂直平分线的x1</param>
/// <param name="x2">传递值为已知坐标点x2,返回值为垂直平分线的x2</param>
/// <param name="y1">传递值为已知坐标点y1,返回值为垂直平分线的y1</param>
/// <param name="y2">传递值为已知坐标点y2,返回值为垂直平分线的y2</param>
/// <returns>成功返回0;失败返回非0</returns>
private static int Calculate(ref float x1, ref float x2, ref float y1, ref float y2)
{
float k1 = 1; //已知坐标点直线的斜率k值
float b1 = 1; //已知坐标点直线的纵截距b值
float k2 = 1; //垂直平分线的斜率k值
float b2 = 1; //垂直平分线的纵截距b值
try
{
//特殊线1
if (x1 == x2)
{
float center = (y1 + y2) / 2;//中心点
float dist = Math.Abs(y1 - center);//端点到中心点的距离值
x1 = center - dist;
x2 = center + dist;
y2 = y1 = (x1 + x2) / 2;
return 0;
}
//特殊线2
if (y1 == y2)
{
float center = (x1 + x2) / 2;//中心点
float dist = Math.Abs(x1 - center);//端点到中心点的距离值
x1 = x2 = (y1 + y2) / 2;
y1 = center - dist;
y2 = center + dist;
return 0;
}
#region [求已知曲线的k和b]
float temp = 0;
float coefficient; //系数值
if (x1 >= x2)
{
coefficient = (float)Math.Round((x1 / x2), 2);
temp = y2 * coefficient; //将对应的函数乘以系数
b1 = (float)Math.Round(((temp - y1) / (coefficient - 1)), 2); //求出b值
k1 = (float)Math.Round(((y1 - b1) / x1), 2); //求出k值
}
else
{
coefficient = x2 / x1;
temp = y1 * coefficient;
b1 = (float)Math.Round(((temp - y2) / (coefficient - 1)), 2); //求出b值
k1 = (float)Math.Round(((y2 - b1) / x2), 2); //求出k值
}
#endregion [求已知曲线的k和b]
#region [垂直平分线的k,b以及起始点、终止点]
{
k2 = -1 / k1; //垂直平分线的斜率k值
b2 = (x1 + x2) / (2 * k1) + (y1 + y2) / 2; //垂直平分线的纵截距b值
double cenX = (x1 + x2) / 2;//交点x
double cenY = (y1 + y2) / 2;//交点y
double dist = Math.Sqrt(Math.Abs(x1 - x2) * Math.Abs(x1 - x2) + Math.Abs(y1 - y2) * Math.Abs(y1 - y2)) / 2;//每个点距离交点(中心点)距离相同
double douAngle = Math.Atan(k2);//垂直平分线和X轴的夹角
//计算起始点和终止点
x1 = (float)(cenX + dist * Math.Cos(douAngle));
x2 = (float)(cenX - dist * Math.Cos(douAngle));
y1 = (float)(cenY + dist * Math.Sin(douAngle));
y2 = (float)(cenY - dist * Math.Sin(douAngle));
}
#endregion
return 0;
}
catch
{
return -1;
}
}
}
```