前言

断断续续学习C++一年了,现在要做课设,觉得控制台界面实在太难看,于是用Qt做一个图形化的程序出来。

学习Qt也没有多久,只是了解了个大概,这次开发基本上是啃了2天的官方帮助文档,然后利用各种Qt提供的轮子实现的。有些地方做的确实还很不完善,不过似乎没有什么致命的bug。

代码质量底下,谨慎模仿。

Qt真的是一个很好的C++扩展库,学习完C++觉得没有用武之地的可以去学习一下Qt来开发几个图形化软件来练练手。

项目介绍

实现一个简单的电话本程序,能够实现添加、查找、修改、删除、保存到文件等基本功能

开发环境

IDEQtCreator(我个人认为非常好用,这也是我现在在linux下编写C++的主力IDE,因为是官方的IDE所以契合度非常高)

系统Windows(本来是想在linux下开发的,但是考虑到最后做的程序要在windows平台上展示,不想进行二次编译所以选择了windows平台,Qt是跨平台的因此这个不用过多考虑)

编程思路

其实第一反应肯定是用数据库来实现这个功能了。但是既然是C++的课设,而且考虑到数据量应该不会太大,所以就直接使用文本文档来储存和读取数据(这是一个偷懒的做法orz)

主界面,看了一下,本来是想用一个表格来展示的,调教了一天之后发现设置起来非常麻烦,于是就改用了列表控件。(其实是我上网找到了一个类似的教程我会乱说?)查询,删除,添加都可以使用列表控件自带的方法,至于保存,直接是使用文本文档输出的方式即可。

功能开发

程序主体

首先来编写程序的主窗口界面,建立一个新的Qt项目,基类选择为QMainWindow,然后编辑界面文件如下(没有美化,轻喷):

各个部件的命名如图。

接下来开始编写各个功能

添加

添加功能需要一个弹出的窗口,输入姓名和电话,然后插入到主程序的listWidget中去。因此需要再编写一个对话窗口类,向工程中添加一个设计师界面类,基类选择QDialog,命名为editDialog(这个窗口待会也可以用在修改功能中),模板选择Dialog with Buttons under(就是下面有一组按钮的对话框),然后把界面设置成这样:

两个输入框都是PlainTextEdit控件,下面那组按钮已经分别关联了这个对话框的accept()和reject()槽

然后在editDialog中添加以下几个公用函数:

QString name() const;//获取姓名
QString number() const;//获取号码
void setName(const QString &);//设置姓名
void setNumber(const QString &);//设置号码

上面两个函数用来获取编辑框中的内容,下面两个函数则用于设置编辑框中的初始内容(会在下面的修改功能中用到)

实现是这样的:

QString EditDialog::name() const
{
return ui->nameEdit->toPlainText().trimmed();
} QString EditDialog::number() const
{
return ui->numEdit->toPlainText().trimmed();
} void EditDialog::setName(const QString & name)
{
ui->nameEdit->setPlainText(name);
} void EditDialog::setNumber(const QString & num)
{
ui->numEdit->setPlainText(num);
}

然后我们来修改主窗口中对应按钮的槽(修改槽只要在控件上右键选择“转到槽”就可以快速切换到槽函数的实现了) 注意实例化EditDialog是要包含头文件的,之后新添加的类也是一样

void MainWindow::on_addButton_clicked()
{
EditDialog editDialog(this);
if(editDialog.exec()==)
{
QString line = editDialog.name()+"---"+editDialog.number();
ui->listWidget->addItem(line);
this->statusBar()->showMessage("1 item added",);//设置状态栏的提示信息
}
}

我们在这个槽里实例化一个editDialog对象,并把它的父对象设置为主窗口,利用exec()来实现模态窗口效果,通过editDialog对象内的name和number方法获取用户输入的内容并把他们组装在一起,用addItem()方法插入ListWidget就可以了。

修改

修改功能和添加功能基本是差不多的,我们直接转到对应按钮的槽里实现就可以了

void MainWindow::on_editButton_clicked()
{
if(!ui->listWidget->currentItem())
return;
QStringList parts = ui->listWidget->currentItem()->text().split("---");
EditDialog editDialog(this);
editDialog.setName(parts[]);
editDialog.setNumber(parts[]); if(editDialog.exec()==)
{
ui->listWidget->currentItem()->setText(editDialog.name()+"---"+editDialog.number());
this->statusBar()->showMessage("1 item updated",);
}
}

这里用到了QStringList类和QString的split()方法,其实并不难,看一下这个实例就很容易理解,官方的文档也写的很详细

删除

删除功能其实直接利用了QListWidget提供的返回当前选择行的currentItem()函数和delete方法,但是为了防止误操作,需要一个模态的确认对话框,再向工程中添加一个设计师界面类,仍然选择是有两个按钮的对话框,对话框的界面只需要放一个label写上“确定删除?”即可。

这个对话框类我命名为ConfirmDialog,主窗口对应按钮的槽函数如下:

void MainWindow::on_delButton_clicked()
{
if(!ui->listWidget->currentItem())
return; ConfirmDialog * confirmDialog = new ConfirmDialog(this);
if(confirmDialog->exec()==)
{
delete ui->listWidget->currentItem();
this->statusBar()->showMessage("1 item deleted",);
}
}

查找

这个是最难写的一个功能,还是先做查询窗口,这次我选择了没有按钮的对话框类,命名为QueryDialog,界面如下:

下面的两个按钮:“查询”设置为queryButton,这个槽稍后将会和主窗口里的槽关联,“退出”则直接和对话框的reject()槽关联了。

另外,为了能够把queryButton跟主窗口的槽关联起来,就必须把他设置为公有的,于是我把头文件中,ui改成了public的:

public:
Ui::QueryDialog *ui;

这其实不是一个很好的办法,破坏了面向对象的封装性,但是我懒啊。。于是就这么干了。

查找功能的思路是,用户在查找对话框中输入关键字,然后通过查询按钮发送的信号把关键字传送给主窗口里的槽,这个槽函数调用listWidget的findItem()方法,然后把结果(一个基类性为 QListWidgetItem *的Qlist)发送给查询窗口来显示。

QueryDialog里增加一个函数来返回编辑框中的内容

QString QueryDialog::getTarget()
{
return ui->QueryEdit->toPlainText();
}

在MainWindow类里添加一个私有的QueryDialog对象qdlg(这么做是为了实现两个窗口的通信,以及槽的关联)

主窗口“查找”按钮的槽直接写成以模态窗口显示qdlg即可:

void MainWindow::on_queryButton_clicked()
{
qdlg.exec();
}

主窗口里的槽函数,写在public slots下:

void MainWindow::SendQueryResult()
{
QString target = qdlg.getTarget();
QList <QListWidgetItem * > resList = ui->listWidget->findItems(target,Qt::MatchContains);//这个函数第二个参数是匹配方法,我这里设置成包含字段就匹配
qdlg.ShowQueryResult(resList);//这个是QueryDialog里面用于处理显示结果数据的,接下来会写实现
qdlg.exec();
}

接着,在MainWindow类的构造函数中,把这个槽和它的成员对象qdlg的查询按钮的信号关联起来:

connect(qdlg.ui->queryButton,SIGNAL(clicked()),this,SLOT(SendQueryResult()));

然后是QueryDialog里面,用于接收到数据并显示的函数ShowQueryResult:

void QueryDialog::ShowQueryResult(const QList <QListWidgetItem * > & resList)
{
if(resList.size()==)
{
ui->resLabel->setText("No results!");
return;
}
else
{
QString resNumber = QString::number(resList.size());//注意这里的字符串处理 ui->resLabel->setText(resNumber+" item(s) founded:"); for(int i=;i<resList.size();i++)
{
ui->listWidget->addItem(resList[i]->text());
}
}
}

在这里说明一下,我本来希望能够直接利用addItem函数重载的QListWidgetItem * 参数来直接读取List里的记录,但是这样做却发现不能显示内容(原因我至今不明,望高人指点),于是我用了QListWidgetItem的text()方法来获取字符串添加进去。

这样就基本实现了查询功能

保存

其实我一开始是想做成动态保存的结果的(对listWidget的操作直接影响保存文件),但是查询略麻烦,所以改成了每点击一下保存按钮就重新写入一次文档(还是偷懒23333)。

要实现保存,就需要一个外部的txt文档(我这里命名为data.txt)

在主窗口类里添加一个私有的QFile对象file,用它来读写data.txt

接下来实现,打开程序时自动加载之前保存内容。其实很简单,直接在构造函数里添加读取txt并写入listWidget就可以

file.setFileName("data.txt");
//从文件读取
if(file.open(QIODevice::ReadOnly|QIODevice::Text))//注意这里的参数
{
QTextStream readin(&file);
while(!readin.atEnd())
{
QString line = readin.readLine();//一行一行读取
ui->listWidget->addItem(line);
}
file.close();
}

接下来实现保存按钮的槽

void MainWindow::on_saveButton_clicked()
{
//功能:把当前程序中的所有记录保存到data.txt
if(file.open(QIODevice::WriteOnly))
{
QTextStream out(&file);
for(int i=;i<ui->listWidget->count();i++)
{
out<<ui->listWidget->item(i)->text()<<endl;
}
file.close();
this->statusBar()->showMessage("File saved",);
}
else
{
this->statusBar()->showMessage("Save failed!",);
return;
}
}

看一下帮助文档中QFile和QTextStream的用法,上面的程序应该不难理解。

至此我们的程序就写完了!快快发布release吧~

源码

请查看我的github:

github.com/MarkLux/Qt-PhoneBook

记一次开发:Qt简单电话本程序的更多相关文章

  1. 使用Go开发一个简单的服务器程序

    最近有个小项目,需要一个简单的后台程序来支撑,本来想用Nodejs来做,但是由于本人js一直很菜,并且很讨厌callback,虽然我也很喜欢异步模型,但我一直都觉得JS是反人类的.后台就用了go处理, ...

  2. 【Flask系列】开发一个简单的Flask程序

    知识点 初始化:每一个flask程序都必须创建一个程序实例,遵循WSGI(Web Server Gateway interface)协议,把请求->flask Obj; 创建实例: app = ...

  3. Cocos2d-x-Lua 开发一个简单的游戏(记数字步进白色块状)

    Cocos2d-x-Lua 开发一个简单的游戏(记数字步进白色块状) 本篇博客来给大家介绍怎样使用Lua这门语言来开发一个简单的小游戏-记数字踩白块. 游戏的流程是这种:在界面上生成5个数1~5字并显 ...

  4. 简单记账本APP开发一

    在对Android的一些基础的知识有了一定了解,以及对于AndroidStudio的如何使用有了 一定的熟悉后,决定做一个简单的记账本APP 开发流程 1.记账本的页面 2.可以添加新的账目 (一)页 ...

  5. Android-->发送短信页面实现(短信发送以及群发和从电话本中选择联系人)-----------》2

    分析下怎么写 首先,我们需要一个输入框,可以手动的输入手机号码, 其次,很少有人愿意手动输入,那么我们需要提供一个按钮来给我们的用户选择自己电话本中的联系人(一次可以选择多个即群发) 然后,我们需要一 ...

  6. 如何开发一个简单的HTML5 Canvas 小游戏

    原文:How to make a simple HTML5 Canvas game 想要快速上手HTML5 Canvas小游戏开发?下面通过一个例子来进行手把手教学.(如果你怀疑我的资历, A Wiz ...

  7. Objective C (iOS) for Qt C++ Developers(iOS开发,Qt开发人员需要了解什么?)

    Qt/C++开发人员眼中的Obj-C      对于我们第一次自己定义iOS应用来说,对于来自Qt/C++开发人员来说,我不得不学习Objective-C相关语法与知识 为了让读者可以更easy理解这 ...

  8. 用SpringBoot搭建简单电商项目 01

    前几节呢,我们已经简单介绍了SpringBoot框架的使用,从这一节开始,我们尝试着使用SpringBoot框架来一步一步搭建一个简单电商项目.当然了,这不是真正的电商项目,你可以看成是一个CRUD案 ...

  9. java模拟而一个电话本操作

    哈哈.大家平时都在使用电话本.以下使用java来模拟而一个简单的电话本吧... 首先给出联系人的抽象类 package net.itaem.po; /** * * 电话人的信息 * */ public ...

随机推荐

  1. Android——String.IndexOf 方法 (value, [startIndex], [count])

    报告指定字符在此实例中的第一个匹配项的索引.搜索从指定字符位置开始,并检查指定数量的字符位置.  参数 value  要查找的 Unicode 字符. 对 value 的搜索区分大小写. startI ...

  2. 信号值大于-75dBm时

    dBm是一个表示功率绝对值的值,是以1mw为0dbm,公式dbm=10×lg(毫瓦数/1).所以,为负值 这个值越大,表示信号越好,如-70dbm信号比-90dbm好  信号值大于-75dBm时,说明 ...

  3. linux下使用yum安装telnet

    参考文章: http://futeng.iteye.com/blog/2039490?utm_source=tuicool&utm_medium=referral

  4. 对于REST中无状态(stateless)的一点认识(转)

    在请求中传递SessionID被普遍认为是unRESTful的,而将用户的credentials包含在每个请求里又是一种非常RESTful的做法.这样一个问题经常会造成困扰.本文就REST的一些概念进 ...

  5. DataGridView使用技巧六:冻结列或行

    一.冻结列 DataGridViewColumn.Frozen属性为true时,该列左侧的所有列被固定,横向滚动时固定列不随滚动条滚动而左右移动.这对于重要列固定很有用. 示例:通过程序固定左侧第二列 ...

  6. 用大白话揭开Ajax长轮询(long polling)的神秘面纱

    在看这篇Ajax长轮询之前可以先看看Ajax轮询技术(没有长),有助于理解: Ajax长轮询属于Ajax轮询的升级版,在客户端和服务端都进行了一些改造,使得消耗更低,速度更快. "不间断的通 ...

  7. Tomcat负载均衡和集群环境的搭建

    实现此集群的方法参考了网上的很多文章,但由于很多文章都表明是原创的,故无法知道整个操作流程的真正作者是谁.下面就是我用我们真实的项目去实现这个过程.同时修复这过程中一些问题.以下的所有步骤均为亲自测试 ...

  8. RunnableException与CheckedException

    Checked Exception 编译时异常 编译的时候检查你的代码可能在运行的时候抛出异常,这通常在编译的时候要去处理的. RunnableException 运行时异常,可以编译通过,但如果不处 ...

  9. 关于PHP的特点

    魔术方法 当一个对象引用变量调用一个没有定义的属性或方法时,可以这一个函数.当发生这种情况时调用这种函数.

  10. 常用命令——sed详解

    以下内容参考:http://qifuguang.me/2015/09/21/sed命令详解/ sed是stream editor的简称,也就是流编辑器.它一次处理一行内容,处理时,把当前处理的行存储在 ...