目录

  • 无用的前言(无用的话,无需用看)
  • 前言
  • 一、开发工具
  • 二、功能演示以及 源码和安装包 下载
  • 三、功能介绍以及设计思路
  • 四、代码具体实现
    • 项目文件结构
    • main.cpp
    • mainwindow.ui
    • mainwindow.h
    • mainwindow.cpp
    • data.h
    • data.cpp
    • addui.ui
    • addui.h
    • addui.cpp
    • delui.ui
    • delui.h
    • delui.cpp
  • 五、打包程序(记得选择Release,但Debug也不是不行)
  • 六、可能遇到的坑&FAQ
    • 先用Qt Creator写的项目怎么用VS2019打开?(建议直接看方法二,方法二也更简单)
      • 方法一:使用vs拓展工具(写这个通讯录时一直折腾才成功一次,写博客时就一直翻车了, **建议直接看方法二,方法二也更简单** )
      • 方法二:使用命令行(暂无翻车情况)
    • 呼叫功能怎么配置呀(需要自己折腾一下 ~~最好别折腾,大概率会觉得不值得~~)?
    • 为什么用windeployqt 打包后的程序运行不正常呀?
    • 用vs打开后的项目再用Qt Creator修改没用欸
    • 自己电脑下载源码后vs2019运行报错
    • Qt Creator运行报错报错找不到相关.txt文件(VS一般不会出现)
    • 如果使用Qt Creator运行源码的一般步骤
  • 七、总结

无用的前言(无用的话,无需用看)

在大二上期中的一日大二的学子们要开始做他们大二的课设了,阿鑫选择了通讯录系统的题目,时隔一星期有余,阿鑫完成了他的代码编写工作,他决定写点东西了 应该和他发现课设报告内容和博客主体内容高度重合关系不算大吧 ,是该写点东西了,大二了,未曾发过一篇博客,却也怪他不得,毕竟他多年属于一种天南星科魔芋属多年生宿根性块茎草本植物,但写时还是用了些心的, 毕竟他平常注释少的可怜,这里居然这么多。

前言

利用C++和Qt编写带GUI(图形用户界面)的通讯录系统并打包,打包后可到其他电脑(没有安装vs和qt也使用)上正常运行(呼叫功能不可直接使用,需要配置,否则程序会崩),其他功能可正常使用),如果想自己运行源码的话,建议用vs2019打开,可以省去不少不必要的麻烦
因为阿鑫的水平很低,很多地方讲不清楚,如果没有接触过Qt的话强烈建议和类似参考书一同阅读。

当然也可在阿鑫的半成品个人博客网站上阅读:阿鑫的学习小站


素材来源:
大部分图片素材源于 iconfont-阿里巴巴矢量图标库和pixabay
通讯录像素图标源于以前改电脑桌面图标时找的(可以看出和桌面图标风格一致),忘记出处,不好意思,金城武的照片应该是源于网页直接搜索 似乎是当时父母想看我近期样貌情况而找的 (若侵权联系删除)。

学习Qt时的参考:《Qt5.12实战》(该书的书评似乎不佳,大家可以选取其他书籍)以及相关博客(太多了,不一一列举了,感谢分享相关问题解决方法的所有人)。


阿鑫也才初涉Qt,很多地方有待完善,主要希望可以和其他刚开始学习计算机的同学分享交流一些如何制作图形化界面的知识和一些学习过程中遇到的坑(毕竟一直看着黑框框会有一点点累),文章有些许长。


一、开发工具

Visual Studio2019和Qt Creator,vs的qt开发环境配置一类的教程很多,此处不做介绍。

二、功能演示以及 源码和安装包 下载

源码阿鑫没有在其他电脑上尝试过,不确定是否可以正常运行。但是打包好的程序和安装包在学校的机房的古董机上尝试过可以正常运行,安装包也可正常安装后使用(当然先前提到的 拨号 依旧需要配置才可以点击,不配置也可以正常运行,但请不要点击 拨号)。

功能演示:bilibili

如果要用vs运行源码的话,记得选择 Release x86
百度云链接: https://pan.baidu.com/s/1kJMQsWUTgZuD2uvB3xxG3g
提取码: 14h6

gitee链接:https://gitee.com/jason-czx/address-list
(多加了个播放bgm的功能,但是博客中没有提到 因为刚加)

三、功能介绍以及设计思路


阿鑫先利用Qt Creator来完成绝大多数的代码编写(初学者用Qt ),快完成时在利用vs2019完成剩下的功能完善。

四、代码具体实现

下面就详细讲讲文件的编写吧(以注释的形式)。主要讲解.cpp和.h文件。.ui文件大家感兴趣可以下载源码时看看,这个.ui文件利用Qt Designer会自动编写,难度不大(我这种蒟蒻不会写,只好拖拖拽拽了,哈哈),而且利用Qt Designer可以很方便的给按钮啥的绑定槽函数(转到槽)。

没有添加注释的代码大多不需要自己编写(也可能是没啥好注释的)。

项目文件结构


main.cpp

这个没有太多好说的

#include "mainwindow.h"
#include <QApplication>
#include "data.h"                                   //需要的头文件int main(int argc, char *argv[])
{QApplication a(argc, argv);                     //定义应用程序对象MainWindow w;                                   //定义一个主窗口对象 ww.show();                                       //显示主窗口w.setWindowIcon(QIcon("images/Logo.ico"));      //更改主窗口图标return a.exec();                                //事件循环
}

mainwindow.ui


实际运行的效果

mainwindow.h

主窗口程序头文件,主要就是各种需要的函数的定义

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QStringListModel>
#include <QModelIndex>
#include <QStandardItemModel>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTQStringListModel *model;                //添加的成员变量QStringList tuser;                      //添加的成员变量public:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots://下面是槽函数们,会被对应的信号触发,即对应按钮被点击时,按钮的部分由Qt Designer自动绑定void on_pushButton_clicked();           //查找联系人void on_pushButton_2_clicked();         //新建联系人void on_pushButton_3_clicked();         //删除联系人void on_pushButton_4_clicked();         //拨号void on_pushButton_5_clicked();         //设置头像void on_pushButton_6_clicked();         //设置窗口背景//下面是自己编写的函数,此处申明,之后在mainwinodw.cpp中定义void re_change(QModelIndex index);      //选择列表用户改变ID框和电话框void listinit();                        //初始化右侧列表 private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

提前说的话
拨号 (这个功能需要配置一下 你的手机 这款应用,没有就不要点,否则点击会崩溃,会在data.cpp中提到),如果直接用Qt Creator打开的话把这函数注释掉,包括data.cpp中的对他的定义,否则也会报错,原因会在data.cpp中提到,vs打开则不需要注释掉
(我也觉得很捞)

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "addui.h"
#include "data.h"
#include "delui.h"
#include <QMessageBox>
#include <QDialog>
#include <QWidget>
#include <QFileDialog>using namespace std;#define z(s) (QString::fromLocal8Bit(s))      //定义z(s)方便使用,其作用是为了让中文可以正常显示MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);listinit();                               //自己编写的函数,用于主窗口初始化QModelIndex index = model->index(0);      //即设置第一个用户ui->listView->clicked(index);             //默认点击列表的一个用户(让头像显示第一个用户)ui->listView->setCurrentIndex(index);     //默认选择列表的一个用户(让用户和电话显示第一个用户)//用户和姓名文本框设为只读,否则可以修改(有兴趣的同学也可以不设为只读,添加并绑定新的槽函数(需同学额外编写),使得更改的用户名和电话可保存)ui->lineEdit_2->setReadOnly(true);         ui->lineEdit_3->setReadOnly(true);
}MainWindow::~MainWindow()
{delete ui;}//查找联系人
void MainWindow::on_pushButton_clicked()
{QString qname = ui->lineEdit->text();               //读取查找文本框内文字(姓名)//将其转化为string类,为什么要转化呢,其实就是阿鑫太菜了,初学Qt对Qt数据类型的用法不太清楚,转为string后很多对阿鑫来说就好写了string name=string(qname.toLocal8Bit());            int i;//vector<pair<string, string> >users申明在data.h中,之后会讲,first存的名字,second存的电话for(i=0;i<users.size();i++)                         {if(users[i].first==name){                       //如果存的用户中有叫这个名字的人break;}}if(i>=users.size()){                                //即没这个人QMessageBox::information(this,z("错误"),z("查无此人"));       //消息弹窗,提醒查无此人ui->lineEdit->setText("");                      //清空查找文本框内容}else{                                              //即有这个人    QString qphone;qphone = QString::fromLocal8Bit(users[i].second.data());    //记录他电话,并将string转为qstring,否则下面会报错ui->lineEdit_2->setText(qname);                 //姓名文本框显示他的名字ui->lineEdit_3->setText(qphone);                //电话文本框显示他的电话//下面几行就是选中并点击该用户(触发对应槽函数)来显示 姓名,电话和头像,仔细一看上面几行似乎多余了,不删了吧listinit();                                     QModelIndex index = model->index(i);ui->listView->setCurrentIndex(index);           ui->listView->clicked(index);                       QMessageBox::information(this, "note", z("已成功找到"));     //消息弹窗,已成功找到ui->lineEdit->setText("");                      //清空查找文本框内容}
}//新建联系人
void MainWindow::on_pushButton_2_clicked()
{addUI addui;                                        //定义一个addUI对象 adduiaddui.setWindowTitle(z("添加联系人"));              //设置标题addui.setWindowIcon(QIcon("images/Logo.ico"));      //设置图标addui.exec();                                       //显示listinit();                                         //再次初始化列表(其实就是更新信息)
}//删除联系人
void MainWindow::on_pushButton_3_clicked()
{delUI dui;                                          //定义一个delUI对象 duidui.setWindowTitle(z("删除联系人"));                //设置标题dui.setWindowIcon(QIcon("images/Logo.ico"));        //设置图标dui.exec();                                         //显示listinit();                                         //再次初始化列表(其实就是更新信息)
}//拨号 (这个需要配置一下 你的手机 这款应用,没有就不要点,否则点击会崩溃,会在data.cpp中提到)
//如果直接用Qt Creator打开的话把这函数注释掉,包括data.cpp中的对他的定义,原因会在data.cpp中提到,vs打开则不需要注释掉
void MainWindow::on_pushButton_4_clicked()
{QString phone = ui->lineEdit_3->text();             //读取电话文本框的内容string tphone;tphone = string(phone.toLocal8Bit());               //转为stringmycall(tphone);                                     //在data.cpp中定义
}//设置头像
void MainWindow::on_pushButton_5_clicked()
{//打开文件选择对话框,设定只可以选择.png和.jpg文件并利用qpath保存文件路径QString qpath = QFileDialog::getOpenFileName(this,z("选择导入头像"),".","image file(*.png *.jpg);");QModelIndex index = ui->listView->currentIndex();   //读取当前用户列表中选中的用户int idx = index.row();                              //idx保存他在第几行(对应他保存时的下标)if(qpath == "") qpath = "images/human.png";         //如果读取路径为空,即直接关闭了,则设为默认图形位置idpixs[idx] = qpath;                                //将图像路径保存,(QVector<QString> idpixs申明在data.h,用于存头像文件路径)//下面两行用于将头像更改qpath = "#widget_5{border-image:url("+ qpath +");}";//将widget_5的背景更改的语句ui->widget_5->setStyleSheet(qpath);                 //即更改头像窗口的样式表//保存修改后的图片路径,否则下次重新运行时头像又是默认头像了QFile pixfout("idpix.txt");                        //idpix.txt存头像图片路径,使得下次打开程序是头像会显示之前设置的     if(!pixfout.open(QIODevice::WriteOnly | QIODevice::Text)) {cout<<"can not open the idpix.txt"<<endl;      //打不开保存的文件(用cout其实打包后这个似乎并没用,只是我最初编写时为了方便自己查看问题)}for(int i=0;i<users.size();i++){pixfout.write((idpixs[i]+"\n").toUtf8());      //将头像文件路径依次写入idpix.txt}pixfout.close();
}//设置窗口背景
void MainWindow::on_pushButton_6_clicked()
{//此处和头像更改几乎一样不多做解释//但这里你也可以看到将路径保存到.txt文件的用处了//头像更改后,再次打开头像显示会是更改后的,但是背景更改后再次打开会又变成默认背景(毕竟没有保存嘛)QString qpath = QFileDialog::getOpenFileName(this,z("选择导入背景"),".","image file(*.png *.jpg);");if (qpath == "") qpath = "images/flowers.png";qpath = "#MainWindow{border-image:url("+ qpath +");}";this->setStyleSheet(qpath);
}//选择列表用户改变ID框和电话框
void MainWindow::re_change(QModelIndex index)           //这个函数绑定的信号是点击列表用户时触发,可在下面的listinit()中看到
{int idx;idx = index.row();                                  //idx保存传来的index的所在行数(其与保存下标相等)(当然也是从第0行开始)QString name,phone,qpath;name = QString::fromLocal8Bit(users[idx].first.data());   //保存名字phone = QString::fromLocal8Bit(users[idx].second.data()); //保存电话ui->lineEdit_2->setText(name);                      //姓名文本框显示他的名字ui->lineEdit_3->setText(phone);                     //电话文本框显示他的电话//下面几行使得图片窗口显示他的头像qpath = idpixs[idx];qpath = "#widget_5{border-image:url("+ qpath +");}";ui->widget_5->setStyleSheet(qpath);
}//初始化右侧列表
void MainWindow::listinit()
{myinit();                                           //申明在data.h,定义在data.cppQString name,phone;                         int i;tuser.clear();                                      //申明在mainwindow.h中对类MainWindow申明中,清空tuser;                for(i=0;i<users.size();i++){name=QString::fromLocal8Bit(users[i].first.data());     //读取用户名字并转为qstringphone = QString::fromLocal8Bit(users[i].second.data()); //读取用户电话并转为qstringname = name +" : "+ phone;                              //组合在一起tuser.push_back(name);                                  //将其放入tuser中}model = new QStringListModel(this);                        model->setStringList(tuser);                        //将tuser放到model里面ui->listView->setModel(model);                      //将model放到listView里面//这里为什么不能直接放呢,说下我个人的理解(很可能错的,大家听我瞎说一下就好,若有幸遇见懂得的大佬,希望可以指正一下我)//阿鑫以为其结构为QListView->QStringListModel->QStringList,可将QStringList比作内存,cpu一类,QStringListModel比作主板,//QListView比作机箱,要先将内存一类先装入主板,再将主板装入机箱,而不可直接将内存一类直接装于机箱//下面一行将列表用户被点击的信号和自己写的re_change(QModelIndex)槽函数绑定connect(ui->listView,SIGNAL(clicked(QModelIndex)),this,SLOT(re_change(QModelIndex)));  ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers); //设置列表的文本不可编辑
}

data.h

#ifndef DATA_H
#define DATA_H#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <fstream>
#include <QStringList>
#include <QFile>
#include <QVector>using namespace std;
//extern 是为了让其他程序访问以下变量,注意在此处申明但不要定义
extern vector<pair<string, string> >users;  //用于保存姓名和电话
extern QVector<QString> idpixs;               //用于保存头像图片文件路径
extern string s, name, phone;               extern void myinit();                       //初始化,读取文本文件中的内容
extern void myfinish();                     //保存修改后的内容到文本文件中
extern int myfind(string a,string b);       //查找用户是否存在
extern void mycall(string s);               //拨号#endif // DATA_H

data.cpp

#include "data.h"vector<pair<string, string> >users;
QVector<QString> idpixs;
string s, name, phone;//拨号(用Qt Creator或者没有配置 你的手机 的话记得把这段函数注释掉)
void mycall(string s) {                              //传入电话的字符串//这里可以看出来阿鑫实现拨号的方法很笨(但确实是阿鑫当时可以想到最简单的方法了)//利用命令行打开 你的手机的快捷键 即打开这款应用system("C:\\Users\\lenovo\\Desktop\\communication\\你的手机.lnk");  //等待四秒(应用打开需要时间,但实际发现两秒就完全够了,四秒是为了保险)Sleep(4000);for (int i = 0; i < s.size(); i++) {             //将电话的每一位数字按顺序按下keybd_event(s[i], 0, 0, 0);                  //将对应的按键按下keybd_event(s[i], 0, KEYEVENTF_KEYUP, 0);    //将对应的按键抬起,组合以及就是模拟键盘输入}//下面四行就是点两下回车(也就是确认拨号键和拨号)keybd_event(VK_RETURN, 0, 0, 0);keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);keybd_event(VK_RETURN, 0, 0, 0);keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
}//初始化,读取文本文件中的内容
void myinit() {users.clear();                                  //清空usersidpixs.clear();                                 //清空idpixsifstream data("userbook.txt");                  //打开存有用户信息的文本文件QFile file("idpix.txt");                        //打开存有用户头像文件路径的文本文件if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {cout<<"can not open the idpix.txt"<<endl;}while(!file.atEnd()) {QString line = file.readLine();          //一行一行读line =line.trimmed();                       //去掉回车idpixs.push_back(line);                     //将路径存入idpixs}while (data >> s) {                             //读一行名字name = s;                                   data >> s;                                  //读下一行的电话phone = s;                                  users.push_back(make_pair(name, phone));    //保存用户姓名和电话到users}//文件关闭data.close();file.close();
}//保存修改后的内容到文本文件中
void myfinish() {//打开文件ofstream fout("userbook.txt");      QFile pixfout("idpix.txt");if(!pixfout.open(QIODevice::WriteOnly | QIODevice::Text)) {cout<<"can not open the idpix.txt"<<endl;}for(int i=0;i<users.size();i++){//将对应信息分别写入对应的文本文件fout << users[i].first << " " << users[i].second << endl;pixfout.write((idpixs[i]+"\n").toUtf8());}//文件关闭fout.close();pixfout.close();
}//查找用户是否存在
int myfind(string a, string b) {for (int i = 0; i < users.size(); i++) {if (users[i].first == a && users[i].second == b) {   //找到了名字和电话都相同的用户return i+1;                                      //返回他的位置,(背后完善mainwindow时忘记写过了这个了,啧)}}return 0;
}

addui.ui


实际运行的效果

addui.h

#ifndef ADDUI_H
#define ADDUI_H#include <QDialog>namespace Ui {class addUI;
}class addUI : public QDialog
{Q_OBJECTpublic:explicit addUI(QWidget *parent = nullptr);~addUI();private slots://三个槽函数申明void on_pushButton_clicked();void on_pushButton_2_clicked();void on_pushButton_3_clicked();private:Ui::addUI *ui;
};#endif // ADDUI_H

addui.cpp

#include "addui.h"
#include "ui_addui.h"
#include "data.h"
#include <QMessageBox>
#include <QFileDialog>#define z(s) (QString::fromLocal8Bit(s))
addUI::addUI(QWidget *parent) :QDialog(parent),ui(new Ui::addUI)
{ui->setupUi(this);}addUI::~addUI()
{delete ui;
}//添加单个用户
void addUI::on_pushButton_clicked()
{QString name = ui->lineEdit_2->text();        //读取姓名文本框中的姓名QString phone = ui->lineEdit->text();         //读取电话文本框中的电话string tname,tphone;//stirng转为qstringtname=string(name.toLocal8Bit());tphone=phone.toStdString();myinit();                                     //读入(初始化)一下数据int flag;flag=myfind(tname,tphone);                    //看是否有名字和电话相同的人存在if(flag!=0){                                  //有QMessageBox::information(this,z("错误"),z("该用户已存在"));//弹出消息窗口提示}else{                                        users.push_back(make_pair(tname, tphone));//没有则将他添加进来idpixs.push_back("images/human.png");     //将头像设为默认头像QMessageBox::information(this,z("完成"),z("添加成功"));//弹出消息窗口提示myfinish();                              //保存数据,重新存入对应文本文件中}//文本框清空ui->lineEdit->clear();ui->lineEdit_2->clear();
}//取消关闭添加
void addUI::on_pushButton_2_clicked()
{this->close();
}//导入名单
void addUI::on_pushButton_3_clicked()
{//打开文件打开对话框,选择要读入的文本文件,并保存其路径到qpathQString qpath = QFileDialog::getOpenFileName(this,z("选择导入名单"),".","txt file(*.txt);");string path,tname,tphone;path = string(qpath.toLocal8Bit());ifstream data(path);                        //打开选择的文本文件myinit();                                   //数据初始化,即读入原有数据while (data >> s) {tname = s;data >> s;tphone = s;int flag;flag=myfind(tname,tphone);              //判断导入名单中当前导入的用户是否存在,避免重复添加if(flag!=0){continue;}else{users.push_back(make_pair(tname, tphone));  //存入姓名电话idpixs.push_back("images/human.png");       //设为默认头像}}data.close();QMessageBox::information(this,z("完成"),z("添加名单成功"));//弹出消息窗口提示myfinish();                                 //保存数据,重新存入对应文本文件中
}

delui.ui


实际运行的效果

delui.h

#ifndef DELUI_H
#define DELUI_H#include <QDialog>
#include <QStringListModel>
#include <QFile>namespace Ui {class delUI;
}class delUI : public QDialog
{Q_OBJECTQStringListModel *model;                //添加的成员变量,列表实现老工具人了QStringList tuser;                      //添加的成员变量public:explicit delUI(QWidget *parent = nullptr);int mulflag;                            //实现快速删除时会用到~delUI();private slots:void on_pushButton_clicked();void on_pushButton_2_clicked();void on_pushButton_3_clicked();    void on_pushButton_4_clicked();void on_pushButton_5_clicked();void on_pushButton_6_clicked();//下面为为实现快速删除设置的函数void del_change(QModelIndex index);private:Ui::delUI *ui;
};#endif // DELUI_H

delui.cpp

#include "delui.h"
#include "ui_delui.h"
#include <QMessageBox>
#include <QFileDialog>
#include "data.h"#define z(s) (QString::fromLocal8Bit(s))
delUI::delUI(QWidget *parent) :QDialog(parent),ui(new Ui::delUI)
{ui->setupUi(this);int i;mulflag = 0;                                        //默认快速删除关闭myinit();                                           //初始化(读入数据)//下面这一段和mainwindow.cpp那一段类似,目的就是初始化列表,不再多介绍QString name,phone;for(i=0;i<users.size();i++){name=QString::fromLocal8Bit(users[i].first.data());phone = QString::fromLocal8Bit(users[i].second.data());name = name +" : "+ phone;tuser.push_back(name);}model = new QStringListModel(this);model->setStringList(tuser);ui->listView->setModel(model);ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);//绑定列表成员被点击时的信号和槽函数del_change(QModelIndex)connect(ui->listView,SIGNAL(clicked(QModelIndex)),this,SLOT(del_change(QModelIndex)));ui->textBrowser->setText(z("快速删除:关闭")); //默认显示关闭ui->textBrowser->setFocusPolicy(Qt::NoFocus);  //使得 快速删除状态栏 不可被聚焦(点不了)
}delUI::~delUI()
{delete ui;
}//快速删除开
void delUI::on_pushButton_clicked()
{ui->textBrowser->setText(z("快速删除:开启"));mulflag=1;
}//快速删除关
void delUI::on_pushButton_2_clicked()
{ui->textBrowser->setText(z("快速删除:关闭"));mulflag=0;
}//导入黑名单
void delUI::on_pushButton_3_clicked()
{//qpath保存选择的名单路径QString qpath = QFileDialog::getOpenFileName(this,z("选择导入名单"),".","txt file(*.txt);");string path,tname,tphone;path = string(qpath.toLocal8Bit());ifstream data(path);myinit();while (data >> s) {tname = s;data >> s;tphone = s;int flag;flag=myfind(tname,tphone);                      //查看黑名单的用户是否存在if(flag==0){                                    //不存在直接跳过continue;}else{                                          //存在就删掉有关他的信息users.erase(users.begin()+flag-1);idpixs.erase(idpixs.begin()+flag-1);model->removeRow(flag-1);}}data.close();QMessageBox::information(this,z("完成"),z("删除全体在黑名单中的成员成功"));//消息窗口提醒myfinish();                                         //保存数据
}//清空列表
void delUI::on_pushButton_4_clicked()
{model->removeRows(0,model->rowCount());             //清空列表内容users.clear();                                      //清空用户姓名电话idpixs.clear();                                     //清空用户头像myfinish();                                         //保存数据
}//删除
void delUI::on_pushButton_5_clicked()
{    int row_idx;QModelIndex index = ui->listView->currentIndex();   //index存当前所在列表的下标row_idx = index.row();                              //第几行model->removeRow(row_idx);                          //删掉那一行users.erase(users.begin()+row_idx);                 //清除他的名字电话idpixs.erase(idpixs.begin()+row_idx);               //清除他的头像myfinish();                                         //保存数据
}//完成
void delUI::on_pushButton_6_clicked()
{myfinish();                     //退出前保存数据this->close();
}//快速删除实现
void delUI::del_change(QModelIndex index)
{if(mulflag==1){on_pushButton_5_clicked();  //即开启后点击用户直接删除(自动帮你点击 删除 按钮)}
}

五、打包程序(记得选择Release,但Debug也不是不行)


在项目的release(如果之前选的Debug就在debug中找)文件夹中找到对应的.exe文件,将他和项目需要的图片素材文件夹,用于保存用户信息和头像的两个文本文件单独放在一个新的文件夹内,如下。

并复制此文件夹的路径
打开Qt命令行工具

输入命令 windeployqt 对应的文件路径

按下回车

此时再去看文件夹就多了不少东西了(打包完成)

这个时候即使在一台没有设置C++环境和安装Qt之类的电脑上点击.exe也可以正常使用程序啦
最后,为他创建一个快捷键,再更改一下图标就像那么一回事了


六、可能遇到的坑&FAQ

先用Qt Creator写的项目怎么用VS2019打开?(建议直接看方法二,方法二也更简单)

方法一:使用vs拓展工具(写这个通讯录时一直折腾才成功一次,写博客时就一直翻车了, 建议直接看方法二,方法二也更简单

第一种呢 就是打开vs2019,在vs顶部工具栏中依次点击:拓展->管理拓展,然后下载Qt Visual Studio Tools(这个方法阿鑫只有一次成功了,背后一直不行,不清楚是不是阿鑫自己的问题,所以不做多介绍,但还是分享下阿鑫的翻车路程,感兴趣可自行了解)

安装后依次点击:拓展->Qt VS Tools->Open Qt Pro Project File(.pro)…

选择需要打开的项目的.pro文件

可能会和我一样报错,但问题不大 毕竟有方法二吗 ,点击确认

这个时候我们再去打开需要打开的项目文件夹我们会发现他多了些许东西,点击 .vcxproj 以为后缀的文件

点击后就会自动在vs中打开我们的项目,点击运行,如果你和我一样 sui 的话,运行是没反应的,但问题不大,点击关闭,他会弹出下面这个窗口

都点击保存

阿鑫之前这样再多折腾一下似乎就差不多可以了(背后怎么折腾了一下也忘记了),但是确实现在一直翻车。

方法二:使用命令行(暂无翻车情况)

首先cmd进入到项目的目录下(可直接到该目录下输入cmd再回车)

输入命令qmake -tp vc xx.pro 再回车
讲xx.pro换为自己的pro文件,如阿鑫这里就是qmake -tp vc Cyzx.pro

之后再回到项目目录下就可以看到新增了几个文件,点击其中的.vcxproj文件后会自动打开vs,就可以正常运行了。

呼叫功能怎么配置呀(需要自己折腾一下 最好别折腾,大概率会觉得不值得)?

呼叫功能利用的是win10中系统自带的 “你的手机”
使用方法可自行搜索 “你的手机” 关键词查看(一是阿鑫懒得写了,二是记得有点点麻烦记不清了)
当电脑上 “你的手机” 和手机上 “你的手机助手” 都安装好后就可以连接起来进行下一步了。
(连接时可能需要使用科学的方法 )

如果可以修改源码就将 data.cpp中的void mycall(string s) 函数中的 “C:\Users\lenovo\Desktop\communication\你的手机.lnk” 中的
C:\Users\lenovo\Desktop\communication 改到自己的快捷键路径下

如果不会的话就为 “你的手机” 创造快捷键放到
C:\Users\lenovo\Desktop\communication 目录下(太捞了,这种话我怎么说的出口)
之后就可以正常使用了,

为什么用windeployqt 打包后的程序运行不正常呀?

如果程序中使用到了 音频,图片或者文本文件之类的资源 的话记得要一同复制到打包的目录下,这些文件需要手动复制。

用vs打开后的项目再用Qt Creator修改没用欸

阿鑫开始使用Qt Creator写的,后期用了vs2019,背后再想用Qt Creator(也就图个转到槽方便)写时发现了这个问题,但阿鑫并没有去解决,因为阿鑫发现用vs打开的Qt Designer 还是可以正常使用的,少个转到槽而已,自己声明下,再用connect绑定一下,用vs写也挺舒服(可以参考 on_pushButton_7_clicked 之类的编写)(其实一开始就一直用vs也挺好的,省的Qt Creator转到vs写麻烦)。
可能要将vs项目再次导入Qt Creator中才可以正常使用Qt Creator编写吧,但阿鑫没试过,大家感兴趣可以试试,方法估计类似前面提到的 Qt Creator写的项目怎么用VS2019打开 。


自己电脑下载源码后vs2019运行报错

可能的原因其实前面已经讲过。
可能是因为用的dubug运行的,应该要选择 Release x86才可正常运行

Qt Creator运行报错报错找不到相关.txt文件(VS一般不会出现)

将data.cpp中的相对路径改为自己电脑上的绝对路径。因为阿鑫在后面改用vs写了,而且如果让别人用的话每个人的绝对路径不一样,所以改为了相对路径,这在VS2019运行是正常的,所以也没有注意,但是Qt Creator的话会报错,还有其实userbook.txt用Qt Creator这样应该也打不开的,只是阿鑫只写了idpix.txt的异常处理。当然其他文件内含有文件路径的地方也需要修改,否则会发现图片没保存,没读取成功之类的。

如果使用Qt Creator运行源码的一般步骤

‍首先需要你重新打开一个新的没有修改过的项目(可以理解为重新下载源文件,再用qt creator打开该项目,点击.pro文件就可以打开了)。再将data.cpp中对mycall(string s)的定义和mainwindow.cpp的void MainWindow::on_pushButton_4_clicked()注释掉,其次qt creator似乎不像vs一样可以那样方便的用相对路径(但每台电脑的绝对路径又不太一样,所以还是用的相对路径),所以要如果用qt creator的话要将所有相对路径改为绝对路径,一般修改掉data.cpp的void myinit() 中的两个路径后就可以运行,但是很多功能都不管用(因为其他的相对路径还没修改),将其他所有相对路径改为绝对路径后功能就可以正常使用了(一般你发现哪里功能不对的话,就是哪里路径没改,比如bgm播放点了没播放,就是bgm相关函数内的路径没修改)。所以还是建议使用vs运行省事。

七、总结

就目前来说阿鑫的水平还是很水的 大一不好好学习吧 ,习惯也不太好,代码看上去混乱,还懒得写注释(在没写这篇博客前原本的注释只有每个函数前面说明下是干嘛的(最多每句也就七八个字)),一些多余的代码也懒得改,还有程序运行起来还有一些问题(比如最大化后不会自适应大小)。所以大家看看就好,不要被阿鑫误导。可维护性,可读性,鲁棒性,可复用性…这些可以说都和目前的阿鑫没啥关系。之后可能会开始不定期写点博客 (再不学点感觉要废了)。如果文中有错误,望指正,多谢。
最后附上单身狗靓仔照一张

通讯录系统图形化界面(C++,Qt5.12)(Visual Studio2019,QtCreator)(初学)相关推荐

  1. Python学生信息管理系统图形化界面-老师端-学生端项目实现

    Student-information-management-system 本项目是一个学生信息管理系统,这个项目是用Python语言实现的,也实现了图形化界面的显示,同时也实现了管理员端,学生端两个 ...

  2. centos7操作系统图形化界面和命令行界面切换

    centos7操作系统 由图形化界面切换到命令行界面:ctrl+alt+f2+(fn) 由命令行界面切换到图形化界面:ctrl+alt+f1+(fn) 如果是笔记本电脑,输入上述命令时记得加上fn,即 ...

  3. debian+linux百度云,Linux Centos/Ubuntu/Debian系统图形化界面挂BT、PT一键包(rtorrent+rutorrent)...

    大概三个月以前吧,入手了一个DS的128M内存的年付vps.说实话,价格低超售肯定很严重,内存又少,就将它闲置了几个月.前且日子拿来测试下,发现性能还不错,估计折腾的人也不折腾了,想着好东西不要浪费, ...

  4. vncserver对linux系统图形化界面

    参考连接:使用VNC Viewer连接Linux云服务器_弹性云服务器 ECS_最佳实践_华为云 (huaweicloud.com) 在本地安装vncviewer,在Linux安装vncserver, ...

  5. ubuntu 无法进入startx_Ubuntu无法进入图形化界面(报错/dev/sda1:clean的解决)

    进入命令行模式,执行下面的命令: rm -rf /etc/X11/xorg.conf cp /etc/X11/xorg.conf.failsafe /etc/X11/xorg.conf 重启电脑. 上 ...

  6. ubuntu18.04 安装qt5.12.8及环境配置的详细教程

    这篇文章主要介绍了ubuntu18.04 安装qt5.12.8及环境配置的教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 环境 系统: ...

  7. linux yum 安装widget,CentOS 7安装Qt5.12.1过程

    默认下载在Downloads目录下 预安装 sudo yum -y install mesa-libGL-devel mesa-libGLU-devel freeglut-devel 给下载的文件赋予 ...

  8. Firefly AIO-3399ProC开发板与PC端部署Qt5.12.2交叉编译环境

    文章目录 前言 一.Qt是什么? 二.开发部署环境 三.部署Qt5.12.2交叉编译环境 3.1 安装前的相关包下载及环境准备 3.2 在开发板端部署Qt5.12.2交叉编译环境 3.3 在PC端部署 ...

  9. Win10/Win7离线搭建Qt5.12+MinGW/MSVC2015开发环境

    三种Qt开发环境方案 Win10搭建Qt + Clion 版本选择与开发环境方案 Qt5.12.8 + Clion/QtCreator + MinGW:无法使用MSVC编译的lib库 Qt5.12.8 ...

  10. ubuntu18.04 安装qt5.12.8及环境配置

    文章目录 一.下载安装包 二.安装 三.QT项目测试 环境 系统:ubuntu18.04 软件:qt5.12.8 一.下载安装包 下载地址http://download.qt.io/archive/q ...

最新文章

  1. java 它 引用(基本类型的包装,构造函数和析构函数c++不同)
  2. OpenMV中AprilTag识别Python程序源码
  3. 了解linux内核必读的5本书
  4. java 序列化 原理解析
  5. 【bzoj1597】 土地购买
  6. VirtualBox命令更改虚拟硬盘空间
  7. 数论 —— 莫比乌斯反演
  8. SpringCloud Hoxton版微服务- OpenFeign实现服务调用
  9. Archlinux 安装软件(更新系统)报错
  10. php奖学金系统,java/php/net/pythont奖助学金管理系统设计
  11. 医院PACS系统源码
  12. 新大陆云平台使用笔记
  13. 自媒体免费编辑工具竞品分析 135编辑器乐观号媒号通三大功能优劣报告
  14. 人类历史上最智慧的169条警世箴言(句句珠玑,发人深省)
  15. SQL Sever 各版本下载 SQL Server 2012下载SQL Server 2008下载SQL Server 2005 下
  16. 复制微信号并跳转到微信界面
  17. 弘扬奥运精神,我们49行画个奥运五环
  18. docker 下载mysql 8.0_docker安装mysql8.0
  19. acm的比赛经验和组队说明
  20. PSpice 常见问题

热门文章

  1. python——【2】gzip模块二进制格式读取压缩文件
  2. Windows7系统提示当前页面的脚本发生错误怎么办
  3. 1.工作汇报结构: 黄金圈法则结构、PREP结构、时间轴结构、金字塔结构
  4. Python实现基于ClipCap的看图说话Image Caption模型
  5. Kibana操作Elasticsearch-Aggregations聚合数据分析
  6. CVPR'22 最新132篇论文分方向整理|包含目标检测、图像处理、医学影像等28个方向...
  7. 10年软件测试行业经验教你如何写简历【绝对靠谱】
  8. Python基础学习之正则表达式(完整版)
  9. Java实现PDF转换成图片
  10. 加了尾注怎么添加新页_如何在毕业论文利用尾注添加参考文献之后再续正文