业务需求:

基于网盘客户端的实现,原有网盘的设置面板无论从界面显示还是从业务需求都不能满足我们的正常需求。当前的要求是,模拟QQ系统设置的面板实现当前我们网盘中的基本配置功能。在完成这篇文章时已将基本功能实现完成,虽未整合进网盘客户端中,但基本技术预演已经实现。

QQ系统设置面板分析:

QQ系统设置面板效果图:

QQ系统设置面板功能描述:

由于存在较多的配置,如果每个模块的配置项都设计到一个窗体中,则会存在很多的窗体,不太符合用户的使用体验,且程序编写也比较麻烦。QQ系统设置面板中的实现是,所有的配置项均列在右侧区域中,当移动右侧的滚动条的过程中,如果对应的面板出现则在左边的导航中对应的标题也显示点击的效果。同时,单独点击左侧的导航,右面的区域也显示对应导航的配置项。

实现思路:

左侧:

左侧导航的实现很简单,使用QListWidget完全可以满足我们的需求,至于当点击左侧时右侧显示对应模块的配置项则需要我们添加处理代码完成。

右侧:

由于右侧存在导航栏,因此右侧的区域需要使用QScrollArea控件,这里需要注意两点:1> 在QScrollArea控件中每个模块的配置需要放在一个单独的QWidget中,只  有这样我们在移动滚动条经过某个某块的配置项时才可以识别到。2> 在实现滚动条效果时,看到网上有很多文章说滚动条效果无法实现出来,其实我的做法很简单,在ui窗体中将QScrollArea拖入窗体中,然后设置改窗体的属性:widgetResizable为不选中,即false状态。如果你的QScrollArea是在代码中new出来的,则它默认的widgetResizable是true,必须在代码中将它设置为false才行。

为了直观地说明第一个注意点,在我测试的UI窗体中QScrollArea区域中防止了多个QWidget(每个模块配置对应一个QWidget),贴图如下:

到这里我们面临的问题就是:

1. 当拖动滚动条时如何判断经过某个QWidget,从而显示左侧的对应项?

首先,需要绑定垂直滚动条的valueChanged事件,这样我们才能随时的监控它的移动变化;其次,利用QWidget的visibleRegion()方法,官方关于这个函数的解释是“当paint事件出现的时候返回它清晰的范围,对与可见的widget,它是一个没有被其它widget覆盖的近似的范围;反之返回一个空的范围”,通过调用QWidget的visibleRegion().isEmpty() 就可以确定出当前滑动过的区域。

2. 当点击左侧的导航时,右侧区域如何定位到对应的配置模块?

首先,需要绑定QListWidget的itemClicked事件,这样我们才能监控到点击事件;其次利用QScrollBar的setSliderPosition()方法设置滚动调到特定模块的位置。

3. 由于绑定了滚动条的valueChanged事件,又在itemClicked事件中设置了滚动条的问题,那么在设置位置的同时不也同样触发valueChanged事件吗?

需要一个变量来标记,本次valueChanged事件是由于setSliderPosition方法引起的。

关键代码段:

1. 绑定QScrollArea的valueChanged事件和QListWidget的itemClicked事件

  1. void LHTSettingsBoard::SetupUi()
  2. {
  3. m_scroll = qFindChild<QScrollArea *>(m_wgtMain, "scrollArea");
  4. m_widget_login = qFindChild<QWidget *>(m_wgtMain, "widget_login");
  5. m_widget_register = qFindChild<QWidget *>(m_wgtMain, "widget_register");
  6. m_widget_network = qFindChild<QWidget *>(m_wgtMain, "widget_network");
  7. m_widget_password = qFindChild<QWidget *>(m_wgtMain, "widget_password");
  8. m_listWidget = qFindChild<QListWidget *>(m_wgtMain, "left_navigation");
  9. connect((const QObject*)m_scroll->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(valueChanged(int)));
  10. connect(m_listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(itemClicked(QListWidgetItem*)));
  11. QListWidgetItem *loginItem = m_listWidget->item(0);
  12. loginItem->setSelected(true);
  13. m_wgtMain->show();
  14. }

2. 响应valueChanged事件的槽,完成移动滚动条时,当某个面板出现时触发左侧QListWidget中item的选中事件

  1. void LHTSettingsBoard::valueChanged(int value)
  2. {
  3. QListWidgetItem *loginItem = m_listWidget->item(0);
  4. QListWidgetItem *registerItem = m_listWidget->item(1);
  5. QListWidgetItem *networkItem = m_listWidget->item(2);
  6. QListWidgetItem *passwordItem = m_listWidget->item(3);
  7. if (!m_sign)
  8. {
  9. if (!m_widget_login->visibleRegion().isEmpty())
  10. {
  11. loginItem->setSelected(true);
  12. return;
  13. }
  14. else
  15. {
  16. loginItem->setSelected(false);
  17. }
  18. if (!m_widget_register->visibleRegion().isEmpty())
  19. {
  20. registerItem->setSelected(true);
  21. return;
  22. }
  23. else
  24. {
  25. registerItem->setSelected(false);
  26. }
  27. if (!m_widget_network->visibleRegion().isEmpty())
  28. {
  29. networkItem->setSelected(true);
  30. return ;
  31. }
  32. else
  33. {
  34. networkItem->setSelected(false);
  35. }
  36. if (!m_widget_password->visibleRegion().isEmpty())
  37. {
  38. passwordItem->setSelected(true);
  39. return ;
  40. }
  41. else
  42. {
  43. passwordItem->setSelected(false);
  44. }
  45. }
  46. m_sign = false ;
  47. }

3. 响应itemClicked事件的槽,完成点击QListWidget中的item时,QScrollArea中的滚动条移动到相应配置项的位置

  1. void LHTSettingsBoard::itemClicked(QListWidgetItem *item)
  2. {
  3. QString itemText = item->text();
  4. qDebug() << itemText;
  5. QPoint pos ;
  6. m_sign = true ;
  7. if (itemText.compare("Login") == 0)
  8. {
  9. pos = m_widget_login->pos();
  10. m_scroll->verticalScrollBar()->setSliderPosition(pos.y());
  11. }
  12. else if (itemText.compare("Register") == 0)
  13. {
  14. pos = m_widget_register->pos();
  15. m_scroll->verticalScrollBar()->setSliderPosition(pos.y());
  16. }
  17. else if (itemText.compare("Network") == 0)
  18. {
  19. pos = m_widget_network->pos();
  20. m_scroll->verticalScrollBar()->setSliderPosition(pos.y());
  21. }
  22. else if (itemText.compare("ChangePassword") == 0)
  23. {
  24. pos = m_widget_password->pos();
  25. m_scroll->verticalScrollBar()->setSliderPosition(pos.y());
  26. }
  27. }

总结:

通过以上就可以实现类似QQ系统设置面板的功能,开始我对这一块如何实现,使用什么控件完全不知道,共花了不到一天的事件查资料、试验才找到合适的方法。在这个过程中深刻地体会到解决问题最关键的地方在于思路,如果有了一个思路,哪怕别人告诉你应该朝着哪个方向走,后面的工作其实都是水到渠成很简单的了。慢慢享受这个过程,一个问题由完全不知道如何解决,到有思路,到真正解决。

http://blog.csdn.net/houqd2012/article/details/26501791

模拟QQ系统设置面板实现功能的更多相关文章

  1. TCP模拟QQ聊天功能

    需求: 模拟qq聊天功能:实现客户端与服务器(一对一)的聊天功能,客户端首先发起聊天,输入的内容在服务器端和客户端显示,然后服务器端也可以输入信息,同样信息在客户端和服务端显示. 提示: 客户端 1) ...

  2. 计时器中qq上的一个功能,延时作用

    在qq主页面板上的最上方有自己的用户名,往用户名上移动会出现一个大框,往大框中移动,大框不会消失,如果离开大框或者姓名,大框就会消失,这一功能用到display:none的效果还有就是计时器的延时功能 ...

  3. python模拟QQ聊天室(tcp加多线程)

    python模拟QQ聊天室(tcp加多线程) 服务器代码: from socket import * from threading import * s = socket(AF_INET,SOCK_S ...

  4. Web 项目中分享到微博、QQ空间等分享功能

    Web 项目中分享到微博.QQ空间等分享功能 网上有很多的模板以及代码,但是有很多都不能分享内容,简单的测试了下: 以新浪微博为例,文本框中的内容是title属性,下面的链接是url属性,如果你的链接 ...

  5. java 模拟qq源码

    java 模拟qq源码: http://files.cnblogs.com/files/hujunzheng/QQ--hjzgg.zip

  6. 利用phantomjs模拟QQ自动登录

    之前为了抓取兴趣部落里的数据,研究了下QQ自动登录. 当时搜索了一番,发现大部分方法都已经失效了,于是准备自己开搞. 第一个想到的就是参考网上已有方案的做法,梳理登陆js的实现,通过其他语言重写.考虑 ...

  7. MVC实现类似QQ的网页聊天功能-ajax(下)

    此篇文章主要是对MVC实现类似QQ的网页聊天功能(上)的部分代码的解释. 首先说一下显示框的滚动条置底的问题: 结构很简单一个大的div(高度一定.overflow:auto)包含着两个小的div第一 ...

  8. WPF案例 (三) 模拟QQ“快速换装"界面

    原文:WPF案例 (三) 模拟QQ"快速换装"界面 这个小程序使用Wpf模拟QQ快速换装页面的动画特效,通过使用组合快捷键Ctrl+Left或Ctrl+Right,可实现Image ...

  9. Android简易实战教程--第二十二话《自定义组合控件模拟qq登录下拉框和其中的一些”小技巧”》

    转载此文章请注明出处:点击打开链接   http://blog.csdn.net/qq_32059827/article/details/52313516 首先,很荣幸此专栏能被CSDN推荐到主页.荣 ...

随机推荐

  1. for语句的嵌套(示例及练习)

    for(初始条件:循环条件:状态改变) {for(初始条件:循环条件:状态改变) {     循环体      }} 一般,用来解决循环的方法:穷举法.迭代法. 示例一:阶乘的和 示例二: 练习一:兔 ...

  2. iOS开发之第三方登录微信-- 史上最全最新第三方登录微信方式实现

    项目地址 :    https://github.com/zhonggaorong/weixinLoginDemo 最新版本的微信登录实现步骤实现: 1.在进行微信OAuth2.0授权登录接入之前,在 ...

  3. js中的setTimeout和setInterval

    在html页面中要使用自动刷新功能时,可以是使用js中setTimeout和setInterval: 一.使用方法 setTimeout的使用setTimeout('要调用的Js方法', 调用的延迟时 ...

  4. YII2 Gridview

    YII2 Gridview 部分使用规则 1.页面显示的时间戳转换 a. [ 'label'=>'创建日期', 'attribute' => 'created_at', 'filter' ...

  5. C# Programming Study #1

    引用的时候需要在参数和使用的时候加上 ref 关键字 static bool addnum (ref int val) //引用 { ++val; return true; } 参数数组的概念,可以接 ...

  6. BZOJ 1726: [Usaco2006 Nov]Roadblocks第二短路

    1726: [Usaco2006 Nov]Roadblocks第二短路 Description 贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友.贝茜很喜欢路边的风景,不想那么快地结束她 ...

  7. PHP 自学之路-----XML编程(Xpath技术,simpleXml技术)基础入门

    XPAth技术 XPath的设计的核心思想,可以通过xpath迅速简介的定位到你希望查找的节点.主要目的是描述节点相对其他节点的位置,可以取得所有符合条件的节点,成为[位置路径]. Xapth主要用来 ...

  8. HDU 4741 Save Labman No.004 2013 ACM/ICPC 杭州网络赛

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4741 题意:给你两条异面直线,然你求着两条直线的最短距离,并求出这条中垂线与两直线的交点. 需要注意的是 ...

  9. java学习——入门扫盲篇

    概要 近期这几天開始进入java的学习,接触到了好多不是非常了解的概念,像JDK.JRE.JVM.GC等等这些,放到这里来进行下扫盲. java java是一种面向对象程序设计语言和java平台的总称 ...

  10. [计算机网络] vsftpd的安装与使用

    简单介绍: vsftpd是一个能够执行在类UNIX操作系统上的FTPserver软件,它能够执行在Linux.BSD.Solaris.HP-UX等系统上. 1 vsftpd的安装 在ubuntu系统上 ...