65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (5投票s)

2012年7月30日

CPOL

3分钟阅读

viewsIcon

41099

downloadIcon

898

一个便利贴控件

引言

本教程介绍了一种在 C# (.NET 3.5) 中创建便利贴控件的方法。 起源于我尝试使用画图软件绘制便利贴。在某个时刻,我决定将其制成一个控件。 例如,这可以用于虚拟 SCRUM 板或待办事项应用程序。

a simple postit

a postit with more text

multiple postits

功能

在开始之前,我定义了一个简短的待实现功能列表。将来版本肯定会添加其他功能。

创建时要设置的属性

  • 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);
}

便利贴控件是借助 OnPaintOnPaintBackground 方法绘制的。 这两种方法都被覆盖:

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);
}

鼠标事件 MouseDownMouseMove 也在此处处理

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:将便利贴颜色添加为新属性。

有用的资源

© . All rights reserved.