记一次开发:Qt简单电话本程序

前言

断断续续学习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()==1)
    {
        QString line = editDialog.name()+"---"+editDialog.number();
        ui->listWidget->addItem(line);
        this->statusBar()->showMessage("1 item added",2000);//设置状态栏的提示信息 
    }
}

我们在这个槽里实例化一个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[0]);
    editDialog.setNumber(parts[1]);
 
    if(editDialog.exec()==1)
    {
        ui->listWidget->currentItem()->setText(editDialog.name()+"---"+editDialog.number());
        this->statusBar()->showMessage("1 item updated",2000);
    }
}

这里用到了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()==1)
    {
        delete ui->listWidget->currentItem();
        this->statusBar()->showMessage("1 item deleted",2000);
    }
}

查找

这个是最难写的一个功能,还是先做查询窗口,这次我选择了没有按钮的对话框类,命名为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()==0)
    {
        ui->resLabel->setText("No results!");
        return;
    }
    else
    {
        QString resNumber = QString::number(resList.size());//注意这里的字符串处理 
 
        ui->resLabel->setText(resNumber+" item(s) founded:");
 
        for(int i=0;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=0;i<ui->listWidget->count();i++)
        {
            out<<ui->listWidget->item(i)->text()<<endl;
        }
        file.close();
        this->statusBar()->showMessage("File saved",2000);
    }
    else
    {
        this->statusBar()->showMessage("Save failed!",2000);
        return;
    }
}

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

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

源码

请查看我的github:

github.com/MarkLux/Qt-PhoneBook

 

posted @ 2016-07-06 23:41  DigitalHermit  阅读(3105)  评论(0编辑  收藏  举报