继续上一章的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. Spring jdbctemplate和事务管理器

    内部bean 对象结构: @Autowiredprivate IAccountService accountService; @Service("accountService")@ ...

  2. FTP安装及使用

    通过网络传输数据的手段 1. ssh 2. http 3. nfs 4. rsync 5. ftp 6. samba ftp的简介: 1. ftp是应用层协议,是基于TCP 2. 使用21端口 FTP ...

  3. sql-sql优化

    SQL执行流程 a. 编写过程: select dinstinct .. from .. join .. on .. where .. group by .. having .. order by . ...

  4. 单片机 MCU 固件打包脚本软件

    ​ 1 前言 开发完 MCU 软件后,通常都会生成 hex 文件或者 bin 文件,用来做固件烧录或者升级,如果用来做产品开发,就涉及到固件版本的问题,初学者通常采用固件文件重命名来区分版本. 如果需 ...

  5. Java开发问题:Column 'AAA' in where clause is ambiguous解决办法

    当在java开发中遇到了Column 'AAA' in where clause is ambiguous问题时, 你需要去看看:多表查询的时候不同的表是否出现了相同名称相同的列, 如果存在,你需要在 ...

  6. NC14683 储物点的距离

    NC14683 储物点的距离 题目 题目描述 一个数轴,每一个储物点会有一些东西,同时它们之间存在距离. 每次给个区间 \([l,r]\) ,查询把这个区间内所有储物点的东西运到另外一个储物点的代价是 ...

  7. 详解HashMap源码解析(上)

    jdk版本:1.8 数据结构: HashMap的底层主要基于数组+链表/红黑树实现,数组优点就是查询块,HashMap通过计算hash码获取到数组的下标来查询数据.同样也可以通过hash码得到数组下标 ...

  8. 单调栈_Largest Rectangle in a Histogram

    题面 https://flowus.cn/xjsc01/share/395ca9dc-315c-4bd5-a942-016709980c03 这里还有很多笔记(归纳好的) https://www.ac ...

  9. 【Azure 应用服务】PHP应用部署在App Service for Linux环境中,上传文件大于1MB时,遇见了413 Request Entity Too Large 错误的解决方法

    问题描述 在PHP项目部署在App Service后,上传文件如果大于1MB就会遇见 413 Request Entity Too Large 的问题. 问题解决 目前这个问题,首先需要分析应用所在的 ...

  10. Mysql 数据恢复流程 基于binlog redolog undolog

    注:文中有个易混淆的地方 sql事务,即每次数据库操作生成的事务,这个事务trx_id只在undolog里存储,同时undolog维护了此事务是否完成的状态. 日志持久化事务,为了保证redolog和 ...