继续上一章的360新特性界面。源代码:http://download.csdn.net/detail/zhangyang1990828/5241242

上一章中实现了整个界面的纯UI设计,这次我们让它生动起来。

QT学习(五)

首先让“360安全桌面”“木马防火墙”..这四个按钮“动”起来。

让这个按钮有几种状态:

①鼠标进入时变成低亮高透明

②鼠标离开时恢复原状

③鼠标点击后变成高亮低透明

为了实现这几种状态,需要三个事件和两个变量:

enterEvent(QEvent* e);

leaveEvent(QEvent* e);

mousePressEvent(QMouseEvent* e);

m_mousePressFlag;

m_mouseEnterFlag;

通过这三个事件和两个变量,就可以实现按钮的几种状态了。(还需要通过信号槽来实现只有一个按钮被选中)

代码:

  1. connect(label, SIGNAL(signalLabelPress(CLabel*)), this, SLOT(slotLabelButtonPress(CLabel*)));
  1. void DataBrain::slotLabelButtonPress(CLabel *label)
  2. {
  3. for (int i = 0; i < WINDOW_BUTTON_COUNT; i++)
  4. {
  5. if (label != m_pLabelBtnArray[i])
  6. {
  7. m_pLabelBtnArray[i]->setMousePressFlag(false);
  8. }
  9. }
  10. }
  1. //按钮特效
  2. void CLabel::setMouseEnterFlag(bool flag)
  3. {
  4. m_mouseEnterFlag=flag;
  5. this->update();
  6. }
  7. void CLabel::setMousePressFlag(bool flag)
  8. {
  9. m_mousePressFlag=flag;
  10. this->update();
  11. }
  12. bool CLabel::getMouseEnterFlag()
  13. {
  14. return m_mouseEnterFlag;
  15. }
  16. bool CLabel::getMousePressFlag()
  17. {
  18. return m_mousePressFlag;
  19. }
  20. void CLabel::enterEvent(QEvent *e)
  21. {
  22. if(!getMousePressFlag())
  23. {
  24. setMouseEnterFlag(true);
  25. }
  26. this->setCursor(Qt::PointingHandCursor);//设置鼠标的形状
  27. }
  28. void CLabel::leaveEvent(QEvent *e)
  29. {
  30. setMouseEnterFlag(false);
  31. }
  32. void CLabel::mousePressEvent(QMouseEvent *e)
  33. {
  34. if(e->button()==Qt::LeftButton)
  35. {
  36. setMousePressFlag(true);
  37. emit signalLabelPress(this);
  38. }
  39. }

效果图:

ok!我们继续来实现右上角关闭按钮的动态的效果。

和上面的相同,关闭的按钮也是需要三个状态:

①鼠标进入时

②鼠标离开时

③鼠标点击后

不同的是,关闭按钮不是对按钮设置样式,而是对它进行更换图片。

这里值得一提的是,这里用的eventFilter(事件过滤器),对某个控件install一个eventFiler后,可以在eventFilter的事件中通过传递进来的两个参数(QObject*,QEvent*)来对事件进行控制。

十分简单,上代码:

  1. //关闭按钮的效果
  2. void DataBrain::createEventFilter()
  3. {
  4. m_pCloseBtn->installEventFilter(this);
  5. }
  6. bool DataBrain::eventFilter(QObject *target , QEvent *event)
  7. {
  8. EButtonMouseState state=EButtonMouseNone;
  9. if(target==m_pCloseBtn)
  10. {
  11. if(event->type()==QEvent::Enter)
  12. {
  13. state=EButtonMouseEnter;
  14. }
  15. else if(event->type()==QEvent::Leave)
  16. {
  17. state=EButtonMouseDefault;
  18. }
  19. else if(((QMouseEvent*)event)->button()==Qt::LeftButton)
  20. {
  21. if(event->type()==QEvent::MouseButtonPress)
  22. {
  23. state=EButtonMousePress;
  24. }
  25. else if (event->type()==QEvent::MouseButtonRelease)
  26. {
  27. state = EButtonMouseEnter;
  28. }
  29. }
  30. if(state!=EButtonMouseNone)
  31. {
  32. setButtonIcon((QToolButton*)target,state);
  33. }
  34. }
  35. return QWidget::eventFilter(target, event);
  36. }
  37. void DataBrain::setButtonIcon(QToolButton *btn, EButtonMouseState state)
  38. {
  39. QPixmap pixmap(":/images/images/btn_close.png");
  40. int nWidth = pixmap.width()/4;
  41. int nHeight = pixmap.height();
  42. btn->setIcon(QIcon(pixmap.copy(QRect(state*nWidth, 0, nWidth, nHeight))));
  43. btn->setIconSize(QSize(nWidth, nHeight));
  44. }
  1. connect(m_pCloseBtn,SIGNAL(clicked()),qApp,SLOT(quit()));//给按钮加上关闭程序的功能

效果图:


最后来实现窗口的推拽功能(点击串口上的一部分内可以拖动窗口)和主页面选择页的拖拽(页面选择以及按钮选择的变换)

这里是整个设计中最复杂的地方!

首先需要先确定要完成窗口拖拽和主页面选择需要抽象出几个方法,怎样划分这些方法

①鼠标被按下事件mousePressEvent,在这里需要去判断鼠标的左键和右键,左键的话按下的区域是在窗口拖拽区还是在主页选择区,这里需要注意的是,关闭按钮也在窗口拖拽区,需要在关闭按钮的的点击事件将窗口拖拽的flag设置成false。完成这个类需要m_mouseMoveWindowFlag(窗口是否能被拖拽的flag),m_mousePressFlag(主窗口能否被拖拽的flag)两个flag;右键的话判断当前的主页面是否能向左滚动,需要setLabelMove和getLabelMove进行设置和读取m_labelMoveFlag来对主页面能被向左移还是向右移进行flag。m_labelMoveFlag=flase能向右移不能向左移,m_labelMoveFlag=true能向左移不能向右移。(这里的左移和右移指的是整页的移动)

②鼠标移动的事件mouseMoveEvent,在这里需要进行判断m_mouseMoveWindowFlag和m_mousePressFlag,通过这两个标识去完成是进行窗口的移动还是主页面的拖拽。(这里需要注意的是,这里的移动是拖拽,需要进行不断的事件响应,才能出现拖拽的效果。)

③鼠标的按键释放事件mouseReleaseEvent,在这里需要对m_mouseMoveWindowFlag和m_mousePressFlag进行判断,看刚结束的鼠标按键按下和释放过程中做了什么,如果m_mousePressFlag=true,则干才进行了主页面的拖拽,需要通过鼠标按键按下时鼠标的坐标和释放时鼠标的坐标来进行判断鼠标拖拽的方向,再通过moveCurrentPage(整页移动的函数)来完成页面的滚动;如果m_mousePressFlag=false,则刚才进行了窗口移动事件,需要在这里重新将m_mouseMoveWindowFlag设置成false。

③整页移动的函数moveCurrentPage,通过起始点的坐标和终点的坐标来判断滚动的方向。如果没有鼠标的拖动,而是通过鼠标右键或者快捷键来实现的页面滚动,则直接进行页面滚动。

④拖拽主页面到新的页面时,需要用改变当前选择按钮的函数changeCurrentButton,需要在这里调用CButton的setMousePressFlag函数重新对选中按钮进行设定。

⑤slotChangeCurrentPage函数,需要对点击按钮的事件进行响应,点击按钮则主页面进行响应的滚动

⑥快捷键的响应keyPressEvent,这里对快捷键进行设置。

OK!明白了以上的就可以了,代码:

  1. //窗口拖拽
  2. void DataBrain::mousePressEvent(QMouseEvent *e)
  3. {
  4. if(e->button()==Qt::LeftButton)
  5. {
  6. m_mouseSrcPos=e->pos();
  7. if(m_mouseSrcPos.y()<=40)
  8. {
  9. m_mouseMoveWindowFlag=true;
  10. }
  11. else
  12. {
  13. m_currentFgXpos=m_pLabelFg->x();
  14. m_mousePressFlag=true;
  15. }
  16. }
  17. //右键左移
  18. else if(e->button()==Qt::RightButton)
  19. {
  20. if(getLabelMove())
  21. {
  22. if(m_currentFgIndex>0)
  23. {
  24. m_currentFgIndex--;
  25. moveCurrentPage(false);
  26. }
  27. }
  28. }
  29. }
  30. inline void DataBrain::setLabelMove(bool enable)
  31. {
  32. m_labelMoveFlag = enable;
  33. }
  34. inline bool DataBrain::getLabelMove()
  35. {
  36. return m_labelMoveFlag;
  37. }
  38. void DataBrain::moveCurrentPage(bool direction)
  39. {
  40. int currentXpos = 0;//当前label的x坐标
  41. int destXpos = 0;//目标x坐标
  42. //改变当前页面对应的按钮
  43. changeCurrentButton();
  44. //图片的几个分割点
  45. //0-680, 680-1360, 1360-2040, 2040-2720
  46. //真:向左移;  假:向右移
  47. if (direction)
  48. {
  49. //左移的几种可能性,对于x坐标
  50. //index=0, 将label移动到-680*0
  51. //index=1, 将label移动到-680*1
  52. //index=2, 将label移动到-680*2
  53. //index=3, 将label移动到-680*3
  54. setLabelMove(false);
  55. currentXpos = m_pLabelFg->x();
  56. destXpos = -WINDOW_WIDTH * m_currentFgIndex;
  57. while(currentXpos > destXpos)//平滑滚动效果
  58. {
  59. m_pLabelFg->move(currentXpos-WINDOW_PAGE_MOVE, WINDOW_START_Y);
  60. currentXpos = m_pLabelFg->x();
  61. qApp->processEvents(QEventLoop::AllEvents);//依然保持监听事件
  62. }
  63. m_pLabelFg->move(destXpos, WINDOW_START_Y);//确保最后移到指定的位置
  64. setLabelMove(true);
  65. }
  66. else
  67. {
  68. //右移的几种可能性,对于x坐标,与左移一致
  69. //index=0, 将label移动到-680*0
  70. //index=1, 将label移动到-680*1
  71. //index=2, 将label移动到-680*2
  72. //index=3, 将label移动到-680*3
  73. setLabelMove(false);
  74. currentXpos = m_pLabelFg->x();
  75. destXpos = -WINDOW_WIDTH * m_currentFgIndex;
  76. while(currentXpos < destXpos)
  77. {
  78. m_pLabelFg->move(currentXpos+WINDOW_PAGE_MOVE, WINDOW_START_Y);
  79. currentXpos = m_pLabelFg->x();
  80. qApp->processEvents(QEventLoop::AllEvents);
  81. }
  82. m_pLabelFg->move(destXpos, WINDOW_START_Y);
  83. setLabelMove(true);
  84. }
  85. }
  86. void DataBrain::changeCurrentButton()
  87. {
  88. for (int i = 0; i < WINDOW_BUTTON_COUNT; i++)
  89. {
  90. if (i != m_currentFgIndex)
  91. {
  92. m_pLabelBtnArray[i]->setMousePressFlag(false);
  93. }
  94. else
  95. {
  96. m_pLabelBtnArray[i]->setMousePressFlag(true);
  97. }
  98. }
  99. }
  100. void DataBrain::slotChangeCurrentPage(CLabel *label)
  101. {
  102. int index = 0;
  103. for (int i = 0; i < WINDOW_PAGE_COUNT; i++)
  104. {
  105. if (label == m_pLabelBtnArray[i])
  106. {
  107. index = i;
  108. break;
  109. }
  110. }
  111. //移动的几种可能性,对于x坐标
  112. //index=0, 将label移动到-680*0
  113. //index=1, 将label移动到-680*1
  114. //index=2, 将label移动到-680*2
  115. //index=3, 将label移动到-680*3
  116. //点击左边的按钮 右移
  117. if (index < m_currentFgIndex)
  118. {
  119. while(index != m_currentFgIndex)
  120. {
  121. m_currentFgIndex--;
  122. moveCurrentPage(false);
  123. }
  124. }
  125. else if (index > m_currentFgIndex) //点击右边的按钮 左移
  126. {
  127. while(index != m_currentFgIndex)
  128. {
  129. m_currentFgIndex++;
  130. moveCurrentPage(true);
  131. }
  132. }
  133. }
  134. void DataBrain::mouseMoveEvent(QMouseEvent *e)
  135. {
  136. int x = 0;
  137. if (m_mousePressFlag)
  138. {
  139. if (getLabelMove())
  140. {
  141. m_mouseDstPos = e->pos();
  142. x = m_mouseDstPos.x() - m_mouseSrcPos.x();
  143. setLabelMove(false);
  144. m_pLabelFg->move(m_currentFgXpos + x, WINDOW_START_Y);
  145. setLabelMove(true);
  146. }
  147. }
  148. else if (m_mouseMoveWindowFlag)
  149. {
  150. m_mouseDstPos = e->pos();
  151. this->move(this->pos() + m_mouseDstPos - m_mouseSrcPos);
  152. }
  153. }
  154. void DataBrain::mouseReleaseEvent(QMouseEvent *e)
  155. {
  156. int xpos = 0;
  157. if (m_mousePressFlag)
  158. {
  159. if (getLabelMove())
  160. {
  161. m_mouseDstPos = e->pos();
  162. xpos = m_mouseDstPos.x() - m_mouseSrcPos.x();
  163. if (xpos > 0)//右移
  164. {
  165. if (xpos >= WINDOW_ONEBUTTON_WIDTH)
  166. {
  167. if (m_currentFgIndex > 0)
  168. {
  169. m_currentFgIndex--;
  170. moveCurrentPage(false); //右移
  171. }
  172. else
  173. {
  174. moveCurrentPage(true); //左移
  175. }
  176. }
  177. else
  178. {
  179. moveCurrentPage(true); //左移
  180. }
  181. }
  182. else //左移
  183. {
  184. if (xpos <= -WINDOW_ONEBUTTON_WIDTH)
  185. {
  186. if (m_currentFgIndex < WINDOW_PAGE_COUNT-1)
  187. {
  188. m_currentFgIndex++;
  189. moveCurrentPage(true); //左移
  190. }
  191. else
  192. {
  193. moveCurrentPage(false); //右移
  194. }
  195. }
  196. else
  197. {
  198. moveCurrentPage(false); //右移
  199. }
  200. }
  201. m_mousePressFlag = false;
  202. }
  203. }
  204. else if (m_mouseMoveWindowFlag)
  205. {
  206. m_mouseMoveWindowFlag = false;
  207. }
  208. }
  209. //快捷键
  210. void DataBrain::keyPressEvent(QKeyEvent *e)
  211. {
  212. if (getLabelMove())
  213. {
  214. switch(e->key())
  215. {
  216. case Qt::Key_Left:
  217. case Qt::Key_Up:
  218. if (m_currentFgIndex > 0)
  219. {
  220. m_currentFgIndex--;
  221. moveCurrentPage(false); //右移
  222. }
  223. break;
  224. case Qt::Key_Right:
  225. case Qt::Key_Down:
  226. if (m_currentFgIndex < WINDOW_PAGE_COUNT-1)
  227. {
  228. m_currentFgIndex++;
  229. moveCurrentPage(true); //左移
  230. }
  231. break;
  232. default:
  233. break;
  234. }
  235. }
  236. }

代码有点长,需要全部代码的可以去 http://download.csdn.net/detail/zhangyang1990828/5241242下载源代码。效果图就不上了,和360的新特性差不多。

通过这样一个例子,我想对于整个Qt的机制有了一定的了解吧,以后有好例子还会与大家分享的。

QT学习(五)----360界面制作(2终结)的更多相关文章

  1. qt学习 (五) 登陆界面之连接按钮

    登陆步骤是比对输入的账号密码与数据库中的表项目是否一致 一样,  跳出mainwidget对话框 不一样,跳出消息错误框 今天就是要进去, 因为进去以后是widget的窗口,所以把用来核对消息的数据库 ...

  2. QT学习(四)----360界面制作(1)

    参照网上的资料,模仿了一份360新特效的界面. 源代码在:http://download.csdn.net/detail/zhangyang1990828/5238013 360真实效果:(最好自己打 ...

  3. JFinal Web开发学习(五)注册界面和后端验证

    效果: 直接点击注册后 : 后端验证是可靠地,前端js验证是不可靠的.只需要在浏览器删除js验证代码即可突破js验证. 1.注册界面 在WebRoot下新建regist.jsp <%@ page ...

  4. Qt之实现360安全卫士主界面代码开源

    匆匆一年又过去了,总结去年一年的节奏就是忙爆了:生活忙.工作忙,值得庆幸的是没有瞎忙:今天打开博客园查看我的博客,才发现几乎差不多一年时间没写博客了:博客文章就是记忆,就是曾经努力过的见证,感谢博客园 ...

  5. 第15.10节 PyQt(Python+Qt)入门学习:Qt Designer可视化设计界面组件与QWidget类相关的组件属性详解

    PyQt学习有阵子了,对章节的骨架基本考虑好了,准备本节就写组件的属性的,结果一是日常工作繁忙,经常晚上还要加班,二是Qt的组件属性很多,只能逐一学习.研究和整理,花的时间有点长,不过终于将可视化设计 ...

  6. qt学习笔记(五) QGraphicsPixmapItem与QGraphicsScene的编程实例 图标拖动渐变效果

    应大家的要求,还是把完整的project文件贴出来,大家省点事:http://www.kuaipan.cn/file/id_48923272389086450.htm 先看看执行效果,我用的群创7寸屏 ...

  7. QT学习之windows下安装配置PyQt5

    windows下安装配置PyQt5 目录 为什么要学习QT 命令行安装PyQt5以及PyQt5-tools 配置QtDesigner.PyUIC及PyRcc 为什么要学习QT python下与界面开发 ...

  8. QT学习2

    一.常用控件与常用的功能函数.  QDialog.QMainWindow.QPushButton.QLabel.QLineEdit 构造函数指定父容器.setText,getText,size,res ...

  9. Qt 学习之路 2(51):布尔表达式树模型

    Qt 学习之路 2(51):布尔表达式树模型 豆子 2013年5月15日 Qt 学习之路 2 17条评论 本章将会是自定义模型的最后一部分.原本打算结束这部分内容,不过实在不忍心放弃这个示例.来自于 ...

随机推荐

  1. bat-winget-win平台的软件包管理器

    win10 1709版本以后 引入的包管理器,如果不可用 需要 更新一下 应用安装程序. winget命令的功能  常用的就  安装 卸载 更新  . 卸载 使用中如果提示 策略 不允许,可执行下面命 ...

  2. Golang并发编程——goroutine、channel、sync

    并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...

  3. Collection子接口:Set接口

    1.Set 存储的数据特点:无序的.不可重复的元素具体的:以HashSet为例说明: 1. 无序性:不等于随机性.存储的数据在底层数组中并非照数组索引的顺序添加,而是根据数据的哈希值决定的. 2. 不 ...

  4. 项目中使用@Transactional需要注意的点

    项目如果是Spring Boot.或者Spring Cloud,切记需要在启动类上加入@EnableTransactionManagement该注解.否则事务不生效. @Transactional是一 ...

  5. MISC 2022/4/21 刷题记录-千字文

    1.千字文 得到名为png的无类型文件,010 Editor查看,png,改后缀,得到二维码 QR扫描,得到一句话"这里只有二维码" 思路不对,binwalk一下,发现有错误信息 ...

  6. 使用APICloud开发app录音功能

    ​ mp3Recorder模块封装在iOS.Android下录音直接生成mp3,统一两个平台的录音生成文件,方便双平台之间的交互,减少录音完成后再转码的过程:同时提供分贝波形图显示UI:使用该模块前需 ...

  7. 无用的IP黑名单

    无效的IP黑名单,有些还没有收集,在阿里云或者腾讯云的安全组里面设置,拦截不必要的IP,免得遭到攻击,也避免的CPU和内存过高 来源 备注82.102.21.217 拒绝 随机访问目录攻击,频繁69. ...

  8. Winsock Server Code

    以下代码来自:https://msdn.microsoft.com/en-us/library/windows/desktop/ms737593(v=vs.85).aspx #undef UNICOD ...

  9. OpenCV视频防抖技术解析

    视频防抖有很多种技术,各有优劣,主流的目前分为三种:EIS电子防抖EIS电子防抖是通过软件算法实现防抖的.其技术运作原理是通过加速度传感器和陀螺仪模块侦测手机抖动的幅度,从而来动态调节整ISO.快门以 ...

  10. TCP通信的概述