Qt之WIFI搜索、显示与连接
首先介绍一下我的环境,Linux环境下使用Qt,交叉编译到ARM板上调试,ARM板自带WIFI模块,大部分Linux命令我都可以自由地使用。首先,需要通过控制台命令来获取WIFI信息,按照图片上画的,至少要得到WIFI名称、信号强度和加密方式。获取WIFI的命令有很多,但是简单地调用命令获取WIFI信息文件无法直接使用,还需要提取到其中的字符串信息。假定我们通过一些命令,获取到了这些内容,还要通过
前两天,产品开发到WIFI模块了,PM丢给我一张图片,很简单,只有一个标签,再加一个按钮,大概就是下面这个样子。
当WIFI在关闭状态下,整个页面就只有上面那俩控件,整个页面不可谓不简单。
但是作为没有需求文档的我,一看就傻眼了。这就好比甲方爸爸跟你说:我的需求非常简单,你给我开发一个手机淘宝出来就行了。
真有那么简单吗(黑人问号)?粗略地脑部了一下所有硬性需求和隐形需求之后,我问了PM一句:翻页的,还是滑动的?
PM回:滑动的,跟苹果那种一样。
“收到”
没办法,开发这件事,总得有个人难受。程序猿不难受,用户就得难受。PM不想难受,程序猿就得难受。程序猿不想难受,老板就难受,你这个月钱包也别想好受。
好吧,那就硬着头皮分析一下,这样一个看似无比简单的页面,到底需要哪些功能点。
首先介绍一下我的环境,Linux环境下使用Qt,交叉编译到ARM板上调试,ARM板自带WIFI模块,大部分Linux命令我都可以自由地使用。
首先,需要通过控制台命令来获取WIFI信息,按照图片上画的,至少要得到WIFI名称、信号强度和加密方式。获取WIFI的命令有很多,但是简单地调用命令获取WIFI信息文件无法直接使用,还需要提取到其中的字符串信息。假定我们通过一些命令,获取到了这些内容,还要通过代码将它们传递给主程序。做到这一点,前期的准备工作才算做完。
这一块的内容,可以参考我之前发的博客:ARM上搜索WIFI并解析字符串
顺便补充一下,自定义WIFI按钮的纯代码实现可以看我这篇博客:Qt自定义开关按钮控件
接下来才算正式开始。在第一次进入WIFI页面,WIFI按钮默认是关闭的,点击WIFI按钮,就有一大堆事情要处理了。首先,要搜索附近的WIFI,并显示到页面的下方。搜索并提取信息已经在上面处理了,我们只需要通过system命令在主程序中,逐行读取它们即可。
而接下来的显示就比较麻烦了,首先要有一个大致的布局。因为要实现拖动,所以需要建一个大的ScrollArea,然后在里面放一个widget,作为拖动的幕布。在这个widget里,需要逐个地塞入WIFI内容,它们是一个个小的widget,里面包含WIFI名、信号强度和加密方式这三种控件,并排板。用代码来说基本就是这样:
vLayout = new QVBoxLayout;
{
gridLayout = new QGridLayout;
wifiWidget[curLine] = new QWidget(this);
gridLayout -> addWidget(wifiNameLabel[curLine],0,0,1,3);
gridLayout -> addWidget(lockLabel[curLine],0,3,1,1);
gridLayout -> addWidget(signLevelLabel[curLine],0,4,1,1);
wifiWidget[curLine] -> setLayout(gridLayout);
vLayout -> addWidget(wifiWidget[curLine]);
}
scrollWidget -> setLayout(vLayout);
因为ScrollArea自带边框和滚动条,如果要设计成苹果那种风格,就要修改ScrollArea的属性。
scrollArea -> setFrameShape(QFrame::NoFrame); //无边框
scrollArea -> setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); //关闭滚动条
到这里,差不多就有一个能看的WIFI页面了,此时还无法拖动。
接下来,就要设置显示在WIFI列表的内容。通过readLine()等方式,获取到WIFI名,传递到WIFI名 Label上。同理,获取信号强度,计算一下WIFI质量,并传递给信号Label对应的图片。最后看一下有没有加密,现在一般都是WPA2加密了,没有密码的WIFI不会解析到这样的内容。
然后就是仔细地排版,如果希望相邻的WIFI信息中间设置一个可见的间隔线,可以设置给widget设置stylesheet。
border-bottom: 1px solid black;
打开按钮暂时到这,接下来是关闭按钮。
点击关闭按钮后,要断开WIFI,这里还是用system命令来操作。然后,隐藏ScrollArea和里面的widget,使页面恢复成之前只有两个控件的样子。
开闭按钮事件,建议写在一起并分别判断,然后把WIFI搜索和断开连接的方法分离。
接下来说鼠标事件。
在WIFI按钮打开的状态下,用户可以点击任意的一条WIFI,进入输密码连接的页面。由于点击的不是button而是widget,没法用Qt里的槽函数,所以可以使用eventFilter来替代。
我们给每一个WIFI的widget安装eventFilter。
installEventFilter(this);
然后编辑eventFilter。
首先要通过某种鼠标事件触发eventFilter,一般来说鼠标的release事件最为适合。
顺便,前面的页面还不能拖动,为了实现拖动,我们需要修改鼠标事件,主要是控制坐标的变化。
void mouseMoveEvent(QMouseEvent *e)
{
if (!m_bMousePressed)
{
return;
}
QPoint currentPt = e->pos();
int dist = m_PressPosition.y() - currentPt.y();
scrollArea->verticalScrollBar()->setValue(scrollArea->verticalScrollBar()->value() + dist);
m_PressPosition = currentPt;
keeping = true;
}
void mousePressEvent(QMouseEvent *e)
{
m_bMousePressed = true;
m_PressPosition = e->pos();
}
void mouseReleaseEvent(QMouseEvent *e)
{
Q_UNUSED(e);
m_bMousePressed = false;
m_PressPosition.setX(0);
m_PressPosition.setY(0);
keeping = false;
}
这里的keeping,是用来监控鼠标是不是按住的状态的。如果不加这个,在判断press或者release事件会有问题,如果是press触发eventFilter,你会发现拖动时就直接跳转了;如果是release触发eventFilter,那么在拖动页面后,会立刻跳转到你一开始点击的那个wifi连接页。所以这样的一个监控flag必不可少。
有了鼠标事件,就可以编写eventFilter了。在eventFilter的最前面先加入keeping的判断,要是现在用户在keeping(拖动状态),那就不要响应,直接return。首先要获取到点击的是哪条WIFI,这一点我们可以通过监视obj->objectName().contains的widget
名来确定。在前面定义WIFI widget的时候我们可以设置一个自定义的WIFI名,在里面加入WIFI的各种信息,然后监视点击的obj包含的WIFI名来确定点击的是哪个WIFI widget。确定了点击的WIFI后,下面就和写槽函数一样了,弹出输入密码的页面即可。
这个页面可以看做一个自定义的QMessageBox,里面包含输入密码的QLineEdit,加入、取消按钮、关闭按钮云云。关于自定义QMessageBox,我这篇博客里有介绍。
Qt自定义弹出窗口
这里说一下加入。同样需要通过system命令来控制。只是你需要把用户在WIFI页面选择的WIFI的名称,以及在此页面输入的密码传递进system命令中去,具体细节不多讲了,不难。
最后是记忆功能。
为什么要记忆呢?页面的开关默认是关闭的,当用户连接WIFI成功,退出此页面,又一不小心重新进入此页面后,虽然WIFI还连通着,但是页面只有光秃秃的两个控件,用户肯定会黑人问号。因此需要记忆下用户在离开页面时的开关状态。
我们可以把开关的开闭状态利用QSettings写道配置文件里,关于这部分的操作,可以看我这篇博客。
Qt使用QSettings保存和读取用户信息
最关键的就是读写的时机,这个要根据实际情况来控制。此外,用户重新进入页面,而按钮为开状态,那么还要再搜索一遍WIFI并显示出来。
除此之外,还有一大堆细节问题。篇幅问题,这篇文章就介绍这么一个大体的框架,还有一些细节的功能点我没写进来。总之,这部分代码实际写起来,远比上面写的还要麻烦的多。而且由于没有文档,很多功能都是突然想到,然后一顿修改。
所以啊,尽管PM只给我看了两个控件,其中的逻辑却深不见底。很多看似简单的需求,那只是提出需求的人没有仔细思考、或者缺乏思考的能力,看不到问题的本质。
对于PM来说,一份尽量详尽的需求文档和概要设计文档,对于程序猿是很重要的,虽然程序猿大多时候不看这些文档,但这些文档相当于一份字典——软件开发的字典。只有全盘理解了其中的内容,才能快速地形成软件架构,写出漂亮的、易维护、高重用的代码。
至于这部分的代码,我就不提供了,公司保密要求,呵呵。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)