在微风 IM 版本2中我们实现了局域网内的p2p通信,具体见:
前面有朋友说微风IM的UI有点朴素,也确实,于是到网上去淘了件新衣服。
新的UI来自于网上开源程序,由“翱翔的雄鹰”老师编写的完全开源的QQ2010.(c# WinForm).新的UI中有许多自定义控件,我从其中学到了很多Winfrom控件制作的知识。
比如,带边框的文本框
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; } } } } }
鼠标经过时,显示边框的按钮
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
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相关文章下载。
微风IM V3客户端EXE文件
祝大家新年快乐
谢谢大家的支持
源码包含以下四个工程文件,通信框架需要另行下载
源码 ( 包含客户端与服务器端) 数据库下载
3.1版本已经发布
微风IM3.2已发布
请见 [源码分享]微风IM 3.2 实现新用户注册 含详细过程
有朋友问性能的问题,请参见下面这篇文章
NetworkComms通信框架 V3 性能测试