在 C# (.Net 3.5) 中创建便利贴控件






4.50/5 (5投票s)
一个便利贴控件
引言
本教程介绍了一种在 C# (.NET 3.5) 中创建便利贴控件的方法。 起源于我尝试使用画图软件绘制便利贴。在某个时刻,我决定将其制成一个控件。 例如,这可以用于虚拟 SCRUM 板或待办事项应用程序。
功能
在开始之前,我定义了一个简短的待实现功能列表。将来版本肯定会添加其他功能。
创建时要设置的属性
Message
:消息本身Font
:字体类型和大小TextColor
:消息的文本颜色PostitColor
:便利贴的颜色Urgency
:一个标志,指示任务是否紧急
在便利贴上执行的操作
- 移动:四处移动便利贴
- 更改大小:使用鼠标滚轮使便利贴更大或更小
- 重置大小:将便利贴设置为其原始大小
使用代码
本节首先介绍控件的实现,然后介绍使用该控件的示例客户端的实现。
步骤 1:创建图像
经过一些实验,我创建了一个足够好的位图。您当然可以使用附件中提供的图像。
步骤 2:创建项目
在 Visual Studio 中创建一个类型为 Windows 窗体应用程序的项目。
步骤 3:将图像添加为资源
- 打开项目属性,然后转到“资源”选项卡
- 选择“添加资源”,然后选择“添加现有文件”。
- 选择附加到本文的位图(“lightyellow.bmp”、“flatyellow.bmp”)
步骤 4:添加用户控件
通过解决方案资源管理器添加新的用户控件,并将其命名为 Postit。
步骤 5:实现控件
此处定义了以下属性:
private string message; // the message
private Size postitSize; // the size of the postit
private Bitmap postitBitMap; // the bitmap
private int sizeDiff = 20; // the diff for resizing the postit
private int maxWidth = 750; // the maximum width
private int maxHeigth = 750; // the maximum height
private int minWidth = 150; // the minimum width
private int minHeigth = 150; // the minimum width
private int blackBorderWidth = 50; // the width to avoid a black border around the bitmap
private int blackBorderHeight = 70; // the height to avoid a black border around the bitmap
private int messageLeft = 5; // the left position of the message
private int messageTop = 100; // the top position of the message
private bool isUrgent = false; // the urgency flag
private int urgencyFlagLeft = 5; // the left position of the urgency flag
private int urgencyFlagTop = 5; // the top position of the urgency flag
private Size originalSize; // the original size
private Font messageFont = new Font("Tahoma", 20); // the font
private Brush messageColor = Brushes.Black; // the font color
private PostitColor postitColor; // the color of the postit
便利贴控件有三个不同的构造函数
public Postit(String message)
{
this.message = message;
this.postitColor = PostitColor.FlatYellow;
this.init();
}
public Postit(String message, Font messageFont, Brush messageColor, PostitColor postitColor)
{
this.message = message;
this.messageFont = messageFont;
this.messageColor = messageColor;
this.postitColor = postitColor;
this.init();
}
public Postit(String message, Font messageFont, Brush messageColor, PostitColor postitColor, bool isUrgent)
{
this.message = message;
this.messageFont = messageFont;
this.messageColor = messageColor;
this.postitColor = postitColor;
this.isUrgent = isUrgent;
this.init();
}
所有构造函数都调用 init()
方法,该方法执行所有常规初始化,即创建位图,定义便利贴的大小和原始大小,并设置事件处理程序
private void init()
{
//set the control styles
SetStyle(ControlStyles.OptimizedDoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
InitializeComponent();
// set the postit bitmap
if (this.postitColor == PostitColor.LightYellow)
this.postitBitMap = PostitDemo.Properties.Resources.lightyellow;
else
this.postitBitMap = PostitDemo.Properties.Resources.flatyellow;
//set the size
this.postitSize = this.postitBitMap.Size;
this.originalSize = this.Size;
// set the event handlers
this.MouseWheel += new MouseEventHandler(this.OnMouseWheel);
this.DoubleClick += new EventHandler(this.OnDoubleClick);
}
便利贴控件是借助 OnPaint
和 OnPaintBackground
方法绘制的。 这两种方法都被覆盖:
protected override void OnPaint(PaintEventArgs e)
{
this.drawPostit(e.Graphics);
}
private void drawPostit(Graphics controlGraphics)
{
// define a rectangle to draw the image in.
// NOTE: Make the rectangle slightly larger than the original bitmap to avoid a black border.
Rectangle imageRect = new Rectangle(0, 0, this.postitSize.Width+this.blackBorderWidth,
this.postitSize.Height+this.blackBorderHeight);
controlGraphics.DrawImage(this.postitBitMap, imageRect);
// draw the text
RectangleF textRect = new RectangleF(this.messageLeft, this.messageTop, this.postitSize.Width,
this.postitSize.Height);
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Center;
controlGraphics.DrawString(this.message, this.messageFont, this.messageColor, textRect,
drawFormat);
// draw the emergency flag if necessary
if (this.isUrgent)
{
RectangleF urgentRect = new RectangleF(this.urgencyFlagLeft, this.urgencyFlagTop,
this.postitSize.Width / 10, 100);
controlGraphics.DrawString("!", new Font("Tahoma", 50,FontStyle.Bold), Brushes.Red,
urgentRect);
}
}
drawPostit
方法首先绘制位图。 然后,使用给定的字体绘制消息。 最后,如果设置了该标志,则绘制紧急标志。
OnPaintBackground
方法为空,以避免绘制背景。 这最大限度地减少了移动便利贴时出现闪烁的问题。
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//Don't allow the background to paint
}
便利贴的大小调整由 OnMouseWheel
方法处理
protected void OnMouseWheel(object sender, MouseEventArgs e)
{
this.resize(e);
}
private void resize(MouseEventArgs e)
{
int width = this.Size.Width;
int height = this.Size.Height;
// make it larger
if (e.Delta > 0)
{
if ((width + this.sizeDiff <= this.maxWidth)
&& (height + this.sizeDiff <= this.maxHeigth))
{
width += this.sizeDiff;
height += this.sizeDiff;
}
}
else // make it smaller
{
if ((width - this.sizeDiff >= this.minWidth)
&& (height - this.sizeDiff >= this.minHeigth))
{
width -= this.sizeDiff;
height -= this.sizeDiff;
}
}
// set the new size
this.Size = new Size(width, height);
this.postitSize = new Size(width - 25, height - 35);
}
如上所述,便利贴的大小应通过双击重置
protected void OnDoubleClick(object sender, EventArgs e)
{
this.resetSize();
}
private void resetSize()
{
this.Size = this.originalSize;
this.postitSize = this.postitBitMap.Size;
}
步骤 6:实现窗体
现在,便利贴控件已准备就绪,以下描述了使用该便利贴控件的 Windows 窗体的创建
该窗体包含以下控件
- 一个 groupbox (name=grpPostitSettings)
- 一个 label (name=lblMessageText)
- 一个 textbox (name=txtMessage)
- ...以及一个 button (name=btnCreatePostit)
此外,该窗体还具有以下属性
private Postit currentPostit = null; // represents the currently selected postit
private List<Postit> postitList = new List<Postit>();
private Point ptStartPosition; // the start position of the postit when moving
private Point ptEndPosition; // the end position of the postit when moving
单击该按钮时,将创建一个新的便利贴,设置事件处理程序,并将控件添加到窗体:
private void btnCreatePostit_Click(object sender, EventArgs e)
{
Postit postit = new Postit(this.txtMessage.Text, new Font("Comic", 20),
Brushes.Green, PostitColor.FlatYellow, this.chkUrgent.Checked);
postit.Location = new Point(5, 100);
postit.MouseDown += new MouseEventHandler(this.OnMouseDown);
postit.MouseMove += new MouseEventHandler(this.OnMouseMove);
postit.BackColor = Color.FromKnownColor(KnownColor.Transparent);
this.Controls.Add(postit);
this.currentPostit = postit;
this.postitList.Add(postit);
}
鼠标事件 MouseDown
和 MouseMove
也在此处处理
private void OnMouseDown(object sender, MouseEventArgs e)
{
this.currentPostit = sender as Postit;
this.ptStartPosition = this.PointToScreen(e.Location);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Cursor.Current = Cursors.SizeAll;
this.ptEndPosition = this.currentPostit.PointToScreen(e.Location);
ptEndPosition.Offset(-ptStartPosition.X, -ptStartPosition.Y);
this.currentPostit.Location = ptEndPosition;
this.Invalidate();
}
}
历史
- 2012-07-30:这是第一个版本。
- 2012-08-09:将便利贴颜色添加为新属性。