在微风 IM 版本2中我们实现了局域网内的p2p通信,具体见:
【开源下载】c#编写的聊天程序微风IM 版本2 增加局域网P2P通信
前面有朋友说微风IM的UI有点朴素,也确实,于是到网上去淘了件新衣服。
新的UI来自于网上开源程序,由“翱翔的雄鹰”老师编写的完全开源的QQ2010.(c# WinForm).新的UI中有许多自定义控件,我从其中学到了很多Winfrom控件制作的知识。
比如,带边框的文本框
![](http://static.oschina.net/uploads/img/201503/03144411_Hbuk.gif)
![](http://static.oschina.net/uploads/img/201503/03144411_ZtNr.gif)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SimpleIMClient.Skin;
namespace SimpleIMClient.Skin
{
public partial class BasicQQTextBox : UserControl
{
private Graphics g = null;
private Bitmap Bmp = null;
private Color borderColor = Color.FromArgb(84, 165, 213);
private Bitmap _icon;
public BasicQQTextBox()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
Bmp = ResClass.GetImgRes("frameBorderEffect_normalDraw");
Icon = ResClass.GetImgRes("keyboard");
InitializeComponent();
}
[Description("文本"), Category("Appearance")]
public string Texts
{
get
{
return textBox1.Text;
}
set
{
textBox1.Text = value;
this.Invalidate();
}
}
[Description("图标"), Category("Appearance")]
public Bitmap Icon
{
get
{
return _icon;
}
set
{
_icon = value;
this.Invalidate();
}
}
[Description("密码框"), Category("Appearance")]
public bool IsPass
{
get
{
return textBox1.UseSystemPasswordChar;
}
set
{
textBox1.UseSystemPasswordChar = value;
if(value)
Icon = ResClass.GetImgRes("keyboard");
}
}
[Description("只读"), Category("Appearance")]
public bool ReadOn
{
get
{
return textBox1.ReadOnly;
}
set
{
textBox1.ReadOnly = value;
if (value)
textBox1.BackColor = Color.Gray;
else
textBox1.BackColor = Color.White;
}
}
public System.Windows.Forms.TextBox textBox
{
get
{
return textBox1;
}
set
{
textBox1 = value;
}
}
[Description("右键菜单"), Category("Appearance")]
public override ContextMenuStrip ContextMenuStrip
{
get
{
return textBox1.ContextMenuStrip;
}
set
{
textBox1.ContextMenuStrip = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
g = e.Graphics;
if(Bmp==null)
Bmp = ResClass.GetImgRes("frameBorderEffect_normalDraw");
if (Bmp != null)
{
g.DrawImage(Bmp, new Rectangle(0, 0, 4, 4), 0, 0, 4, 4, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(4, 0, this.Width - 8, 4), 4, 0, Bmp.Width - 8, 4, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(this.Width - 4, 0, 4, 4), Bmp.Width - 4, 0, 4, 4, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(0, 4, 4, this.Height - 6), 0, 4, 4, Bmp.Height - 8, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(this.Width - 4, 4, 4, this.Height - 6), Bmp.Width - 4, 4, 4, Bmp.Height - 6, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(0, this.Height - 2, 2, 2), 0, Bmp.Height - 2, 2, 2, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(2, this.Height - 2, this.Width - 2, 2), 2, Bmp.Height - 2, Bmp.Width - 4, 2, GraphicsUnit.Pixel);
g.DrawImage(Bmp, new Rectangle(this.Width - 2, this.Height - 2, 2, 2), Bmp.Width - 2, Bmp.Height - 2, 2, 2, GraphicsUnit.Pixel);
}
if (Icon != null)
g.DrawImage(Icon, new Rectangle(1, 1, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel);
}
private void textBox1_MouseEnter(object sender, EventArgs e)
{
Bmp = ResClass.GetImgRes("frameBorderEffect_mouseDownDraw");
this.Invalidate();
}
private void textBox1_MouseLeave(object sender, EventArgs e)
{
Bmp = ResClass.GetImgRes("frameBorderEffect_normalDraw");
this.Invalidate();
}
protected override void OnParentFontChanged(EventArgs e)
{
base.OnParentFontChanged(e);
textBox1.Font = this.Font;
}
protected override void OnParentForeColorChanged(EventArgs e)
{
base.OnParentForeColorChanged(e);
textBox1.ForeColor = this.ForeColor;
}
private void textBox1_Enter(object sender, EventArgs e)
{
if (!textBox1.UseSystemPasswordChar)
{
if (textBox1.Text.Equals("<请输入帐号>"))
{
textBox1.Text = "";
textBox1.ForeColor = Color.Black;
}
}
}
private void textBox1_Leave(object sender, EventArgs e)
{
if (!textBox1.UseSystemPasswordChar)
{
if (textBox1.Text.Equals(""))
{
textBox1.Text = "<请输入帐号>";
textBox1.ForeColor = Color.DarkGray;
}
}
}
}
}
鼠标经过时,显示边框的按钮
![](http://static.oschina.net/uploads/img/201503/03144411_Hbuk.gif)
![](http://static.oschina.net/uploads/img/201503/03144411_ZtNr.gif)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SimpleIMClient.Skin;
namespace SimpleIMClient.Skin
{
public partial class LoginButton : UserControl
{
private Graphics g = null;
private Bitmap Bmp = null;
public LoginButton()
{
Bmp = ResClass.GetImgRes("login_btn_normal");
if (this.Focused)
Bmp = ResClass.GetImgRes("login_btn_focus");
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.BackColor = Color.Transparent;
this.Size = new Size(74,27);
}
[Description("文本"), Category("Appearance")]
public string Texts
{
get
{
return Text;
}
set
{
Text = value;
this.Invalidate();
}
}
private PointF GetPointF(string text)
{
float x, y;
switch (text.Length)
{
case 1:
x = (float)(this.Width - 12.5 * 1) / 2;
y = 4;
break;
case 2:
x = (float)(this.Width - 12.5 * 2) / 2;
y = 4;
break;
case 3:
x = (float)(this.Width - 12.5 * 3) / 2;
y = 4;
break;
case 4:
x = (float)(this.Width - 12.5 * 4) / 2;
y = 4;
break;
case 5:
x = (float)(this.Width - 12.3 * 5) / 2;
y = 4;
break;
case 6:
x = (float)(this.Width - 12.3 * 6) / 2;
y = 4;
break;
default:
x = (float)(this.Width - 12.3 * 4) / 2;
y = 4;
break;
}
return new PointF(x, y);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
g = e.Graphics;
if (Bmp != null)
{
g.DrawImage(Bmp, new Rectangle(0, 0, this.Width, this.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel);
}
PointF point = GetPointF(this.Text);
if (this.Enabled)
g.DrawString(this.Texts, new Font("微软雅黑", 9F), Brushes.Black, point);
else
g.DrawString(this.Texts, new Font("微软雅黑", 9F), Brushes.Gray, point);
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
Bmp = ResClass.GetImgRes("login_btn_highlight");
this.Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
Bmp = ResClass.GetImgRes("login_btn_normal");
if (this.Focused)
Bmp = ResClass.GetImgRes("login_btn_focus");
this.Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Bmp = ResClass.GetImgRes("login_btn_down");
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Bmp = ResClass.GetImgRes("login_btn_normal");
if (this.Focused)
Bmp = ResClass.GetImgRes("login_btn_focus");
this.Invalidate();
}
}
}
鼠标经过时显示边框效果的CheckBox
![](http://static.oschina.net/uploads/img/201503/03144411_Hbuk.gif)
![](http://static.oschina.net/uploads/img/201503/03144411_ZtNr.gif)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SimpleIMClient.Skin;
namespace SimpleIMClient.Skin
{
[DefaultEvent("CheckedChanged")]
public partial class BasicCheckBox : UserControl
{
private Graphics g = null;
private bool m_Checked = false;
private string m_buttonText = "CheckBox";
public enum CheckStates { Unchecked, Checked, Indeterminate }
private CheckStates m_CheckState = CheckStates.Unchecked;
public delegate void CheckedChangedEventHandler(object sender, bool Checked);
public event CheckedChangedEventHandler CheckedChanged;
private Bitmap Bmp = null;
public BasicCheckBox()
{
if (Checked)
{
switch (CheckState)
{
case CheckStates.Checked:
Bmp = ResClass.GetImgRes("cb_c_l");
break;
case CheckStates.Indeterminate:
Bmp = ResClass.GetImgRes("cb_b_l");
break;
default:
Bmp = ResClass.GetImgRes("cb_c_l");
break;
}
}
else
{
Bmp = ResClass.GetImgRes("cb_n_l");
}
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.BackColor = Color.Transparent;
this.Size = new Size(95,20);
}
[Description("按钮上的文本"), Category("Appearance")]
public string Texts
{
get
{
return m_buttonText;
}
set
{
m_buttonText = value;
this.Invalidate();
}
}
[Description("是否选中"), Category("Appearance")]
public bool Checked
{
get
{
return m_Checked;
}
set
{
m_Checked = value;
if (value)
CheckState = CheckStates.Checked;
else
CheckState = CheckStates.Unchecked;
if (CheckedChanged != null)
CheckedChanged(this, value);
}
}
[Description("选中状态"), Category("Appearance")]
public CheckStates CheckState
{
get
{
return m_CheckState;
}
set
{
m_CheckState = value;
switch (value)
{
case CheckStates.Unchecked:
m_Checked = false;
Bmp = ResClass.GetImgRes("cb_n_e");
break;
case CheckStates.Checked:
m_Checked = true;
Bmp = ResClass.GetImgRes("cb_c_e");
break;
case CheckStates.Indeterminate:
m_Checked = true;
Bmp = ResClass.GetImgRes("cb_b_e");
break;
}
this.Invalidate(new Rectangle(0, (Height - 15) / 2, 15, 15));
}
}
protected override void OnPaint(PaintEventArgs e)
{
if (Bmp != null)
{
g = e.Graphics;
g.DrawImage(Bmp, new Rectangle(0, (this.Height - 15) / 2, 15, 15), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel);
g.DrawString(m_buttonText, this.Font, Brushes.Black, 16, (this.Height - 15) / 2);
}
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.MinimumSize = new Size(15, 15);
}
protected override void OnClick(EventArgs e)
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
protected override void OnDoubleClick(EventArgs e)
{
if (!Checked)
{
Checked = true;
}
else
{
Checked = false;
}
}
protected override void OnMouseEnter(EventArgs e)
{
if (Checked)
{
switch (CheckState)
{
case CheckStates.Checked:
Bmp = ResClass.GetImgRes("cb_c_e");
break;
case CheckStates.Indeterminate:
Bmp = ResClass.GetImgRes("cb_b_e");
break;
default:
Bmp = ResClass.GetImgRes("cb_c_e");
break;
}
}
else
{
Bmp = ResClass.GetImgRes("cb_n_e");
}
this.Invalidate(new Rectangle(0,(Height - 15)/2,15,15));
}
protected override void OnMouseLeave(EventArgs e)
{
if (Checked)
{
switch (CheckState)
{
case CheckStates.Checked:
Bmp = ResClass.GetImgRes("cb_c_l");
break;
case CheckStates.Indeterminate:
Bmp = ResClass.GetImgRes("cb_b_l");
break;
default:
Bmp = ResClass.GetImgRes("cb_c_l");
break;
}
}
else
{
Bmp = ResClass.GetImgRes("cb_n_l");
}
this.Invalidate(new Rectangle(0, (Height - 15) / 2, 15, 15));
}
}
}
我们看一下新的微风V3的UI
我们实现了登陆功能,注册新账号,找回密码等都没有实现,是原来UI 上面有的
聊天窗口:
支持更换皮肤
服务器端、数据库、通信框架没有变化,请去 微风IM V1,或 微风IM V2相关文章下载。
祝大家新年快乐
谢谢大家的支持
源码包含以下四个工程文件,通信框架需要另行下载
3.1版本已经发布
[c#源码]微风IM V3.1 支持TCP通信发送图片
微风IM3.2已发布
请见 [源码分享]微风IM 3.2 实现新用户注册 含详细过程
有朋友问性能的问题,请参见下面这篇文章