目录
- 无用的前言(无用的话,无需用看)
- 前言
- 一、开发工具
- 二、功能演示以及 源码和安装包 下载
- 三、功能介绍以及设计思路
- 四、代码具体实现
- 五、打包程序(记得选择Release,但Debug也不是不行)
- 六、可能遇到的坑&FAQ
- 七、总结
无用的前言(无用的话,无需用看)
在大二上期中的一日大二的学子们要开始做他们大二的课设了,阿鑫选择了通讯录系统的题目,时隔一星期有余,阿鑫完成了他的代码编写工作,他决定写点东西了 应该和他发现课设报告内容和博客主体内容高度重合关系不算大吧 ,是该写点东西了,大二了,未曾发过一篇博客,却也怪他不得,毕竟他多年属于一种天南星科魔芋属多年生宿根性块茎草本植物,但写时还是用了些心的, 毕竟他平常注释少的可怜,这里居然这么多。
前言
利用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; //定义一个主窗口对象 w
w.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_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
QStringListModel *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对象 addui
addui.setWindowTitle(z("添加联系人")); //设置标题
addui.setWindowIcon(QIcon("images/Logo.ico")); //设置图标
addui.exec(); //显示
listinit(); //再次初始化列表(其实就是更新信息)
}
//删除联系人
void MainWindow::on_pushButton_3_clicked()
{
delUI dui; //定义一个delUI对象 dui
dui.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()); //转为string
mycall(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.cpp
QString name,phone;
int i;
tuser.clear(); //申明在mainwindow.h中对类MainWindow申明中,清空tuser;
for(i=0;i<users.size();i++){
name=QString::fromLocal8Bit(users[i].first.data()); //读取用户名字并转为qstring
phone = QString::fromLocal8Bit(users[i].second.data()); //读取用户电话并转为qstring
name = 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(); //清空users
idpixs.clear(); //清空idpixs
ifstream 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_OBJECT
public:
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转为qstring
tname=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()
{
//打开文件打开对话框,选择要读入的文本文件,并保存其路径到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.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_OBJECT
QStringListModel *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运行省事。
七、总结
就目前来说阿鑫的水平还是很水的 大一不好好学习吧 ,习惯也不太好,代码看上去混乱,还懒得写注释(在没写这篇博客前原本的注释只有每个函数前面说明下是干嘛的(最多每句也就七八个字)),一些多余的代码也懒得改,还有程序运行起来还有一些问题(比如最大化后不会自适应大小)。所以大家看看就好,不要被阿鑫误导。可维护性,可读性,鲁棒性,可复用性…这些可以说都和目前的阿鑫没啥关系。之后可能会开始不定期写点博客 (再不学点感觉要废了)。如果文中有错误,望指正,多谢。
最后附上单身狗靓仔照一张