Qt编译陷入死循环
查看编译输出,发现卡在了make,查了一下,原因是make根据文件修改时间进行编译,而我在双系统切换之后系统时间没有自动同步。
进度条一开始白屏,类似卡顿
解决方法:进度条初始值设置为2
auto pd = new QProgressDialog("正在保存...","取消",0,10, &w);
pd->setWindowModality(Qt::WindowModal);
pd->setAttribute(Qt::WA_DeleteOnClose, true);
pd->setMinimumDuration(0);
pd->setWindowTitle("请稍后");
pd->setValue(2);
pd->show();
for(int i=0; i<10; i++){
pd->setValue(i+1);
Sleep(1000);
}
pd->setValue(10);
在循环中发送信号导致程序很卡
解决方法:最好可以打包一次发送;参数类型如果是自定义的,最好使用qRegisterMetaType注册到Qt元对象系统。如果还是很卡,可以考虑信号和槽函数的连接方式,阻塞和非阻塞。
QgraphicsScene 画布元素实现群组和解组功能
由于QgraphicsItemGroup对于group对象的再群组,会出现一些问题,所以自己实现了一个group对象。
但是仍然存在奇怪的问题,花了一天的时间终于解决了。
上图中时QgraphicsScene的三个方法,第一个方法获取场景中的所有item,第三个方法获取所有visible的item。
从scene中删除group对象,removeitem仅仅是从移出并交还控制权(Removes the item item and all its children from the scene. The ownership of item is passed on to the caller (i.e., QGraphicsScene will no longer delete item when destroyed).),group对象的isvisible属性可能仍然时true。
所以当发生鼠标框选事件,使用第三个方法时获取items时,某些已经remove但是仍然visible的元素也会包含在其中,导致不可预料的错误。
解决方案:每一次remove之后设置isvisible为false;每一次additem之后设置isvisible为true。
delete 自定义群组对象引起软件闪退
闪退原因:执行QGraphicsView::paintEvent 时调用QGraphicsSceneFindItemBspTreeVisitor::visit(QList<QGraphicsItem*>*) 访问到了空指针。
BspTree 是Qt为了提高场景中元素访问效率所使用的数据结构,但是它的更新有Bug。可以查看qgraphicsscene_bsp.cpp了解源码。
闪退场景:从场景中removeItem 之后 delete,等到paintEvent 的时候就闪退了,但并不是每次都闪退。
此问题无解,如果您找到了解决方案,请留言告诉我,非常感谢!
使用MinGW和MSVC编译的区别
1、首先使用第三方库的话,MinGW和我MSVC编译出来的库是不同的,某些三方库不能兼容两种编译器,需要分别编译。
2、由于库文件的不同,某些头文件在引入库文件是一并引入,不需要手动include,另一些不会。例如:使用JPEG库,在MinGW遇到“jmp_buf 未定义”,需要手动include “setjmp.h”。
3、两种编译器的变量初始化不同,使用不同编译器会导致奇怪的问题,解决方法当然是编程习惯了,定义的结构体、数组等一定要显式初始化。
4、关于内存泄漏检测,MSVC有CRT可以解决,但是MinGW不知道如何解决。
代码没问题,但是执行结果始终不对
如果经常使用Git切换不同的版本,没有关闭QtCreater,只是点击重新构建项目,那么Build文件夹某些文件不会被覆盖,有很小的概率会出问题。这时候只需要退出QtCreater删除Build文件夹即可。
C++构造初始化列表的初始化顺序
构造函数初始值列表中初始值的初始化顺序由类定义中的出现顺序决定,也即是说构造函数初始值列表中初始值的前后位置关系并不影响实际的初始化顺序。
关键字noexcept 和 throw()
C++中的异常处理是在运行时而不是编译时检测的。为了实现运行时检测,编译器需要创建额外的代码,然而这会妨碍程序优化。所有在程序设计时说明程序是否会抛出异常是一件好事。
函数申明使用 noexcept 或者 throw() 就说明该函数不会抛出异常。而一旦函数内部发生异常,程序立即退出。
void swap(Type& x, Type& y) throw() //C++11之前
void swap(Type& x, Type& y) noexcept //C++11
new 和 malloc 的区别
new失败时抛出异常,malloc失败时返回NULL。
new可以由用户指定异常处理函数new_handler (https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/4209879.html)
使 32 位程序使用大于 2GB 的内存
debug没问题,release闪退
使用mingw32编译器编译,STL的sort函数在debug和release模式的实现似乎不一致,release模式下stable_sort代替sort即可。
其他:https://www.zhihu.com/question/443340911
创建Qt子线程
#include <QThreadPool>
#include <QRunnable>
class OpenTpfWithDTPWTask : public QObject, public QRunnable
{
Q_OBJECT
private:
QString filename;
public:
ThreadTask() {}
void run();
};
auto *task = new ThreadTask();
task->setAutoDelete(true);
QThreadPool::globalInstance()->start(task);
几个数值之间相互影响
值得注意的是小数位数和比较相等的数值精度
例子:总宽度、每份宽度和宽度份数相互影响。ui设计指定了最小值为0,小数位数为2。
头文件
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = nullptr);
~Dialog();
private:
Ui::Dialog *ui;
double totalWidth_, eachWidth_;
int widthCount_;
void init();
void setEachWidth(double value);
};
#endif // DIALOG_H
CPP文件
#include "dialog.h"
#include "ui_dialog.h"
#include "QDebug"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
init();
}
Dialog::~Dialog()
{
delete ui;
}
bool equald(double a, double b){
if((a-b)>-0.00001 && (a-b)<0.00001) return true;
return false;
}
void Dialog::init()
{
ui->totalWidth->setValue(2);
connect(ui->totalWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged),[&](double){
// 更新每份宽度
if(equald(widthCount_, 0)) return;
setEachWidth(ui->totalWidth->value()/widthCount_);
});
connect(ui->widthCount, QOverload<int>::of(&QSpinBox::valueChanged), [&](int value) {
if(equald(value, widthCount_)) return;
widthCount_ = value;
qDebug()<<"widthCount_"<<widthCount_;
// 更新每份宽度
if(equald(widthCount_, 0))
{
ui->eachWidth->setValue(0);
return;
}
setEachWidth(ui->totalWidth->value()/widthCount_);
});
connect(ui->eachWidth, QOverload<double>::of(&QDoubleSpinBox::valueChanged), [&](double value) {
if(equald(eachWidth_, value)) return;
qDebug()<<"eachWidth_"<<eachWidth_<<value;
eachWidth_ = value;
// 更新宽度份数
if(equald(eachWidth_, 0))
{
ui->widthCount->setValue(0);
return;
}
widthCount_ = qRound(ui->totalWidth->value()/eachWidth_);
ui->widthCount->setValue(widthCount_);
});
}
void Dialog::setEachWidth(double value)
{
eachWidth_ = qRound(value*100)/100.0;
ui->eachWidth->setValue(eachWidth_); // ui->eachWidth 两位小数
}
opencv 图片旋转
方法1(旋转90度,不开辟新的内存)
https://blog.csdn.net/seanwang_25/article/details/43273593
旋转90°,不需要开辟新的内存空间,不受内存限制。缺点:太慢了。
方法2(任意角度旋转)
const double pi=3.1415926535;
void toMoveCenter(Mat& src, Size size)
{
Mat tm = Mat::zeros(2, 3, CV_32FC1);
tm.at<float>(0, 0) = 1;
tm.at<float>(1, 1) = 1;
tm.at<float>(0, 2) = size.width / 2 - src.cols / 2;
tm.at<float>(1, 2) = size.height / 2 - src.rows / 2;
warpAffine(src, src, tm, size);
}
void toRotate(Mat& src, double angle)
{
Point2f pt(src.cols / 2.0, src.rows / 2.0); // point from where to rotate
Mat rm = getRotationMatrix2D(pt, -angle, 1.0);
int sw = src.cols;
int sh = src.rows;
warpAffine(src, src, rm, Size(sw, sh));
}
// 任意角度旋转,然后写一个临时文件。 缺点:受内存限制
void rotate(){
double angle = 90;
cv::Mat mat = cv::imread("F:\\1.tif");
// rotate object
int sw = mat.cols;
int sh = mat.rows;
double a = pi / 180 * angle;
double sina = sin(a);
double cosa = cos(a);
// use abs to fix that dw or dh get negative value
int dw = abs(sw * cosa + sh * sina);
int dh = abs(sw * sina + sh * cosa);
int d = ceil(sqrt(sw * sw + sh * sh));
toMoveCenter(mat, Size(d, d));
toRotate(mat, angle);
toMoveCenter(mat, Size(dw, dh));
// write mat
cv::imwrite("F:\\111.tif", mat);
}
方法3(旋转90,180,270)
// 旋转90,180,270度,速度快,不受内存限制,缺点是不支持任意角度。
void rotate2(){
cv::Mat mat = cv::imread("F:\\1.tif");
cv::rotate(mat, mat, cv::ROTATE_90_CLOCKWISE);
cv::imwrite("F:\\111.tif", mat);
}