QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)

目录

  • 写在前面
  • 实训前一天
    • 头文件无法生成
    • 项目栏不见了
    • 不知道如何发布程序
  • 实训第一天(附简易计算器的实现)
    • 自定义命名空间的相关问题
    • 关于隐式调用构造函数的问题
  • 实训第二天(不附地址薄的实现)
    • 关于on_pushButton_clicked()的默认connect
    • 加图标、背景图片的几种方法
  • 实训第三天(附qq登录界面的实现)
    • MainWindow设置setLayout布局时没用?
  • 实训第四天(附QPainter基本绘图)
    • ① Q_OBJECT报错问题 error: undefined reference to `vtable for PaintArea'
    • ② 构造函数出错 error: no matching function for call to 'PaintArea::PaintArea(Widget*)'
    • ③构造函数出错 error: return type specification for destructor invalid void Widget::~Widget()
  • 实训第五天
  • 实训第六天
  • 实训第七天
    • QT资源文件过大引发的问题 cc1plus.exe:- 1: error: out of memory allocating 1073745919 bytes
    • ui设计界面上添加的菜单栏、按钮等控件在程序上显示不了
  • 实训第八天
    • 关于ui设计界面的一些用法(小总结)
    • 如何在界面上新建一个动图
  • 实训第九天
    • 线程操作ui界面问题:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread.
  • 实训第十天
    • 线程创建对象,构造函数操作了界面 ASSERT failure in QWidget: "Widgets must be created in the GUI thread."
    • 跨线程传递自定义参数 QObject::connect: Cannot queue arguments of type 'ThreadSignal' (Make sure 'ThreadSignal' is registered using qRegisterMetaType().)
  • 实训第十一天
  • 实训第十二天
  • 实训第十三、十四天
    • 关于内存的那点事
    • 项目最终效果展示

写在前面

撑住,就要睡觉了

我一开始以为要放暑假了实训应该挺轻松的,就是大家一起做做项目挺有趣的,直到老师第一天要我们做出个计算器,第二天要我们做出个地址簿,然后我每天就几乎没干过别的事情了
一般睡觉时间是凌晨1~2点
换了个头像,我觉得比较适合我敲代码的样子
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第1张图片
结束的时候再换了个头像,还是豌豆射手好看些,梦开始的地方
在这里插入图片描述

实训前一天

任务:第一个Qt程序

  1. Qt下载与安装
  2. 创建图形界面应用程序,显示“Hello World”
    ① 使用纯代码方式编写
    ② 使用.ui文件

头文件无法生成

ctrl shift+B的时候出现 Makefile.Debug: No such file or directory
搜集了各种头文件无法生成原因的资料,附上网址:
添加ui文件以及构建ui头文件方法
QT中 No such file or directory的解决办法
(存着以后也许用得到)

QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第2张图片
调试了很久,原因竟是自己在.pro文件里少打了个字母p
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第3张图片
所以出现这种问题很可能就是自己疏忽输错了
另:网上查找之后发现只需ctrl+B就够了,加上shift老是把我搜狗的颜文字给弹出来了
ctrl+B就是编译的意思,编译不成功就生成不了头文件

项目栏不见了

控件-Show Sidebar,我是不小心关掉的,学习许多软件都会出现这种情况,一般的解决方法都是去找窗口栏
在这里插入图片描述
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第4张图片

不知道如何发布程序

在dubug文件里找到.exe文件后,直接打开会报系统错误
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第5张图片
存疑(明天的我比今天的我更有智慧解决问题)
(实训第二天更)
听课听了一半,在文件夹里找齐了这些ddl
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第6张图片
自信满满以为可以芜湖起飞,结果还是报错
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第7张图片
好在找到了一篇文章,分享一下:
Qt程序打包发布方法
这工具是Qt自带的,左下角搜qt就能出来,打包好久可以直接用了
(简答来说,找到exe文件复制到D盘一个目录下,用命令行打开这个目录,输入wind…打包就行了)
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第8张图片
存一张图免得自己忘记代码了

实训第一天(附简易计算器的实现)

任务:
1.窗口部件学习(窗口,信号与槽,对话框)
2.布局管理器学习
3.实验任务:制作简易计算器

制作简易计算器链接
QT入门_简易计算器的实现与遇到的问题汇总

遇到的问题:

自定义命名空间的相关问题

这串代码困扰了我好久
mainwindow.h:

namespace Ui {
    class MainWindow;
}

ui_mainwindow.h:

namespace Ui {
    class MainWindow: public Ui_MainWindow {};
} // namespace Ui

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent),ui(new Ui::MainWindow)
{
	......
}

疑问的解决参考:
①Qt Ui 头文件研究 (推荐这篇文章,讲得很好)
简单来说,命名空间的用处就是命名变量、类等,多次定义会报错,mainwindow.h中只是声明MainWindow类,ui_mainwindow.h中是在定义MainWindow类,关于命名空间的其他细节请参考上述文章
②MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)解析
至于为什么后面还要加上ui(new Ui::MainWindow),个人的理解是:本来这条语句是定义MainWindow的构造函数,“:”后面的不是类名后有参数说明它也不是继承关系,而是采用初始化列表构造函数。而由于在类外定义构造函数而直接用类中的成员变量会报错,所以采用:ui(new Ui::MainWindow)ui->setupUi(this)this->ui->btn0的方式来使用类的成员变量

(其实笔者当时理解不了是忘记这个使用初始化列表的构造函数的知识点了,哼唧唧.jpg)

书上的知识点:
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第9张图片

关于隐式调用构造函数的问题

敲代码的时候:
有时程序运行不出正确结果,冥思苦想,却说这也不行?
有时候程序突然能运行出正确结果了,一脸懵逼,这怎么又可以?

又是这里:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent),ui(new Ui::MainWindow)
{
	......
}

我定义的是有参构造函数吧

int main(int argc,char *argv[]){
    QApplication a(argc,argv);
    MainWindow w;
    w.show();
    return a.exec();
}

怎么一到主函数变成无参构造了?
本来头一天照着别人的写简易计算器都能运行出正确结果了,今天已检查又纳闷了,这都行?

其实是笔者c++基础不牢实

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

这是缺省的构造函数啦,忘记的可以回去翻课本了
另外关于explicit的用法:explicit关键字的作用

实训第二天(不附地址薄的实现)

任务:
1.应用程序主窗口学习
2.制作简易地址簿

地址簿的博客就不写了,大型拼图游戏,巨多代码
先来解决昨天的这个“世纪难题”

关于on_pushButton_clicked()的默认connect

昨天写计算器的时候遇到一个问题:
老感觉函数里的if 和 else if里的代码都执行了

void MainWindow::on_btnflag_clicked(){
     
    if(flag == 1){
     
        flag = 2;
    }
    else if(flag == 2){
     
        flag = 1;
    }
//    flag = 2;
}

(之前的写的槽函数也遇到了这样的问题,不过后面改掉了,留下了这一个)
我还问朋友,这啥机制啊,Qt里if 和else还有这种操作吗?
我一直很疑惑,思考过后觉得是这个函数运行了两次,但由于信号与槽学得并不好,对这种机制还不是很了解,这里就直接把代码改成了 flag = 2;也就是说flag按钮不能在两个lineEdit中切换了,一旦换到另一个就再不能回到之前那个了。修改过后发现计算器也能用,就没再追究
今天决定再看看这个问题(其实昨天也是因为不知道怎么搜)
搜了个关键字on_pushButton_clicked(),看了这篇博客:Qt on_pushButton_clicked()的用法,豁然开朗
其实也就是Qt Creater默认给你完成on_pushButton_clicked()的信号与槽连接函数,由于我再写了个connect函数,这个语句被执行两遍,就跟没执行一样了,把connect函数注释掉后,flag按钮恢复功能

加图标、背景图片的几种方法

加图标
步骤:
1.找张图
2.找个网站将图修改为.ico图标 网址:ICO在线转换工具
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第10张图片
3.将图片放到项目目录下,在.pro文件里加入这行代码:
RC_ICONS = path.ico(其中path是路径,这里就是文件名)
加背景图片
例如要给mainwindow窗口背景图片
1.找到mainwindow.h,声明槽函数
void setBackgroundIamge(QString path);
2.找到mainwindow.cpp,构造函数里

setBackgroundIamge("path");

其中path是你的路径(path获取有简便方法,下文会提到)
3.找到mainwindow.cpp,实现槽函数

void MainWindow::setBackgroundIamge(QString path){
     
    QPixmap pixmap = QPixmap(path).scaled(this->size());
    QPalette palette(this->palette());
    palette.setBrush(QPalette::Background, QBrush(pixmap));
    this->setPalette(palette);
}

另:图片必须要导入项目中
方法:Qt学习之路_010-Qt添加资源文件图片
导入图片后,右击图片就可以直接拷贝路径
(双击图片测试图片能不能打开,如果打不开可能是窗口黑屏的原因)

通过ui设计界面StyleSheet添加
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第11张图片
点击改变样式表
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第12张图片
url地址可以通过添加资源来生成

实训第三天(附qq登录界面的实现)

任务:
1.事件学习(概述、鼠标事件、键盘事件、定时器)
2.Qt对象模型与容器学习
3.3D绘图学习
4.实验:简易QQ登录界面

QT入门_如何制作一个简单的QQ登录页面

MainWindow设置setLayout布局时没用?

QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第13张图片
如图,明明设置了this->setWindowTitle(mainLayout),还是弄出一堆窗口
这是为什么呢?
我调试了很久,最后在CSDN上的这篇文章上找到了答案:
QT——mainwindow使用布局没反应的解决
由于之前用纯代码布局都是用的QWidget类,所以现在才反应出这个问题
QMainWindow类是自带一个主窗口centralWidget的,所以必须要有:

this->centralWidget()->setLayout(layout);
这里我们这么写:

    widget->setLayout(mainlayout);
    this->setWindowTitle("Register");
    this->setCentralWidget(widget);
    this->setLayout(mainlayout);

QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第14张图片
这样点击注册就会出现一个完整的界面了

实训第四天(附QPainter基本绘图)

任务:

  1. 文件操作学习
  2. 数据库学习
  3. 实验:QPainter基本绘图

实验:QT入门_QPainter基本绘图

遇到的问题:

① Q_OBJECT报错问题 error: undefined reference to `vtable for PaintArea’

解决方法:
注释掉了Q_OBJECT
(之后的补充,如果需要用到信号与槽,Q_OBJECT是必须的,那么此时的方法只有把原来使用了Q_OBJECT的头文件和cpp文件全部清除再重新导入,u1s1有点麻烦,但我也没找到其他办法)
参考:Q_OBJECT 报错问题

② 构造函数出错 error: no matching function for call to ‘PaintArea::PaintArea(Widget*)’

paintArea = new PaintArea(this);
查找资料后发现自己这一块有问题
explicit PaintArea();
应该为:
explicit PaintArea(QWidget *parent = 0);

③构造函数出错 error: return type specification for destructor invalid void Widget::~Widget()

查找资料后发现这个错误统一指向的错误是类定义后没加分号,但是我加了,经过反复查找后发现多加了个void

void Widget::~Widget(){
     

}

应为:

Widget::~Widget(){
     

}

实训第五天

休息

实训第六天

确定做的项目为植物大战僵尸(魔改版)

实训第七天

确定了项目方向,做一个飞机大战版的植物大战僵尸。
遇到的问题

QT资源文件过大引发的问题 cc1plus.exe:- 1: error: out of memory allocating 1073745919 bytes

原因:导入了大量图片
QT中增加资源文件过大时,会编译不过,报错:
使用qrc资源文件,也就是在QT的工程中添加资源文件,就是添加的资源文件(如qrc.cpp)会直接被存放到静态数组中,从而一直占用内存,使内存的利用率不高。有的时候如果资源过大,可能编译都无法通过,会造成out of memory的错误。
解决方法:
在工程PRO文件中,添加:

CONFIG += resources_big

原文链接:解决cc1plus.exe: error: out of memory allocating

ui设计界面上添加的菜单栏、按钮等控件在程序上显示不了

我猜你是少加了ui->setupUi(this);

实训第八天

创建了基本的类,设计出了界面,尝试用QPainter来绘制图片,通过draw()move()clean()来绘制图片,用双缓冲技术解决闪烁问题,但由于能力有限放弃了。然后发现QMovie类播放动态图比较巧妙,可以直接用播放植物和僵尸的gif图像,让其继承与QLabel类,标签移动动态图也会跟着移动

关于ui设计界面的一些用法(小总结)

  • 操作完设计界面后进行编译,会生成ui_…….h头文件,不要自己在头文件里去改代码,因为如果你再次使用ui设计界面进行操作并编译后,系统会删掉你写的代码,设计界面还是原样
  • ui设计界面的一些操作

    如图,拖动1中的组件到2中可以创造组件,3中可以选择已经创造的组件,并在4中显示当前组件的参数,以在窗口菜单栏加入一个全屏按钮为例:
    如果你已经设置了MainWindow的背景,对于它下面的子组件,也会自动加入背景图片,但是在样式表中不会显示
    QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第15张图片
    影响美观,此时就需要你在样式表中添加资源等
    左上角菜单栏可以直接编辑
    QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第16张图片
    编辑完成5中就会自动生成QAction对象,修改完参数后
    QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第17张图片
    选择信号triggered(),界面就会立即跳转到cpp里的槽函数中,我们加入showFullScreen();就完成了
    (暂时用到的功能就这些)

如何在界面上新建一个动图

首先在我所搜集的资料里面,用设计界面是添加不了动图的,我们这里用到QMovie
例如我要在我的界面的阳光栏里加一个阳光的gif图,我在设计界面添加一个
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第18张图片
(皇帝的新图)
在这里插入图片描述
这里要注意图形的先后关系(上面的会把下面的图覆盖)
我们再在主窗口cpp构造函数里添加如下代码:

    QMovie *sun = new QMovie(":/new/prefix1/pvz_picture/Sun.gif");
    ui->label_sun->setMovie(sun);
    sun->start();

运行程序
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第19张图片
这样就可以了

实训第九天

学习了一下事件监听等知识,用QMouseEvent中的mouseMoveEvent()来获取鼠标的坐标,通过信号与槽传给植物,再将植物的坐标改变,实现鼠标控制植物移动
开始使用线程,活在被线程支配的恐惧之下,创造了一个线程使一个本来存在于界面上的子弹能动了

另:线程我基本上是通过黑马程序员学的 链接: 黑马程序员Qt 讲得很好。
然后今天做的事情也差不多就这些,感觉耗了好多时间也没多少效果,看空间里都有人子弹敌机都做好开始哗啦啦大战了,顿时感觉我还是太垃圾了,不过最后看到子弹终于能动了还是有点欣慰的。
遇到的问题:

线程操作ui界面问题:ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread.

我出现这个问题是因为在线程run()函数里使用了子弹的draw函数(即用setGeometry重置子弹的位置),而子弹的draw函数需要在界面上操作(标签移动),解决的方法是查csdn秃头调bug两小时用信号与槽的方式,run()函数里发射信号告诉子弹要完成draw()函数了

实训第十天

创建了子弹产生的线程和子弹运动的线程并调试了错误(用时十几个小时)
创建了僵尸产生的线程和僵尸运动的线程(用时一小时)
整个一天给我的感觉就是敲一会代码,然后花一两个小时解决一个bug,闷在家里闷了一天
晚上11点的时候子弹终于能顺利产生了,一下子就把僵尸的线程写完了,痛快

遇到的问题:

线程创建对象,构造函数操作了界面 ASSERT failure in QWidget: “Widgets must be created in the GUI thread.”

我出现这个问题是因为在线程里创建了一个子弹对象,构造函数里也有界面操作。
参考的博客:Qt解决:ASSERT failure in QWidget: “Widgets must be created in the GUI thread.”
我解决的方法是用在线程run()里每隔一段时间发送一个信号,主窗口接受,创建一个子弹后把这个子弹发射到这个线程类里来

跨线程传递自定义参数 QObject::connect: Cannot queue arguments of type ‘ThreadSignal’ (Make sure ‘ThreadSignal’ is registered using qRegisterMetaType().)

对于上一个问题,我用的储存方式是向量,一开始放到了主窗口里,一开始想把这些子弹生成和向量append工作在主窗口里完成的,然后这份数据存在主窗口各个类之间调用都方便,结果出现一系列问题,如信号与槽之间不能引用传递一个数组(容器),然后还涉及到信号与槽跨线程传递一个自定义对象需要注册的问题,最后搞得自己都没脾气了,又突然想起只传递一个对象就行了,唉,自己当时怎么那么傻,既然说到了这里,就把注册这个问题也加上吧
参考的博客:QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类…

实训第十一天

更改了僵尸的产生方式——随机产生,花了一天尝试释放内存消失的子弹的内存空间,由于是用向量储存的,再加上自己本来c++这块学得不扎实,查找了很久释放内存的方法,依然失败。运行超过一段时间就会变得非常卡顿
先贴个链接,今天先放弃处理这个问题了,以后再来解决吧
关于QT的内存申请和释放
然后晚上就思考了一下子弹和僵尸的碰撞问题怎么解决,最后决定子弹和僵尸每移动一次就发射发信号给主窗口,主窗口作为中转站再发信号传到需要碰撞的对象上,再执行hide()等工作,把今天的效果贴上:

实训第十二天

放弃了那个释放内存那个问题后,今天的任务感觉变得养生起来了,找了p了点图
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第20张图片
没有我僵尸发射不了的子弹
新建了两个类,产生僵尸子弹的线程类和僵尸子弹运动的线程类(后来发现僵尸子弹的产生根本不需要新开一个线程,可以在僵尸运动的线程里发信号就行了,比如僵尸move()十次就发送一次信号给主窗口来创建一个僵尸子弹)

然后发现僵尸子弹都是朝一个方向打的,感觉不够刺激,就又修改了下,子弹根据植物的位置来打
效果也贴一下

感觉有那味了,有时间再把植物的子弹丰富一下,打死僵尸后发送信号修改一下阳光值,然后基本上就差不多啦
只是这个内存的问题真的头疼,运行一会就跑不动了

实训第十三、十四天

部分解决了内存的问题,将存储形式由向量存储变成了QList存储,当子弹符合清除的条件时就delete ***.takeAt(index);花了这么长时间,谈谈自己对于内存的心得吧

关于内存的那点事

笔者目前大一,所学的知识为c++,java程序设计基础,学习了数据结构和部分离散数学。
大一上学期学c++碰到delete时还没怎么认真学,觉得没什么用,毕竟那个时候做一些简单算法题根本用不着,直到现在程序跑不动了才知道这部分知识有多重要。数据结构是现学现用,如果没接触过数组和链表储存,没有接触过各种数据的增加与删除操作,很多地方都无从下手。我们现在很多基础学科看起来没用,没学好,以后碰到问题真的是寸步难行了,所以无论如何都要把基础学科学扎实些。

为什么用QList存储而不用向量存储:我的子弹如果储存在向量中,要删除其中一个元素并释放其内存,无论是用erase和remove都做不到(我反正不会),如果用QLIST的话,takeAt(index)不光能从容器里清除该元素,还能返回这个元素,用delete ***.takeAt(index);语句就能够删除元素并且释放内存了。这个我是在同学那里知道的,不然靠自己这里那里找答案估计还要耗费一天功夫
可以清楚地发现,释放掉内存后程序能卡顿的时间延后了很多(具体我不知道哪还有内存泄漏了,到现在也只能说是部分解决了这个内存问题,可能要到以后的学习之中才知道如何解决了)

项目最终效果展示

最后两天部分处理完内存问题后,游戏模式和植物形式的添加是轻松多了,而且这个过程十分有趣。
crazy bullet 3(跟踪导弹)

这里有用到植物gif
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第21张图片QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第22张图片QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第23张图片
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第24张图片QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第25张图片
植物发射的子弹:
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第26张图片
(会点点ps还是有好处的啦,找不到寒冰豌豆就加个滤镜啦,虽然我技术比价菜)
贴一个说明:
QT学习日志(附:简易计算器,qq登录界面,简易绘图板,植物大战僵尸魔改版项目实践)_第27张图片
找几个朋友测试了一下,他们说难度挺大的,能上10000分就很稀有了,看来我还是对自己写的程序比较熟悉,上个两万分轻轻松松啦。其实我发现这个游戏到了无尽模式后最大的敌人不是产得有多快,而是内存够不够了,可惜这个问题我暂时还解决不了。
本来想设一个无敌模式的,还有声音等按钮没有处理,可惜ui设计界面从昨天起一打开就卡退,无奈之下只能这样了,试了一下以前做过的那些实验,发现ui设计界面都可以打开,唯独我的实践项目打不开了,不知道是我的项目文件太多了还是啥的,搜了半天也解决不了,就没继续修改了。

哈哈哈,玩自己的游戏玩到这么高,我可真是无聊

那实训内容更新到这里就截止了,第一次写这么长的博客,也没学习排版追求美观啥的,对于一个qt新手肯定说的也比较浅显比较基础,如果对你有用就点个赞吧。

你可能感兴趣的:(Qt,qt,c++)