C#winform自定义控件模拟设计时界面鼠标移动和调节大小、选中效果

要想玩转Winform自定义控件需要对GDI+非常熟悉,对常用的控件有一些了解,好选择合适的基类控件来简化。
要点说明及代码
1)定义接口:
using System;
using System.Windows.Forms; namespace GDIPrinterDriver
{
/// <summary>
/// 模板元素接口
/// </summary>
public interface ILabelDesignElement
{
/// <summary>
/// PrintData/codeContext里的字段,{} []
/// </summary>
string 动态内容 { get; set; }
/// <summary>
/// 是否被选中
/// </summary>
bool DesignSelected { get; set; }
/// <summary>
/// 选择状态发生改变
/// </summary>
event Action<object, bool> SelectedStatusChange;
/// <summary>
/// 本控件被选中时键盘方向键被按下
/// </summary>
/// <param name="keyData"></param>
void KeysChangedLocation(Keys keyData);
}
}
2)控件基类实现:
using GDIPrinterDriver;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms; namespace GDILabelDesigner
{
/// <summary>
/// 设计时控件基类
/// </summary>
public abstract class DesignCellControl : PictureBox, ILabelDesignElement
{
#region 鼠标移动和缩放
private enum EnumMousePointPosition
{
MouseSizeNone = , //'无
MouseSizeRight = , //'拉伸右边框
MouseSizeLeft = , //'拉伸左边框
MouseSizeBottom = , //'拉伸下边框
MouseSizeTop = , //'拉伸上边框
MouseSizeTopLeft = , //'拉伸左上角
MouseSizeTopRight = , //'拉伸右上角
MouseSizeBottomLeft = , //'拉伸左下角
MouseSizeBottomRight = , //'拉伸右下角
MouseDrag = // '鼠标拖动
}
const int Band = ;
const int MinWidth = ;
const int MinHeight = ;
private EnumMousePointPosition m_MousePointPosition;
private Point p, p1;
private EnumMousePointPosition MousePointPosition(Size size, System.Windows.Forms.MouseEventArgs e)
{ if ((e.X >= - * Band) | (e.X <= size.Width) | (e.Y >= - * Band) | (e.Y <= size.Height))
{
if (e.X < Band)
{
if (e.Y < Band) { return EnumMousePointPosition.MouseSizeTopLeft; }
else
{
if (e.Y > - * Band + size.Height)
{ return EnumMousePointPosition.MouseSizeBottomLeft; }
else
{ return EnumMousePointPosition.MouseSizeLeft; }
}
}
else
{
if (e.X > - * Band + size.Width)
{
if (e.Y < Band)
{ return EnumMousePointPosition.MouseSizeTopRight; }
else
{
if (e.Y > - * Band + size.Height)
{ return EnumMousePointPosition.MouseSizeBottomRight; }
else
{ return EnumMousePointPosition.MouseSizeRight; }
}
}
else
{
if (e.Y < Band)
{ return EnumMousePointPosition.MouseSizeTop; }
else
{
if (e.Y > - * Band + size.Height)
{ return EnumMousePointPosition.MouseSizeBottom; }
else
{ return EnumMousePointPosition.MouseDrag; }
}
}
}
}
else
{ return EnumMousePointPosition.MouseSizeNone; }
}
#endregion
public bool DesignSelected
{
get
{
return designSelected;
}
set
{
designSelected = value;
Invalidate();
}
}
private bool designSelected = false;
public DynamicMapProperty DynamicMapProperty { get; set; }
public StaticMapProperty StaticMapProperty { get; set; }
public string 动态内容 { get; set; }
public RoteDescription RoteDescription { get; set; }
/// <summary>
/// 被选中,获取到焦点的事件
/// </summary>
public event Action<object, bool> SelectedStatusChange;
protected override void OnClick(EventArgs e)
{
DesignSelected = true;
SelectedStatusChange?.Invoke(this, DesignSelected);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
double d = 1.068D;
if (e.Delta > && DesignSelected)
{
this.Size = new Size((int)(this.Size.Width * d), (int)(this.Size.Height * d));
}
else
{
this.Size = new Size((int)(this.Size.Width / d), (int)(this.Size.Height / d));
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
p.X = e.X;
p.Y = e.Y;
p1.X = e.X;
p1.Y = e.Y;
}
protected override void OnMouseUp(MouseEventArgs e)
{
m_MousePointPosition = EnumMousePointPosition.MouseSizeNone;
this.Cursor = Cursors.Arrow;
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
switch (m_MousePointPosition)
{
#region 位置计算
case EnumMousePointPosition.MouseDrag:
Left = Left + e.X - p.X;
Top = Top + e.Y - p.Y;
break;
case EnumMousePointPosition.MouseSizeBottom:
Height = Height + e.Y - p1.Y;
p1.X = e.X;
p1.Y = e.Y; //'记录光标拖动的当前点
break;
case EnumMousePointPosition.MouseSizeBottomRight:
Width = Width + e.X - p1.X;
Height = Height + e.Y - p1.Y;
p1.X = e.X;
p1.Y = e.Y; //'记录光标拖动的当前点
break;
case EnumMousePointPosition.MouseSizeRight:
Width = Width + e.X - p1.X;
Height = Height + e.Y - p1.Y;
p1.X = e.X;
p1.Y = e.Y; //'记录光标拖动的当前点
break;
case EnumMousePointPosition.MouseSizeTop:
Top = Top + (e.Y - p.Y);
Height = Height - (e.Y - p.Y);
break;
case EnumMousePointPosition.MouseSizeLeft:
Left = Left + e.X - p.X;
Width = Width - (e.X - p.X);
break;
case EnumMousePointPosition.MouseSizeBottomLeft:
Left = Left + e.X - p.X;
Width = Width - (e.X - p.X);
Height = Height + e.Y - p1.Y;
p1.X = e.X;
p1.Y = e.Y; //'记录光标拖动的当前点
break;
case EnumMousePointPosition.MouseSizeTopRight:
Top = Top + (e.Y - p.Y);
Width = Width + (e.X - p1.X);
Height = Height - (e.Y - p.Y);
p1.X = e.X;
p1.Y = e.Y; //'记录光标拖动的当前点
break;
case EnumMousePointPosition.MouseSizeTopLeft:
Left = Left + e.X - p.X;
Top = Top + (e.Y - p.Y);
Width = Width - (e.X - p.X);
Height = Height - (e.Y - p.Y);
break;
default:
break;
#endregion
}
if (Width < MinWidth) Width = MinWidth;
if (Height < MinHeight) Height = MinHeight;
if (Tag != null)
{
if (Tag is ImageElementNode)
{
var tag = Tag as ImageElementNode;
tag.Location = Location;
}
else if (Tag is BarcodeElementNode)
{
var tag = Tag as BarcodeElementNode;
tag.Location = Location;
}
else if (Tag is TextBoxElementNode)
{
var tag = Tag as TextBoxElementNode;
tag.Location = Location;
}
}
}
else
{
m_MousePointPosition = MousePointPosition(Size, e);
switch (m_MousePointPosition)
{
#region 改变光标
case EnumMousePointPosition.MouseSizeNone:
this.Cursor = Cursors.Arrow; //'箭头
break;
case EnumMousePointPosition.MouseDrag:
this.Cursor = Cursors.SizeAll; //'四方向
break;
case EnumMousePointPosition.MouseSizeBottom:
this.Cursor = Cursors.SizeNS; //'南北
break;
case EnumMousePointPosition.MouseSizeTop:
this.Cursor = Cursors.SizeNS; //'南北
break;
case EnumMousePointPosition.MouseSizeLeft:
this.Cursor = Cursors.SizeWE; //'东西
break;
case EnumMousePointPosition.MouseSizeRight:
this.Cursor = Cursors.SizeWE; //'东西
break;
case EnumMousePointPosition.MouseSizeBottomLeft:
this.Cursor = Cursors.SizeNESW; //'东北到南西
break;
case EnumMousePointPosition.MouseSizeBottomRight:
this.Cursor = Cursors.SizeNWSE; //'东南到西北
break;
case EnumMousePointPosition.MouseSizeTopLeft:
this.Cursor = Cursors.SizeNWSE; //'东南到西北
break;
case EnumMousePointPosition.MouseSizeTopRight:
this.Cursor = Cursors.SizeNESW; //'东北到南西
break;
default:
break;
#endregion
}
}
} /// <summary>
/// 绘制方框
/// </summary>
/// <param name="g"></param>
protected void DrawSelectedStatus(Graphics g)
{
Rectangle rect = ClientRectangle;
rect.Inflate(-, -);
using (Pen p = new Pen(Brushes.Black, ))
{
p.DashStyle = DashStyle.Dot;
p.DashStyle = DashStyle.Solid;
//8个方块
g.FillRectangle(Brushes.White, new Rectangle(rect.Left - , rect.Top - , , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left + rect.Width / - , rect.Top - , , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left + rect.Width, rect.Top - , , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left - , rect.Top + rect.Height / - , , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left - , rect.Top + rect.Height, , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left + rect.Width, rect.Top + rect.Height / - , , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left + rect.Width / - , rect.Top + rect.Height, , ));
g.FillRectangle(Brushes.White, new Rectangle(rect.Left + rect.Width, rect.Top + rect.Height, , ));
g.DrawRectangle(p, new Rectangle(rect.Left - , rect.Top - , , ));
g.DrawRectangle(p, new Rectangle(rect.Left + rect.Width / - , rect.Top - , , ));
g.DrawRectangle(p, new Rectangle(rect.Left + rect.Width, rect.Top - , , ));
g.DrawRectangle(p, new Rectangle(rect.Left - , rect.Top + rect.Height / - , , ));
g.DrawRectangle(p, new Rectangle(rect.Left - , rect.Top + rect.Height, , ));
g.DrawRectangle(p, new Rectangle(rect.Left + rect.Width, rect.Top + rect.Height / - , , ));
g.DrawRectangle(p, new Rectangle(rect.Left + rect.Width / - , rect.Top + rect.Height, , ));
g.DrawRectangle(p, new Rectangle(rect.Left + rect.Width, rect.Top + rect.Height, , ));
}
}
/// <summary>
/// 旋转图片
/// </summary>
/// <param name="bmp">源图</param>
/// <param name="angle">角度</param>
/// <param name="bkColor">背景色</param>
/// <returns></returns>
protected Bitmap ImageRotate(Bitmap bmp, float angle, Color bkColor)
{
int w = bmp.Width + ;
int h = bmp.Height + ;
PixelFormat pf;
if (bkColor == Color.Transparent)
{
pf = PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tmp = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tmp);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, , );
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);
g = Graphics.FromImage(dst);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tmp, , );
g.Dispose();
tmp.Dispose();
return dst;
}
/// <summary>
/// 响应键盘光标键
/// </summary>
/// <param name="keyData"></param>
public virtual void KeysChangedLocation(Keys keyData)
{
if (keyData == Keys.Up)
{
Top -= ;
}
if (keyData == Keys.Down)
{
Top += ;
}
if (keyData == Keys.Left)
{
Left -= ;
}
if (keyData == Keys.Right)
{
Left += ;
}
if (Tag != null)
{
if (Tag is ImageElementNode)
{
var tag = Tag as ImageElementNode;
tag.Location = Location;
}
else if (Tag is BarcodeElementNode)
{
var tag = Tag as BarcodeElementNode;
tag.Location = Location;
}
else if (Tag is TextBoxElementNode)
{
var tag = Tag as TextBoxElementNode;
tag.Location = Location;
}
}
}
}
}
C#winform自定义控件模拟设计时界面鼠标移动和调节大小、选中效果的更多相关文章
- winform窗体运行时的大小和设计时不一致
窗体设置的尺寸为1946*850,而电脑分辨率是1920*1280 按说宽度已经超过屏幕大小很多了,应该显示占满屏幕宽度才对,但是运行时宽度只有设计时的一半 高度最多只能是1946像素,再拉大也不管用 ...
- C# 自定义控件容器,设计时可添加控件
本分步指南介绍在将 UserControl 放在 Windows 窗体上之后,如何将 UserControl 对象用作设计时控件容器.可能会有这样的情况:您想将一个控件拖到 UserControl 中 ...
- Winform自定义控件实例
本文转自http://www.cnblogs.com/hahacjh/archive/2010/04/29/1724125.html 写在前面: .Net已经成为许多软件公司的选择,而.Net自定义W ...
- WPF案例(二)模拟Apple OS 界面前后180度反转
原文:WPF案例(二)模拟Apple OS 界面前后180度反转 我们在设计应用程序界面的时候,为了充分利用界面空间,住住需要灵活的界面布局方式,比如可以在界面正面空间上定义一个Chart,背面空间上 ...
- (三十)c#Winform自定义控件-文本框(三)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- (六十九)c#Winform自定义控件-垂直滚动条
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (七十三)c#Winform自定义控件-资源加载窗体
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (七十九)c#Winform自定义控件-导航菜单
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- (原创)[C#] 一步一步自定义拖拽(Drag&Drop)时的鼠标效果:(一)基本原理及基本实现
一.前言 拖拽(Drag&Drop),属于是极其常用的基础功能. 无论是在系统上.应用上.还是在网页上,拖拽随处可见.同时拖拽时的鼠标效果也很漂亮,像这样: 这样: 还有这样: 等等等等. 这 ...
随机推荐
- Linux多线程编程——线程的同步
POSIX信号量 posix信号量不同于IPC中的信号量 常用的posix信号量函数 #include <semaphore.h> int sem_init(sem_t* sem,i ...
- windows 终端命令详解
打开"运行"对话框(Win+R),输入cmd,打开控制台命令窗口... 也可以通过cmd /c 命令 和 cmd /k 命令的方式来直接运行命令 注:/c表示执行完命令后关闭cmd ...
- 【技术分析】DowginCw病毒家族解析
作者:钱盾反诈实验室 0x1.背景 近期,钱盾反诈实验室通过钱盾恶意代码智能监测引擎感知并捕获一批恶意应用.由于该批病毒会联网加载"CWAPI"插件,故将其命名为"D ...
- vue页面切换效果(slide效果切换)
最近碰到一个需求,单页应用里面页面切换的效果需要做成跟轮播图滑动slide一样,让这个页面在切换时感觉是一个页面.反复琢磨的vue里面的transition,最终将实现的核心代码贴出来.这里实现的是上 ...
- 简单的调用OpenCV库的Android NDK开发 工具Android Studio
前言 本博客写于2017/08/11, 博主非专业搞安卓开发, 只是工作的需要倒腾了下Android NDK相关的开发, 博文中有什么不正确.不严格的地方欢迎指正哈 本文后续也许还会有删改, 就 ...
- Winform开发中如何将数据库字段绑定到ComboBox控件
最近开始自己动手写一个财务分析软件,由于自己也是刚学.Net不久,所以自己写的的时候遇到了很多问题,希望通过博客把一些印象深刻的问题记录下来. Winform开发中如何将数据库字段绑定到ComboBo ...
- 一种使用GDI+对图片尺寸和质量的压缩方法
今天同事向我询问图片压缩的算法.我想起大概两三年前做过的一个项目. 当中包括了尺寸和质量两种压缩算法.而且支持JPEG.bmp.PNG等格式. 今天把这段逻辑贴出来,供大家參考.(转载请指明来源于br ...
- 【Linux探索之旅】第二部分第五课:用户和权限,有权就任性
内容简单介绍 .第二部分第五课:用户和权限,有权就任性 2.第二部分第六课预告:Nano,刚開始学习的人的文本编辑器 用户和权限.有权就任性 今天的标题也挺任性的啊,虽说小编是一个非常本分的人(真的吗 ...
- Vue.js 基本语法
插值 Html 使用 v-html 指令用于输出 html 代码: <div id="app"> <div v-html="message"& ...
- 主从DB与cache一致性
本文主要讨论这么几个问题: (1)数据库主从延时为何会导致缓存数据不一致 (2)优化思路与方案 一.需求缘起 上一篇<缓存架构设计细节二三事>中有一个小优化点,在只有主库时,通过" ...