上一篇文章,我们搭建好了主界面的布局。本文将实现页面的交互逻辑,比如如何移动窗体、调整窗体大小、点击消息和联系人切换下方的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;

}

}

}

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

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

本文系小博客网站原创,转载请注明文章链接地址 查看更多内容请点击

delphi 登录界面 主窗体 切换_winform项目——仿QQ即时通讯程序06:主界面交互逻辑...相关推荐

  1. winform项目_winform项目——仿QQ即时通讯程序01:原理及项目分析

    即时通讯程序,腾讯QQ可以说是一家独大,虽然市场上仍然有类似QQ的即时通讯程序,但是基本上面向的对象都是特定人群.那么,现在做一个即时通讯的软件还有意义吗?在我看来,意义非常大.作为一个学习编程的人, ...

  2. c# webclient 保存会话信息_winform项目——仿QQ即时通讯程序16:会话列表的存储

    上一篇文章完成了验证消息的接收,这篇文章本打算做好友间互发消息,但是做的时候发现会话列表的存储还没做.就是会话列表中有会话的情况下,关闭了软件,然后再次登录后,应该要复现会话列表.因此本篇文章将实现会 ...

  3. .net winform panel 不刷新_winform项目——仿QQ即时通讯程序04:登录界面补充

    上一篇文章给出了Login登录界面的详细制作过程,目的是让初学者体验如何对窗体上的控件进行布局,过程非常详细,如果对winform布局不熟悉的同学可以详细阅读.本篇文章将继续完成Login窗体上的注册 ...

  4. winform服务器消息推送,winform项目——仿QQ即时通讯程序12:服务端程序补充及优化...

    原标题:winform项目--仿QQ即时通讯程序12:服务端程序补充及优化 上一篇文章大概完成了服务端程序,今天继续做项目的时候发现还有一些功能没有做,还有几处地方不够完善.不做好就会影响客户端程序的 ...

  5. 复习Java第二个项目仿QQ聊天系统 03(两种通信类、登录以及注册功能完善) Java面试题并发编程相关知识生活【记录一个咸鱼大学生三个月的奋进生活】025

    记录一个咸鱼大学生三个月的奋进生活025 复习Java(仿QQ聊天系统03两种通信类.登录以及注册功能完善) TcpSocket类(与服务器进行通信) Server类(服务器类) TcpMessage ...

  6. [go学习笔记.第十六章.TCP编程] 3.项目-海量用户即时通讯系统-redis介入,用户登录,注册

    1.实现功能-完成用户登录 在redis手动添加测试用户,并画出示意图以及说明注意事项(后续通过程序注册用户) 如:输入用户名和密码,如果在redis中存在并正确,则登录,否则退出系统,并给出相应提示 ...

  7. android 仿qq修改头像,Qt:小项目仿QQ修改头像界面,技术点记录

    最近写了一个修改头像功能的UI,布局参考了QQ目前的修改头像界面.如下图 这里主要说明一下两个地方的技术:1.头像图片上层的遮罩层,圆形外部为灰色,内部为全透明:2.上传图片宽高比例可以通过鼠标拖拽移 ...

  8. 高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框

    上一篇高仿QQ即时聊天软件开发系列之二登录窗口界面写了一个大概的布局和原理 这一篇详细说下拉框的实现原理 先上最终效果图 一开始其实只是想给下拉框加一个placeholder效果,让下拉框在未选择未输 ...

  9. delphi 登录界面 主窗体 切换_Python GUI项目实战(二)主窗体的界面设计与实现

    前言 上一节我们介绍了Python GUI项目实战(一)登录窗体的设计与实现,实现了该项目登录窗体的GUI的搭建,用户的账号和密码校验完成后应当跳转到主窗体界面,这一节我们将具体介绍主窗体界面的设计与 ...

最新文章

  1. 无痛涨点!大白话讲解 Generalized Focal Loss
  2. shell脚本按行读取文件的几种方式
  3. ORACEL游标的使用实例
  4. 蝴蝶优化算法_算法|FFT基础及各种常数优化,5万字笔记:公式推导+代码模板...
  5. ELK学习9_ELK数据流传输过程_问题总结2
  6. 树莓派运行python import os未找到命令_通过pip指令在树莓派上基于Python3安装OpenCV...
  7. 服务器select与gevent
  8. JSONOBject的fluentPut(key,value)方法:可链式设置元素
  9. 一个完整网页代码HTML和CSS,第一个网页(HTML/CSS)
  10. js实现删除文章弹窗提示是否确认
  11. cognos ibm 收购_IBM Cognos与Linux上的Sterling Selling and Fulfillment Suite集成
  12. 2022:中国存储的生死时速
  13. RocketMQ 5.0 POP消费模式
  14. 计算机无法正常更新,电脑时间不能自动更新怎么回事?电脑时间校准同步方法介绍...
  15. [CDQ][最小生成树]2018 [HNOI2010]CITY 城市建设
  16. 利用POI将PPT转换为图片
  17. python+qqbot实现qq聊天机器人
  18. 毕业了,开始新的生活!
  19. 计算机中丢失ucore46.dll,Creo6.0 Purge功能 如果试过各种方法还不能使用,可以试下这个方法...
  20. 对话V神:区块链跨链技术大规模应用将在一到两年内爆发

热门文章

  1. Python为给定模型执行留一法交叉验证实战LOOCV(leave-one-out cross-validation)
  2. python和R文件IO操作对比及dataframe创建方式对比:read_csv、to_csv、write.csv、 data.frame、pd.DataFrame
  3. 基准分类模型、分类应用(多分类数字识别、疾病预测、欺诈检测)、监督学习总结
  4. MultiBaC包消除不同组学数据之间的批次效应
  5. Android Studio下的目录结构
  6. Relation Networks for Object Detection
  7. flask 和 ajax 实例
  8. 图像拼接--Construction and Refinement of Panoramic Mosaics with Global and Local Alignment
  9. 腾讯云的Ubuntu 18.04的镜像地址
  10. LeetCode 319. Bulb Switcher--C++,java,python 1行解法--数学题