撑住,就要睡觉了
我一开始以为要放暑假了实训应该挺轻松的,就是大家一起做做项目挺有趣的,直到老师第一天要我们做出个计算器,第二天要我们做出个地址簿,然后我每天就几乎没干过别的事情了
一般睡觉时间是凌晨1~2点
换了个头像,我觉得比较适合我敲代码的样子
结束的时候再换了个头像,还是豌豆射手好看些,梦开始的地方
任务:第一个Qt程序
ctrl shift+B的时候出现 Makefile.Debug: No such file or directory
搜集了各种头文件无法生成原因的资料,附上网址:
添加ui文件以及构建ui头文件方法
QT中 No such file or directory的解决办法
(存着以后也许用得到)
调试了很久,原因竟是自己在.pro文件里少打了个字母p
所以出现这种问题很可能就是自己疏忽输错了
另:网上查找之后发现只需ctrl+B就够了,加上shift老是把我搜狗的颜文字给弹出来了
ctrl+B就是编译的意思,编译不成功就生成不了头文件
控件-Show Sidebar,我是不小心关掉的,学习许多软件都会出现这种情况,一般的解决方法都是去找窗口栏
在dubug文件里找到.exe文件后,直接打开会报系统错误
存疑(明天的我比今天的我更有智慧解决问题)
(实训第二天更)
听课听了一半,在文件夹里找齐了这些ddl
自信满满以为可以芜湖起飞,结果还是报错
好在找到了一篇文章,分享一下:
Qt程序打包发布方法
这工具是Qt自带的,左下角搜qt就能出来,打包好久可以直接用了
(简答来说,找到exe文件复制到D盘一个目录下,用命令行打开这个目录,输入wind…打包就行了)
存一张图免得自己忘记代码了
任务:
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)
敲代码的时候:
有时程序运行不出正确结果,冥思苦想,却说这也不行?
有时候程序突然能运行出正确结果了,一脸懵逼,这怎么又可以?
又是这里:
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.制作简易地址簿
地址簿的博客就不写了,大型拼图游戏,巨多代码
先来解决昨天的这个“世纪难题”
昨天写计算器的时候遇到一个问题:
老感觉函数里的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在线转换工具
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添加
点击改变样式表
url地址可以通过添加资源来生成
任务:
1.事件学习(概述、鼠标事件、键盘事件、定时器)
2.Qt对象模型与容器学习
3.3D绘图学习
4.实验:简易QQ登录界面
QT入门_如何制作一个简单的QQ登录页面
如图,明明设置了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入门_QPainter基本绘图
遇到的问题:
解决方法:
注释掉了Q_OBJECT
(之后的补充,如果需要用到信号与槽,Q_OBJECT是必须的,那么此时的方法只有把原来使用了Q_OBJECT的头文件和cpp文件全部清除再重新导入,u1s1有点麻烦,但我也没找到其他办法)
参考:Q_OBJECT 报错问题
paintArea = new PaintArea(this);
查找资料后发现自己这一块有问题
explicit PaintArea();
应该为:
explicit PaintArea(QWidget *parent = 0);
查找资料后发现这个错误统一指向的错误是类定义后没加分号,但是我加了,经过反复查找后发现多加了个void
void Widget::~Widget(){
}
应为:
Widget::~Widget(){
}
休息
确定做的项目为植物大战僵尸(魔改版)
确定了项目方向,做一个飞机大战版的植物大战僵尸。
遇到的问题
原因:导入了大量图片
QT中增加资源文件过大时,会编译不过,报错:
使用qrc资源文件,也就是在QT的工程中添加资源文件,就是添加的资源文件(如qrc.cpp)会直接被存放到静态数组中,从而一直占用内存,使内存的利用率不高。有的时候如果资源过大,可能编译都无法通过,会造成out of memory的错误。
解决方法:
在工程PRO文件中,添加:
CONFIG += resources_big
原文链接:解决cc1plus.exe: error: out of memory allocating
我猜你是少加了ui->setupUi(this);
创建了基本的类,设计出了界面,尝试用QPainter来绘制图片,通过draw()move()clean()来绘制图片,用双缓冲技术解决闪烁问题,但由于能力有限放弃了。然后发现QMovie类播放动态图比较巧妙,可以直接用播放植物和僵尸的gif图像,让其继承与QLabel类,标签移动动态图也会跟着移动
triggered()
,界面就会立即跳转到cpp里的槽函数中,我们加入showFullScreen();
就完成了首先在我所搜集的资料里面,用设计界面是添加不了动图的,我们这里用到QMovie
例如我要在我的界面的阳光栏里加一个阳光的gif图,我在设计界面添加一个
(皇帝的新图)
这里要注意图形的先后关系(上面的会把下面的图覆盖)
我们再在主窗口cpp构造函数里添加如下代码:
QMovie *sun = new QMovie(":/new/prefix1/pvz_picture/Sun.gif");
ui->label_sun->setMovie(sun);
sun->start();
学习了一下事件监听等知识,用QMouseEvent中的mouseMoveEvent()来获取鼠标的坐标,通过信号与槽传给植物,再将植物的坐标改变,实现鼠标控制植物移动
开始使用线程,活在被线程支配的恐惧之下,创造了一个线程使一个本来存在于界面上的子弹能动了
另:线程我基本上是通过黑马程序员学的 链接: 黑马程序员Qt 讲得很好。
然后今天做的事情也差不多就这些,感觉耗了好多时间也没多少效果,看空间里都有人子弹敌机都做好开始哗啦啦大战了,顿时感觉我还是太垃圾了,不过最后看到子弹终于能动了还是有点欣慰的。
遇到的问题:
我出现这个问题是因为在线程run()函数里使用了子弹的draw函数(即用setGeometry
重置子弹的位置),而子弹的draw函数需要在界面上操作(标签移动),解决的方法是查csdn秃头调bug两小时用信号与槽的方式,run()函数里发射信号告诉子弹要完成draw()函数了
创建了子弹产生的线程和子弹运动的线程并调试了错误(用时十几个小时)
创建了僵尸产生的线程和僵尸运动的线程(用时一小时)
整个一天给我的感觉就是敲一会代码,然后花一两个小时解决一个bug,闷在家里闷了一天
晚上11点的时候子弹终于能顺利产生了,一下子就把僵尸的线程写完了,痛快
遇到的问题:
我出现这个问题是因为在线程里创建了一个子弹对象,构造函数里也有界面操作。
参考的博客:Qt解决:ASSERT failure in QWidget: “Widgets must be created in the GUI thread.”
我解决的方法是用在线程run()里每隔一段时间发送一个信号,主窗口接受,创建一个子弹后把这个子弹发射到这个线程类里来
对于上一个问题,我用的储存方式是向量,一开始放到了主窗口里,一开始想把这些子弹生成和向量append工作在主窗口里完成的,然后这份数据存在主窗口各个类之间调用都方便,结果出现一系列问题,如信号与槽之间不能引用传递一个数组(容器),然后还涉及到信号与槽跨线程传递一个自定义对象需要注册的问题,最后搞得自己都没脾气了,又突然想起只传递一个对象就行了,唉,自己当时怎么那么傻,既然说到了这里,就把注册这个问题也加上吧
参考的博客:QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类…
更改了僵尸的产生方式——随机产生,花了一天尝试释放内存消失的子弹的内存空间,由于是用向量储存的,再加上自己本来c++这块学得不扎实,查找了很久释放内存的方法,依然失败。运行超过一段时间就会变得非常卡顿
先贴个链接,今天先放弃处理这个问题了,以后再来解决吧
关于QT的内存申请和释放
然后晚上就思考了一下子弹和僵尸的碰撞问题怎么解决,最后决定子弹和僵尸每移动一次就发射发信号给主窗口,主窗口作为中转站再发信号传到需要碰撞的对象上,再执行hide()等工作,把今天的效果贴上:
放弃了那个释放内存那个问题后,今天的任务感觉变得养生起来了,找了p了点图
没有我僵尸发射不了的子弹
新建了两个类,产生僵尸子弹的线程类和僵尸子弹运动的线程类(后来发现僵尸子弹的产生根本不需要新开一个线程,可以在僵尸运动的线程里发信号就行了,比如僵尸move()十次就发送一次信号给主窗口来创建一个僵尸子弹)
然后发现僵尸子弹都是朝一个方向打的,感觉不够刺激,就又修改了下,子弹根据植物的位置来打
效果也贴一下
感觉有那味了,有时间再把植物的子弹丰富一下,打死僵尸后发送信号修改一下阳光值,然后基本上就差不多啦
只是这个内存的问题真的头疼,运行一会就跑不动了
部分解决了内存的问题,将存储形式由向量存储变成了QList存储,当子弹符合清除的条件时就delete ***.takeAt(index);
花了这么长时间,谈谈自己对于内存的心得吧
笔者目前大一,所学的知识为c++,java程序设计基础,学习了数据结构和部分离散数学。
大一上学期学c++碰到delete时还没怎么认真学,觉得没什么用,毕竟那个时候做一些简单算法题根本用不着,直到现在程序跑不动了才知道这部分知识有多重要。数据结构是现学现用,如果没接触过数组和链表储存,没有接触过各种数据的增加与删除操作,很多地方都无从下手。我们现在很多基础学科看起来没用,没学好,以后碰到问题真的是寸步难行了,所以无论如何都要把基础学科学扎实些。
为什么用QList存储而不用向量存储:我的子弹如果储存在向量中,要删除其中一个元素并释放其内存,无论是用erase和remove都做不到(我反正不会),如果用QLIST的话,takeAt(index)不光能从容器里清除该元素,还能返回这个元素,用delete ***.takeAt(index);
语句就能够删除元素并且释放内存了。这个我是在同学那里知道的,不然靠自己这里那里找答案估计还要耗费一天功夫
可以清楚地发现,释放掉内存后程序能卡顿的时间延后了很多(具体我不知道哪还有内存泄漏了,到现在也只能说是部分解决了这个内存问题,可能要到以后的学习之中才知道如何解决了)
最后两天部分处理完内存问题后,游戏模式和植物形式的添加是轻松多了,而且这个过程十分有趣。
crazy bullet 3(跟踪导弹)
这里有用到植物gif
植物发射的子弹:
(会点点ps还是有好处的啦,找不到寒冰豌豆就加个滤镜啦,虽然我技术比价菜)
贴一个说明:
找几个朋友测试了一下,他们说难度挺大的,能上10000分就很稀有了,看来我还是对自己写的程序比较熟悉,上个两万分轻轻松松啦。其实我发现这个游戏到了无尽模式后最大的敌人不是产得有多快,而是内存够不够了,可惜这个问题我暂时还解决不了。
本来想设一个无敌模式的,还有声音等按钮没有处理,可惜ui设计界面从昨天起一打开就卡退,无奈之下只能这样了,试了一下以前做过的那些实验,发现ui设计界面都可以打开,唯独我的实践项目打不开了,不知道是我的项目文件太多了还是啥的,搜了半天也解决不了,就没继续修改了。
哈哈哈,玩自己的游戏玩到这么高,我可真是无聊
那实训内容更新到这里就截止了,第一次写这么长的博客,也没学习排版追求美观啥的,对于一个qt新手肯定说的也比较浅显比较基础,如果对你有用就点个赞吧。