Winform绘制控件解决闪烁问题
一开始用复合控件(就是在UserControl上面拖进去一些Label、Button之类的), 然后在把这个用户控件加入到滚动容器中去,
可没想到滚动过程简直不忍直视,即使开启了双缓存
后来一想还是重写onpaint自己绘制界面算了,但是说起绘制界面又麻烦,这可是个苦力活
不过效果还是有的,流畅的让你感觉不到卡
代码如下
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class UserControl1 : UserControl
{
#region 私有属性
Font fontDict = new Font("Microsoft YaHei", 13);
Font fontYb = new Font("Microsoft YaHei", 10);
Font fontDesc = new Font("新宋体", 9);
/// <summary>
/// 发音图标
/// </summary>
Image soundIcon = null;
/// <summary>
/// 发音图标_高亮
/// </summary>
Image soundIconHigh = null;
/// <summary>
/// 遗忘图标
/// </summary>
Image forgetIcon = null;
/// <summary>
/// 阶段图标
/// </summary>
Image gradeIcon = null;
/// <summary>
/// 组队按钮
/// </summary>
UIRectangle flagButton = null;
/// <summary>
/// 删除按钮
/// </summary>
UIRectangle delButton = null;
Rectangle rectSound1;
Rectangle rectSound2;
/// <summary>
/// 是否鼠标进入sound1
/// </summary>
bool isEnterSound1 = false;
/// <summary>
/// 是否鼠标进入sound2
/// </summary>
bool isEnterSound2 = false;
event SoundEvent mouseEnterSound;
event EventHandler mouseClickSound;
event EventHandler mouseClickFlag;
event EventHandler mouseClickDelete;
#endregion
/// <summary>
/// 单词名称
/// </summary>
public string DictName { set; get; }
/// <summary>
/// 英音标
/// </summary>
public string USKSpell { set; get; }
/// <summary>
/// 美音标
/// </summary>
public string USASpell { set; get; }
/// <summary>
/// 释义
/// </summary>
public string Descript { set; get; }
/// <summary>
/// 遗忘次数
/// </summary>
public int ForgetCount { set; get; }
/// <summary>
/// 阶段名称
/// </summary>
public string GradeName { set; get; }
/// <summary>
/// 鼠标进入发音图标事件
/// </summary>
public event SoundEvent OnMouseEnterSound {
add {
mouseEnterSound += value;
}
remove {
mouseEnterSound -= value;
}
}
/// <summary>
/// 鼠标点击发音图标事件
/// </summary>
public event EventHandler OnClickSound {
add {
mouseClickSound += value;
}
remove {
mouseClickSound -= value;
}
}
/// <summary>
/// 鼠标点击旗帜事件
/// </summary>
public event EventHandler OnClickFlag {
add {
mouseClickFlag += value;
}
remove {
mouseClickFlag -= value;
}
}
/// <summary>
/// 鼠标点击删除按钮事件
/// </summary>
public event EventHandler OnClickDelete {
add {
mouseClickDelete += value;
}
remove {
mouseClickDelete -= value;
}
}
public UserControl1()
{
this.DoubleBuffered = true;
InitializeComponent();
this.Load += UserControl1_Load;
}
/// <summary>
/// 加载完毕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void UserControl1_Load(object sender, EventArgs e)
{
//加载图片资源
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UserControl1));
soundIcon = ((System.Drawing.Image)(resources.GetObject("sound_play_gray")));
soundIconHigh = ((System.Drawing.Image)(resources.GetObject("sound_play")));
forgetIcon = ((System.Drawing.Image)(resources.GetObject("ico_question")));
gradeIcon = ((System.Drawing.Image)(resources.GetObject("ico_grade")));
flagButton = new UIRectangle(((System.Drawing.Image)(resources.GetObject("ico_flag_normal"))), ((System.Drawing.Image)(resources.GetObject("ico_flag_focus"))));
delButton = new UIRectangle(((System.Drawing.Image)(resources.GetObject("ico_delete_normal"))), ((System.Drawing.Image)(resources.GetObject("ico_delete_focus"))));
this.Margin = new Padding(0);
DictName = "Caption";
USKSpell = "英 [caption]";
USASpell = "美 [caption]";
Descript = "释义:n. 说明文字 v.给(图片、照片等)加说明文字释义:n. 说明文字 v.给(图片、照片等)加说明文字释义:n. 说明文字 v.给(图片、照片等)加说明文字";
GradeName = "青铜 x3";
ForgetCount = 9;
}
/// <summary>
/// 控件重绘
/// </summary>
/// <param name="e"></param>
protected override void OnPaint(PaintEventArgs e)
{
//单词宽度
float dictWidth = GetTextWidth(e.Graphics, DictName, fontDict);
//USK音标宽度
float uskWidth = GetTextWidth(e.Graphics, USKSpell, fontYb);
//USA音标宽度
float usaWidth = GetTextWidth(e.Graphics, USASpell, fontYb);
//单词阶段宽度
float gradeWidth = GetTextWidth(e.Graphics, GradeName, fontYb);
float left = 10;
//画单词
e.Graphics.DrawString(DictName, fontDict, Brushes.Black, left, 5);
left += dictWidth + 20;
//画音标
e.Graphics.DrawString(USKSpell, fontYb, Brushes.Gray, left, 7);
left += uskWidth + 5;
#region 画发音图标1
//发音图标
if (isEnterSound1)
{
e.Graphics.DrawImage(soundIconHigh, left, 9, 15, 15);
rectSound1 = new Rectangle((int)left, 9, 15, 15);
left += 30;
}
else
{
e.Graphics.DrawImage(soundIcon, left, 9, 15, 15);
rectSound1 = new Rectangle((int)left, 9, 15, 15);
left += 30;
}
#endregion
//画音标
e.Graphics.DrawString(USASpell, fontYb, Brushes.Gray, left, 7);
left += usaWidth + 5;
#region 画发音图标2
if (isEnterSound2)
{
//发音图标
e.Graphics.DrawImage(soundIconHigh, left, 9, 15, 15);
rectSound2 = new Rectangle((int)left, 9, 15, 15);
left += 50;
}
else {
//发音图标
e.Graphics.DrawImage(soundIcon, left, 9, 15, 15);
rectSound2 = new Rectangle((int)left, 9, 15, 15);
left += 50;
}
#endregion
#region try画遗忘次数
if (ForgetCount > 0)
{
e.Graphics.DrawImage(forgetIcon, new Rectangle((int)left,9,15,15));
left += 15+3;
e.Graphics.DrawString(ForgetCount.ToString(), fontYb, Brushes.Gray, left, 7);
left += 30;
}
#endregion
#region 画单词阶段(熟悉度)
e.Graphics.DrawImage(gradeIcon, new Rectangle((int)left, 9, 15, 15));
left += 15 + 3;
e.Graphics.DrawString(GradeName, fontYb, Brushes.Gray, left, 7);
left += gradeWidth + 5;
#endregion
#region 画组队旗帜
if (flagButton.IsEnter)
{
flagButton.Rect = new Rectangle((int)left, 7, 18, 18);
e.Graphics.DrawImage(flagButton.HightImage, flagButton.Rect);
left += 15 + 5;
}
else {
flagButton.Rect = new Rectangle((int)left, 7, 18, 18);
e.Graphics.DrawImage(flagButton.NormalImage, flagButton.Rect);
left += 15 + 5;
}
#endregion
#region 画删除图标
if (delButton.IsEnter)
{
delButton.Rect = new Rectangle(this.Width-25, 7, 18, 18);
e.Graphics.DrawImage(delButton.HightImage, delButton.Rect);
}
else
{
delButton.Rect = new Rectangle(this.Width - 25, 7, 18, 18);
e.Graphics.DrawImage(delButton.NormalImage, delButton.Rect);
}
#endregion
//画释义
e.Graphics.DrawString(Descript, fontDesc, Brushes.Gray, 12, 40);
//画分割线
// e.Graphics.DrawRectangle(Pens.Gray, new Rectangle(0,this.Height-1,this.Width,1));
e.Graphics.DrawLine(Pens.WhiteSmoke,0,this.Height-1,this.Width,this.Height-1);
}
/// <summary>
/// 鼠标移动事件
/// 判断鼠标是否进入某个矩形内
/// 判断鼠标是否移出某个矩形内
/// </summary>
/// <param name="e"></param>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (IsInRangle(e.X, e.Y, rectSound1))
{
//鼠标进入声音1
if (!isEnterSound1)
{
isEnterSound1 = true;
this.Invalidate(rectSound1);
if (mouseEnterSound != null) {
//响应事件
mouseEnterSound(this,0);
}
}
}
else if (IsInRangle(e.X, e.Y, rectSound2))
{
if (!isEnterSound2)
{
//鼠标进入声音2
isEnterSound2 = true;
this.Invalidate(rectSound2);
if (mouseEnterSound != null){
//响应事件
mouseEnterSound(this, 1);
}
}
}
else if (IsInRangle(e.X, e.Y, flagButton.Rect))
{
//鼠标进入旗帜按钮
if (!flagButton.IsEnter)
{
flagButton.IsEnter = true;
this.Invalidate(flagButton.Rect);
}
}
else if (IsInRangle(e.X, e.Y, delButton.Rect)) {
//鼠标进入删除按钮
if (!delButton.IsEnter) {
delButton.IsEnter = true;
this.Invalidate(delButton.Rect);
}
}
else
{
if (isEnterSound1)
{
isEnterSound1 = false;
this.Invalidate(rectSound1);
}
if (isEnterSound2)
{
isEnterSound2 = false;
this.Invalidate(rectSound2);
}
if (flagButton.IsEnter)
{
flagButton.IsEnter = false;
this.Invalidate(flagButton.Rect);
}
if (delButton.IsEnter) {
delButton.IsEnter = false;
this.Invalidate(delButton.Rect);
}
}
}
/// <summary>
/// 鼠标点击事件
/// 响应各个元素的点击事件
/// </summary>
/// <param name="e"></param>
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (IsInRangle(e.X, e.Y, rectSound1))
{
if (mouseEnterSound != null)
{
mouseEnterSound(this, 0);
}
}
else if (IsInRangle(e.X, e.Y, rectSound2))
{
if (mouseEnterSound != null)
{
mouseEnterSound(this, 1);
}
}
else if (IsInRangle(e.X, e.Y, flagButton.Rect))
{
if (mouseClickFlag != null)
{
mouseClickFlag(this, e);
}
}
else if (IsInRangle(e.X, e.Y, delButton.Rect)) {
if (mouseClickDelete != null) {
mouseClickDelete(this,e);
}
}
}
/// <summary>
/// 判断是否再此矩形内
/// </summary>
/// <param name="rect"></param>
/// <returns></returns>
bool IsInRangle(int x,int y,Rectangle rect) {
if (x >= rect.Left && x <= rect.Left + rect.Width
&& y >= rect.Top && y <= rect.Top + rect.Height)
{
return true;
}
return false;
}
/// <summary>
/// 取文字宽度
/// </summary>
/// <param name="gp"></param>
/// <param name="str"></param>
/// <param name="font"></param>
/// <returns></returns>
float GetTextWidth(Graphics gp,string str, Font font) {
SizeF size = gp.MeasureString(DictName, fontDict);
return size.Width;
}
}
/// <summary>
/// 描述ui元素
/// </summary>
class UIRectangle {
public Image NormalImage { set; get; }
public Image HightImage { set; get;}
public Rectangle Rect { set; get; }
public bool IsEnter { set; get; }
public UIRectangle(Image img1,Image img2) {
this.NormalImage = img1;
this.HightImage = img2;
IsEnter = false;
}
}
/// <summary>
/// 发音图标触发事件类型
/// </summary>
/// <param name="sender"></param>
/// <param name="index"></param>
public delegate void SoundEvent(object sender, int index);
}