继续上一章的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. 【RPA之家转载】苏桦 华为RPA 企业财务实践:RPA与AI结合,实现百万级票据、合同处理自动化

    [RPA之家转载]苏桦 华为RPA 企业财务实践:RPA与AI结合,实现百万级票据.合同处理自动化 看到大会的主题,说每一位开发者都了不起,说白了我也非常的感触,因为我自己本身也是一个开发者,我从01 ...

  2. 10分钟实现dotnet程序在linux下的自动部署

    背景 一直以来,程序署都是非常麻烦且无聊的事情,在公司一般都会有 devops 方案,整个 cicd 过程涉及的工具还是挺多的,搭建起来比较麻烦.那么对于一些自己的小型项目,又不想搭建一套这样的环境, ...

  3. 步态识别《GaitSet: Regarding Gait as a Set for Cross-View Gait Recognition》2018 CVPR

    Motivation: 步态可被当作一种可用于识别的生物特征在刑侦或者安全场景发挥重要作用.但是现有的方法要么是使用步态模板(能量图与能量熵图等)导致时序信息丢失,要么是要求步态序列连续,导致灵活性差 ...

  4. 《SVDNet for Pedestrian Retrieval》理解

    <SVDNet for Pedestrian Retrieval>理解 Abstract: 这篇文章提出了一个用于检索问题的SVDNet,聚焦于在行人再识别上的应用.我们查看卷积神经网络中 ...

  5. HMS Core音频编辑服务支持7种音频特效,助力一站式音频处理

    多媒体时代,音频作为内容传播中的重要形式,因其不受空间限制.认知负担小.声音元素多样化等特点,广泛应用于短视频制作.儿童在线教育.有声阅读.游戏等领域产品,在各种形式的音频呈现过程中,合理添加音效能够 ...

  6. 运行Flutter时连接超时

    这个墙不知道浪费了开发者多少的时间!!!!!!!!!!!!!!!!!!! 1.修改仓库地址为阿里仓库: 编辑android/build.gradle,把文件中的两处: google() jcenter ...

  7. ERROR .web.servlet.DispatcherServlet - Context initialization failed

    自己创建了一个SSM 项目,使用maven的tomcat7 运行报错 ERROR .web.servlet.DispatcherServlet - Context initialization fai ...

  8. Java学习day09—-封装和继承

    封装 1.封装 1.1 封装的概念和实现 封装: 属性私有:将属性使用private修饰,表示此属性只能在本类中访问,不让外部直接访问 方法公开:针对每一个属性编写一对公开的方法 get set 分别 ...

  9. 高级数据结构学习笔记 / Data Structure(updating)

    树状数组   查询操作:O(logn) 修改操作:O(logn) #define lowbit(x) (x & -x) int tr[N]; // 树状数组 // 添加c个大小为x的数值 vo ...

  10. 在.NET 6.0中配置WebHostBuilder

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 在阅读第4章"使用Kestrel配置和定制HTTPS"时,您可 ...