我用Qt写程序也两年多了,主要是用这玩意做课程大作业、课程设计之类的玩意。期间遇到过很多奇怪的问题,这里做一下整理。
2017-01-31 更新
2016-12-18 更新
有毒的头文件
我在项目里定义了一个头文件 global.h,一开始工程可以正常地编译运行。但是当多个其他的头文件开始包含global.h的时候,奇怪的时候开始出现了,编译运行各种报错,大概意思就是符号Undifined,特别是global.h文件里的变量怎么也找不到,但是语法高亮又是正常的。折腾一通后,发现是global.h的预处理头的问题:
#ifndef GLOBAL_H
#define GLOBAL_H
/** src **/
#endif
发现GLOBAL_H这个宏很可能在Qt内部的头文件中被定义过了,所以只要把GLOBAL_H换一个名字就行了,可是这是Qt自动帮我生成的啊,好坑爹。
神奇的重构功能
一旦项目中文件多了之后,想要给某个变量或方法进行重命名,手动操作出错概率太高,免不了要用IDE提供的重构(Refactor)功能。Qt这玩意的变量重构似乎不是基于语法树分析的,好像只是在文本层面进行批量替换。
我为什么这么猜测呢,因为我遇到过一件坑爹事。有一次工程里有一个变量名比较特殊,大概是像qstring、os、process之类的变量名,具体叫什么我不记得了,我对这个变量名进行重构后,Qt似乎重构了好久,等重构完成后,发现这个Qt的构建套件已经报废了,无论编译构建什么工程,都会报错,而且错误来源都是Qt自己的头文件。
后来我也是折腾了半天,百思不得其解,怀疑是那次重构Qt把自己的内部头文件里的变量名也给重构了(内部头文件中存在变量刚好和我要重构的这个变量名相同)。后来我重新下载了一个Qt,手动把那个敏感的变量重新命名了一下,问题就解决了。
QAbstractButton的类型转换问题
实例化一个对话框QMessageBox,添加自定义的按钮。代码写法如下:
QMessageBox box;
box.setWindowTitle("标题");
box.setText("文字");
QPushButton *connectButton = box.addButton(tr("确定"), QMessageBox::ActionRole);
QPushButton *abortButton = box.addButton(tr("取消"),QMessageBox::ActionRole);
box.exec();
QAbstractButton* btnClicked = box.clickedButton();
QPushButton* btn = dynamic_cast<QPushButton*>(box.clickedButton());
QPushButton* btn = qobject_cast<QPushButton*>(box.clickedButton());
if (btn == connectButton){
this->close();
} else if (btn == abortButton){
;
}
但是实际上QMessageBox的clickButton()方法返回的是QAbstractButton*类型,因此需要进行类型转换,因为QAbstractButton是QPushButton的基类,因此我用的是dynamic_cast。然而我惊讶地发现这样写会报错:
然后我又试了一下qobject_cast,也不行,最后直接用(QPushButton*)ptr 强转了。我至今也没搞懂为什么无法进行转换。
不稳定的插件
Qt里面有一个Fake Vim,我就试用了一下。那一次打算在头文件里输入一个 #include 语句,结果忘了自己在用Vim,习惯性地打出了第一个字符 # 。 当时Vim不在编辑模式,按理来说对这个输入应该是没有响应的,结果Qt就崩溃了,没有保存的修改也丢失了。
自从那次之后,我就不敢用Qt的Fake Vim了。那还是一年多前的事,现在Qt也更新了好多版本,不知道问题修复了没有。
动态补充中
其实应该还有不少奇怪的问题,不过已经记不太清楚了,下次遇到再补充到Qt里来。
其实从以上的文字看我似乎在吐槽Qt,但其实我个人还是比较喜欢用Qt的。IDE用起来还是比较顺手的,至少比VS要顺手得多。Qt的信号-槽机制我也很喜欢,很多类之间通信的代码写起来方便多了,不用写一堆麻烦的回调。