winform项目——仿QQ即时通讯程序06:主界面交互逻辑

编程项目2019/12/15 13:12:59阅读:916

上一篇文章,我们搭建好了主界面的布局。本文将实现页面的交互逻辑,比如如何移动窗体、调整窗体大小、点击消息和联系人切换下方的panel面板、动态加载消息列表panel和好友列表panel等,并且左下角的按钮改成了添加好友的入口。

上部分

移动窗体

因为设置FormBorderStyle属性为None,所以目前无法移动窗体,要通过代码的方式移动。

鼠标按住窗体上部分移动窗体

要实现这个效果,需要使用上面面板splitContainer1_Panel1的三个事件:MouseDown、MouseMove、MouseUp。具体实现过程:

1.定义两个本地变量

private Point mousepoint;//鼠标的位置

private bool mouseflag = false;//鼠标是否按下的标志

2.实现三个事件

private void splitContainer1_Panel1_MouseDown(object sender, MouseEventArgs e)

{

if (e.Button == MouseButtons.Left)

{

mousepoint.X = e.X;

mousepoint.Y = e.Y;

mouseflag = true;

}

}

private void splitContainer1_Panel1_MouseMove(object sender, MouseEventArgs e)
{
if (mouseflag)
{
this.Left = MousePosition.X - mousepoint.X;
this.Top = MousePosition.Y - mousepoint.Y;
}
}

private void splitContainer1_Panel1_MouseUp(object sender, MouseEventArgs e)
{
mouseflag = false;
}

这样就可以实现按住上部分移动窗体。

调整窗体大小

通过对窗体边缘进行判断,配合鼠标事件,可以完成调整窗体大小的操作。注意,此时窗体的padding值为6。此法也是参考网友的方法,并进行了优化。下面便是放大的窗体效果:

放大的效果

调整Major窗体大小

第一步,定义枚举,表示拖动方向

public enum MouseDirection
{
Herizontal,//水平方向拖动,只改变窗体的宽度

Vertical,//垂直方向拖动,只改变窗体的高度

Declining,//倾斜方向,同时改变窗体的宽度和高度

None//不做标志,即不拖动窗体改变大小
}

第二步,添加四个全局变量

bool isMouseDown = false; //表示鼠标当前是否处于按下状态,初始值为否

MouseDirection direction = MouseDirection.None;//表示拖动的方向,起始为None,表示不拖动

Point mouseOff;//鼠标移动位置变量

bool declinning = false;//宽高同时拖动时的标志

第三步,鼠标按下事件

private void Major_MouseDown(object sender, MouseEventArgs e)
{
mouseOff = new Point(-e.X, -e.Y); //记录鼠标位置
//当鼠标的位置处于边缘时,允许进行改变大小。
if (e.Location.X >= this.Width - 10 && e.Location.Y > this.Height - 10)
{
isMouseDown = true;
}
else if (e.Location.X >= this.Width - 10)
{
isMouseDown = true;
}
else if (e.Location.Y >= this.Height - 10)
{
isMouseDown = true;
}
else
{
this.Cursor = Cursors.Arrow;//改变鼠标样式为原样
isMouseDown = false;
}
}

第四步:鼠标移动事件

private void Major_MouseMove(object sender, MouseEventArgs e)
{
//鼠标移动到边缘,改变鼠标的图标
if (e.Location.X >= this.Width - 2 && declinning == false)
{
this.Cursor = Cursors.SizeWE;
direction = MouseDirection.Herizontal;
}
else if (e.Location.Y >= this.Height - 2 && declinning == false)
{
this.Cursor = Cursors.SizeNS;
direction = MouseDirection.Vertical;
}
else
{
this.Cursor = Cursors.Arrow;
}
if (e.Location.X >=this.Width-10&& e.Location.Y >= this.Height - 4)
{
this.Cursor = Cursors.SizeNWSE;
direction = MouseDirection.Declining;
declinning = true;
}
else
{
declinning = false;
}


//设定好方向后,调用下面方法,改变窗体大小
ResizeWindow();
}

private void ResizeWindow()
{
if (!isMouseDown)
return;

if (direction == MouseDirection.Herizontal)
{
this.Cursor = Cursors.SizeWE;
this.Width = MousePosition.X - this.Left + 1;//改变宽度
}
else if (direction == MouseDirection.Vertical)
{
this.Cursor = Cursors.SizeNS;
this.Height = MousePosition.Y - this.Top + 1;//改变高度
}else if(direction == MouseDirection.Declining)
{
this.Cursor = Cursors.SizeNWSE;
this.Width = MousePosition.X - this.Left + 1;//改变宽度
this.Height = MousePosition.Y - this.Top + 1;//改变高度
}
//鼠标不在窗口右和下边缘,把鼠标变回小箭头
else
{
this.Cursor = Cursors.Arrow;
isMouseDown = false;
}
}

第五步,鼠标松开事件

private void Major_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
declinning = false;
direction = MouseDirection.None;
if (isMouseDown)
isMouseDown = false;
}

根据这五步,就可以实现窗体大小的调整,再配合设置窗体的宽度、高度限制,可以满足CIM主窗体的需求。

切换消息和联系人面板

实现消息和联系人label的点击事件,配合下方panel的visible属性就可以实现。重要的是下面的动态加载一个个会话panel和一个个联系人panel。

切换到联系人

切换两个大panel

注意我的代码里都已经给控件改了Name属性的值了。比如会话列表的大panel改成了leftPanel。

1.消息panel的点击事件

private void changeLeftButton_Click(object sender, EventArgs e)

{

//打开左边panel,关闭右边panel

leftPanel.Visible = true;

rightPanel.Visible = false;

//改变下方指示线的颜色

left_line.BackColor = Color.YellowGreen;

right_line.BackColor = Color.Transparent;

}

2.联系人panel的点击事件

private void changeRightButton_Click(object sender, EventArgs e)
{
//打开右边panel,关闭左边panel
leftPanel.Visible = false;
rightPanel.Visible = true;
//改变下方指示线的颜色
left_line.BackColor = Color.Transparent;
right_line.BackColor = Color.YellowGreen;
}

动态加载控件

因为一个会话列表就是一个小的panel,上面有多个控件,所以需要动态加载它们,并放到外层的大panel中显示。

动态加载

动态加载会话小panel

我们在窗体的load事件中模拟加载100个会话

private void Major_Load(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
loadtalk(i,loadTalkMessageList());
}
}

///


/// 填充会话列表对象到list
///

///
private List loadTalkMessageList()
{
return null;
}

///


/// 加载会话列表
///

/// 会话列表的个数
/// 会话列表实体对象list

private void loadtalk(int talknum,List talkMessage)
{
//模拟加载会话列表
Panel talkPanel = new Panel();
talkPanel.Anchor = ((AnchorStyles.Top | AnchorStyles.Left)
| AnchorStyles.Right);
talkPanel.Size = new Size(346, 58);
talkPanel.Location = new Point(3, talknum*58);
talkPanel.MouseEnter += TalkPanel_MouseEnter;
talkPanel.MouseLeave += TalkPanel_MouseLeave;
//头像
PictureBox pb = new PictureBox();
pb.Size = new Size(35, 35);
pb.Location = new Point(8, 11);
pb.Image = Properties.Resources.知了;
pb.SizeMode = PictureBoxSizeMode.StretchImage;
pb.MouseEnter += TalkPanel_MouseEnter;
pb.MouseLeave += TalkPanel_MouseLeave;
talkPanel.Controls.Add(pb);
//昵称
Label nickname = new Label();
nickname.AutoSize = true;
nickname.Font = new Font("微软雅黑", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134)));
nickname.Location = new Point(56, 10);
nickname.Text = "小龙虾";
nickname.MouseEnter += TalkPanel_MouseEnter;
nickname.MouseLeave += TalkPanel_MouseLeave;
talkPanel.Controls.Add(nickname);
//消息
Label message = new Label();
message.AutoSize = true;
message.ForeColor = SystemColors.ControlDarkDark;
message.Location = new Point(58, 34);
message.Size = new Size(277, 15);
message.Text = "上课了好呀";
message.MouseEnter += TalkPanel_MouseEnter;
message.MouseLeave += TalkPanel_MouseLeave;
talkPanel.Controls.Add(message);
//时间
Label time = new Label();
time.Anchor = ((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
time.AutoSize = true;
time.ForeColor = SystemColors.ControlDarkDark;
time.Location = new Point(220, 11);
if (talknum > 5)
{
time.Location = new Point(204, 11);
}
time.Text = "18:48";
time.MouseEnter += TalkPanel_MouseEnter;
time.MouseLeave += TalkPanel_MouseLeave;
talkPanel.Controls.Add(time);
leftPanel.Controls.Add(talkPanel);
}

private void TalkPanel_MouseLeave(object sender, EventArgs e)
{
if (sender is Panel)
{
((Panel)sender).BackColor = Color.Transparent;
}
else
{
((Control)sender).Parent.BackColor = Color.Transparent;
}
}

private void TalkPanel_MouseEnter(object sender, EventArgs e)
{
if(sender is Panel)
{
((Panel)sender).BackColor = Control.DefaultBackColor;
}
else
{
((Control)sender).Parent.BackColor = Control.DefaultBackColor;
}
}

注意loadtalk这个函数的参数,第一个只是临时测试用的,第二个才是主要的,后面加载数据会用到。动态加载控件最重要的调整控件位置和大小,也就是Size和Location属性,这两个值需要从事先设计好的界面中获取,但是动态生成的和事先设计好的不一样,动态生成的位置会有差距,需要开发者手动调节。注意if(talknum > 5)这个判断,因为到第7个的时候,大panel不能容纳生成的小panel了,time控件的位置又不一样了,所以需要特殊处理。

还有,loadTalkMessageList这个方法也是后面加载数据时才实现的,这里需要定义TalkMessage实体模型,在项目里面,添加这个类,并加上三个属性。

internal class TalkMessage

{

private string _NickName;

private string _SubMessage;

private string _Time;

public string NickName

{

get

{

return _NickName;

}

set

{

_NickName = value;

}

}

public string SubMessage

{

get

{

return _SubMessage;

}

set

{

_SubMessage = value;

}

}

public string Time

{

get

{

return _Time;

}

set

{

_Time = value;

}

}

}

加载会话和加载好友列表原理是一样的,代码也非常相似,只不过是改改变量名称、添加不同的实体列,这里就不再多数,读者请自行实现动态添加好友列表。

到这里,主界面的逻辑交互就全部实现了。还缺的就是数据了,等到后面实现功能的时候再细论。下一篇文章将介绍其余的窗体。当然,有了这篇文章的铺垫,其余窗体将会非常好搭建。


本文系小博客网站原创,转载请注明文章链接地址