过qq的同学都知道,qq主窗口在靠近界面边缘时会自动隐藏,而当鼠标再一次进入的时候会自动弹出,接下来我将记录下自己实现的类似同样的功能,支持多屏幕靠边隐藏。文章末尾我提供了demo的下载地址,这个样例我是从网上下载下来,并自己进行了优化,主要针对边界判断和多屏幕支持。
下面是我做的效果展示,由于录屏软件录制屏幕顶端不好录制,所以录制了屏幕左侧,我自己测试的结果是:屏幕左、屏幕上和屏幕右都没有问题。如果发现问题的同学可以联系我。
效果预览
接下来我将每一步的实现代码分别做以解释:
一、窗口移动
做windows桌面程序的同学,应该都会这个功能,不过我还是贴一下代码吧,虽然不是特别复杂。要实现这个功能只需要重写3个方法,分别是:mousePressEvent、mouseMoveEvent和mouseReleaseEvent。
1、mousePressEvent
1 void FloatingWidget::mousePressEvent(QMouseEvent *e)
2 {
3 if (e->button()==Qt::LeftButton)
4 {
5 m_dragPosition=e->globalPos() - frameGeometry().topLeft();
6 e->accept();
7 }
8 }
2、mouseMoveEvent
1 void FloatingWidget::mouseMoveEvent(QMouseEvent * event)
2 {
3 if (event->buttons() & Qt::LeftButton)
4 {
5 QPoint pos=event->globalPos() - m_dragPosition;
6
7 QDesktopWidget * desktop=qApp->desktop();
8 QRect rect=desktop->screenGeometry(QCursor::pos());
9 QRect frameRect=frameGeometry();
10 if (rect.top() >=pos.y())//修正顶端位置
11 {
12 pos.setY(rect.top());
13 }
14
15 if (rect.left()>=pos.x())//修正左侧位置
16 {
17 int leftScreenNumber=desktop->screenNumber(pos - QPoint(width(), 0));
18 if (desktop->screenGeometry(leftScreenNumber).contains((pos - QPoint(width(), 0)))==false)
19 {
20 pos.setX(rect.left());
21 }
22 }
23
24 if (rect.right() <=pos.x() + frameRect.width())//修正右侧位置
25 {
26 int rightScreenNumber=desktop->screenNumber(pos + QPoint(width(), 0));
27 if (desktop->screenGeometry(rightScreenNumber).contains((pos + QPoint(width(), 0)))==false)
28 {
29 pos.setX(rect.right() - frameRect.width());
30 }
31 }
32 move(pos);
33
34 event->accept();
35 }
36 }
这个函数里有3个位置修正判断,主要实现了在鼠标拖拽时,保证窗口不移出屏幕。
3、mouseReleaseEvent
1 void FloatingWidget::mouseReleaseEvent(QMouseEvent * event)
2 {
3 QWidget::mouseReleaseEvent(event);
4 }
通过上述3个方式的重写,就实现了窗口的拖拽,并且我们的窗口是不能拖拽到屏幕意外
二、屏幕边界自动隐藏
窗口移动到屏幕边界时,自动隐藏我们的窗口,首先我们来考虑这么几个问题:
1、什么时候需要隐藏窗口
2、什么时候需要显示窗口
3、检测窗口是否需要隐藏
4、窗口显示时怎么回到起始位置
问题1:隐藏窗口在我们鼠标移除窗口的时候,这个时候需要注意,鼠标在屏幕边界时不能隐藏
问题2:鼠标进入到我们的窗口时
问题3:窗口的边界和屏幕对应(比如:窗口左边界对应屏幕左边界)边界如果距离小于我们制定的边界检测宽度则可以隐藏
问题4:记录平路隐藏时的位置,方便回显回去
搞清楚上述4个问题后,我们就来贴代码吧
1、首先是窗口隐藏
1 void FloatingWidget::leaveEvent(QEvent * e)
2 {
3 QPoint mousePos=mapFromGlobal(QCursor::pos());
4 if (rect().contains(mousePos)==false
5 && mousePos.x() !=rect().width())
6 {
7 HideDockWidget();
8 }
9 else
10 {
11 if (m_timer==nullptr)
12 {
13 m_timer=new QTimer(this);
14 connect(m_timer, &QTimer::timeout, this, [this]{
15 QPoint mousePos=mapFromGlobal(QCursor::pos());
16 if (this->rect().contains(mousePos)==false
17 && mousePos.x() !=rect().width())
18 {
19 HideDockWidget();
20 }
21 });
22 }
23 m_timer->start(500);
24 }
25
26 QWidget::leaveEvent(e);
27 }
鼠标移出窗口时,需要隐藏窗口,首先判断鼠标是否还在窗口内,包括窗口边界,如果在窗口内,则开启定时器,每隔500毫秒检测鼠标是否还在屏幕内,因为leaveEvent事件和enterEvent是成对出现的,当leaveEvent发生一次后,除非enterEvent触发,否则不会触发;如果不在窗口内,直接去隐藏窗口。
点击领取Qt学习资料+视频教程~「链接」
2、显示窗口
显示窗口就比较好理解了,只需要在鼠标进入窗口时,如果窗口之前隐藏了,则把窗口恢复到之前隐藏的位置
1 void FloatingWidget::enterEvent(QEvent * e)
2 {
3 if (m_timer && m_timer->isActive())
4 {
5 m_timer->stop();
6 }
7
8 ShowDockWidget();
9
10 QWidget::enterEvent(e);
11 }
3、检测窗口是否需要隐藏
1 void FloatingWidget::HideDockWidget()
2 {
3 if (m_IsVisible==false)
4 {
5 return;
6 }
7
8 m_IsVisible=false;
9
10 int curHeight=height();
11 int curWidth=width();
12
13 QDesktopWidget * desktop=qApp->desktop();
14 QRect rect=desktop->screenGeometry(this);
15
16 if (frameGeometry().left() - CHECK_BORDER <=rect.top()
17 && TEST_BIT(m_feature, LeftArea))
18 {
19 MoveWindow(pos(), pos() - QPoint(curWidth - HIDE_BORDER, 0));
20 }
21 else if (frameGeometry().right() + CHECK_BORDER >=rect.right()
22 && TEST_BIT(m_feature, RightArea))
23 {
24 MoveWindow(pos(), pos() + QPoint(curWidth - HIDE_BORDER, 0));
25 }
26 else if (frameGeometry().top() - CHECK_BORDER <=rect.top()
27 && TEST_BIT(m_feature, TopArea))
28 {
29 MoveWindow(pos(), pos() - QPoint(0, curHeight - HIDE_BORDER));
30 }
31 else
32 {
33 m_IsVisible=true;
34 }
35
36 if (m_IsVisible==false)
37 {
38 if (m_timer && m_timer->isActive())
39 {
40 m_timer->stop();
41 }
42 }
43 }
4、窗口回显到起始位置
1 void FloatingWidget::ShowDockWidget()
2 {
3 if (m_IsVisible)
4 {
5 return;
6 }
7
8 m_IsVisible=true;
9
10 int curHeight=height();
11 int curWidth=width();
12
13 QDesktopWidget * desktop=qApp->desktop();
14 QRect rect=desktop->screenGeometry(this);
15 QRect frameRect=frameGeometry();
16
17 if (frameRect.left()==m_RecoverPosition.x() - (curWidth - HIDE_BORDER)
18 && TEST_BIT(m_feature, LeftArea))
19 {
20 MoveWindow(pos(), m_RecoverPosition);
21 }
22 else if (frameRect.left()==m_RecoverPosition.x() + (curWidth - HIDE_BORDER)
23 && TEST_BIT(m_feature, RightArea))
24 {
25 MoveWindow(pos(), m_RecoverPosition);
26 }
27 else if (frameRect.top()==m_RecoverPosition.y() - (curHeight - HIDE_BORDER)
28 && TEST_BIT(m_feature, TopArea))
29 {
30 MoveWindow(pos(), m_RecoverPosition);
31 }
32 else
33 {
34 m_IsVisible=false;
35 }
36 }
5、最后是窗口移动算法
1 void FloatingWidget::MoveWindow(const QPoint & start, const QPoint & end, unsigned int step)
2 {
3 QPoint distance=end - start;
4 QPoint stepPos, stepOne;
5 if (end.x()==start.x())
6 {
7 stepOne.setY(step * (distance.y() > 0 ? 1 : -1));
8 }
9 else
10 {
11 stepOne.setX(step * (distance.x() > 0 ? 1 : -1));
12 }
13 stepPos=stepOne;
14
15 int disLenght=distance.manhattanLength();
16 while (stepPos.manhattanLength() <=disLenght)
17 {
18 move(start + stepPos);
19 stepPos +=stepOne;
20 }
21
22 move(end);
23
24 m_RecoverPosition=start;
25 }
参数分别是:起始位置、终点位置和每次移动距离
转载:https://www.cnblogs.com/swarmbees/p/5926144.html
作者:朝十晚八 or Twowords
.结构标记:作用就是为了提升标记的语义性,每个结构有每个不同的标记。
1.头部标记:<header></header>,用于定义页面的页眉,最上面的内容。等同于<div id="header"></div>,作用一样。就是相当于一个容器,装其他的元素。
2.导航标记:<nav></nav>,用于定义页面的导航链接部分。等同于<div id="nav"></div>
例如可以这样写导航:
<nav>
<ul>
<li></li>
</ul>
</nav>
3.主体标记:<section></section>作用:定义页面主体内容中的小节,现在section可以表示整个页面的主体内容等同于<div id="main"></div>
4.<article></article>作用:用于描述文本性较强,或者艺术气息较强的内容。一般情况下,论坛中的帖子信息,报纸信息,博客或微博中的条目信息。用户回复信息,有限考虑放在article中
5.<footer></footer>定义页面中或某个区域中的脚注信息,页面最底部的信息。
6.边栏:<aside></aside>定义页面侧边栏,靠边的信息
以上结构标记为的就是独立定义结构,替代div。
表单
表单的作用:显示,收集信息,并且将信息提交给服务器
(在注册,登陆的时候,网页就会提供一些供用户填写的表单,表单元素会把填写的信息提交服务器进行处理 )
表单包含两组内容
1.表单元素<form>
<form></form>
注意:使用表单控件提交数据时,表单不能省略
属性:
1.action:后台处理程序的地址(服务器端工程师提供),默认会提交给本页。
2.method:方式,表单的提交方式。不同的提交方式约束的内容不一样。
常用取值:2个
get:
1.显示提交数据,会将提交信息显示在地址栏上面,安全性不高,又叫显示提交
2.大小限制,最大支持到2kb的提交。
3.如果不设置method属性,默认就是get方式提交(显示提交,最大2kb)
4.使用场合:向服务器索取数据时,优先使用get
post:
1.隐式提交数据,不会将提交的信息显示在地址栏上,安全性较高,所有有关密码的信息提交时,必须用post
2.post没有大小限制。
3.使用场合:安全性要求较高的页面,传递数据量较大的时候
3.enctype
作用:设置对表单中提交的数据的编码方式,规范哪些数据可以提交给服务器
取值:
1.application/x-www-form-urlencoded,默认值,可以将普通的文本,特殊的字符,一起提交给服务器。
2.multipart/form-date,允许将表单中的文件,传递给服务器,普通文本不能直接传递。
3.text/plain,只能将普通文本传递给服务器,特殊字符不允许。
4.id
5.name
2.表单控件
什么是表单控件
包含在表单中的元素,具备可视化外观,并且可以接受用户输入的数据。
分类
1.input元素
2.textare文本域
3.select和option选项框
一.input元素,主要作用就是收集用户信息
语法:<input>
属性:
type,根据不同的类型值可以创建不同的输入控件,用户名,密码,按钮形式的
value,控件的值,提交给服务器的数据。
name,控件的名称。必须设置,否则无法提交,服务器主要根据name这个控件的名称,来获取value
disabled,禁用控件,该属性可以没有值。
1.文本框和密码框
文本框:<input type="text">
允许用户输入任意字符的数据,明文显示
密码框:<input type="password">
允许用户输入任意字符的数据,密文显示
属性:
maxlength:限制输入的字符数
readonly:只读,无需给值
value:控件值,同时也可以设置控件
注意:input元素下,如果不写type值,或者type值写错时,都默认为文本框。
单选框和复选框
1.单选框:<input type="radio">
属性:
1.name:定义名称并且实现控件分组,一组内的元素才能实现单选
2.value:控件值
3.checked:设置默认被选中,不需要值
2.复选框
<input type="checkbox">
属性:name:定义名称并且分组,便于服务器获取
3.按钮
1.提交按钮,功能固定化,负责将数据提交给服务器
<input type="submit">
2.重置按钮,功能固定化,负责将表单控件恢复到初始化的状态
<input type="reset">
3.普通按钮,没有固定功能,由开发者通过js来设置。
<input type="button">
value:显示在按钮上的文本
name:名称(可写可不写)
4.非input标签的按钮
<button></button>
<button type="button">普通按钮</button>
属性:type
5.隐藏域和文件选择框
1。隐藏域,不想让用户看见,但是又要提交到服务器的数据,可以放在隐藏域中
例如:隐藏用户id
type="hidden"
<input tpe="hidden">
属性:
name
value
6.文件选择框
提供一个基础控件,允许用户选择本机的文件上传到服务器
type="file"
<input type="file">
属性:name value
注意:
表单的method(提交方式)属性值必须为post
表单的enctype编码必须为multipart/form-date
更多知识关注小编,或者百度网络营销师钟震,钟震讲网络营销。会有很多相关知识,公众号网络营销师钟震,以后每天都会分享web前端,淘宝运营,竞价,网站建设和优化,社媒方面的知识。与大家共同进步。希望对您有一点点帮助,喜欢记得关注公众号。
控制一个元素的显示方式,我们可以使用display:block;display:inline-block;display:none;其中布局相关的还有两个很重要的属性:display:flex;和display:grid;flex表示弹性盒子,grid表示网格;
我们使用一个三例的布局为例来试一下:
display:flex;
<html>
<head>
<title>css</title>
</head>
<body>
<div style="height: 900px;">
<div style="width: 100%;height:100px;background:grey">我是头部</div>
<div style="display: flex;height: 100%;">
<div style="width: 100px;height: 100%;background:yellow;">左侧</div>
<div style="width:100%;background:burlywood">中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间</div>
<div style="width: 100px;height: 100%;background:yellow;">右侧</div>
</div>
</div>
</body>
</html>
<html>
<head>
<title>css</title>
</head>
<body>
<div class="container">
<div class="item">flex1</div>
<div class="item">flex2</div>
<div class="item">flex3</div>
<div class="item">flex4</div>
<div class="item">flex5</div>
<div class="item">flex6</div>
<div class="item">flex7</div>
<div class="item">flex8</div>
</div>
</body>
<style>
.container{
display: flex;
width:600px;
height: 900px;
background:grey;
flex-direction: row; /** 设置排列的方式 row 横向 row-reverse 横向反转 column 纵向 column-reverse*/
justify-content: flex-start; /** 设置每一个列的对齐方向 flex-start靠左排开,flex-end靠右排列,center居中排列,space-between左右靠边平均对齐,space-around */
flex-wrap: wrap;/***是否换行 wrap换行,nowrap不换行,wrap-reverse倒序换行*/
align-content: flex-start; /**用于设置各行之间如何对齐*/
align-items:flex-start; /**设置纵向的排列方式*/
}
.item{
width: 100px;
height: 100px;
margin: 10px;
background:yellow;
}
</style>
</html>
注:以下的属性设置大家可以去尝试一下。
flex-direction: row; /** 设置排列的方式 row 横向 row-reverse 横向反转 column 纵向 column-reverse*/
justify-content: flex-start; /** 设置每一个列的对齐方向 flex-start靠左排开,flex-end靠右排列,center居中排列,space-between左右靠边平均对齐,space-around */
flex-wrap: wrap;/***是否换行 wrap换行,nowrap不换行,wrap-reverse倒序换行*/
align-content: flex-start; /**用于设置各行之间如何对齐*/
align-items:flex-start; /**设置纵向的排列方式*/
display:grid:
<html>
<head>
<title>css</title>
</head>
<body>
<div style="height: 900px;">
<div style="width: 100%;height:100px;background:grey">我是头部</div>
<div style="display: grid;height: 100%;grid-template-columns: 100px auto 100px;">
<div style="background:yellow">左侧</div>
<div style="background:burlywood">中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间中间</div>
<div style="background:yellow">右侧</div>
</div>
</div>
</body>
</html>
以上我们只是用一个三例布局讲了一下基本的内容,这里布局还有很多属性,大家可以去试一下。一定得看,哪怕你不去手写,也要看一下那些属性的作用,因为这块太重要了,但是属性又太多了,要写起来可劲得写了,大家看不明白的,可以给我留言,我会看到给大家回复的!
浮动属性float会使元素脱离文档流,使其他内容重新排列,我们常见的文字环绕效果可以使用浮动来实现:
<html>
<head>
<title>css</title>
</head>
<body>
<div>
<div style="width: 100px;height:100px;padding:50px;border:1px solid black;float:left;left:0px;top:0px;">浮动</div>
<div>显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容
显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容
显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容
显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容显示内容内容
</div>
</div>
</body>
</html>
我们缩小一下窗口就能看到效果。
注:布局属性很重要,大家一定要去看,去写!
*请认真填写需求信息,我们会在24小时内与您取得联系。