2018.5.1
理工科的学习一般是摸着石头过河,有很多新东西可能还没有完全搞明白,但是却必须要先用起来了。实验室这个项目DDL太近,作为QT从没用过的小白,要想纯粹从头学起肯定没法按时完成任务。所以基本上是一边按需学习模仿,一边恶补基础知识。
目前实现的界面效果如下(数据内容涉密就不放出来了):
这个简单的界面实现,用到了三种布局QHBoxLayout、QHBoxLayout、QGridLayout,用到了QLabel、QButton、QTextEdit等多个控件,用到了绘图工具等,用的地图是我们学校的地图,欢迎各位来我们南大玩耍,相互交流学习。项目整体大概推了1/5吧,解决了几个小问题,希望越往后学解决问题可以越轻松一点。
当然,工程还是要推,基础知识还是得捡起来学。
网上大概翻了一些教程,对比一下发现Qt学习之路2的学习推进方式更适合我一些,为了防止自己遗忘,在这里分享一些学习的要点,我记的知识要点可能偏个人一些,大概率思维会比较跳跃,建议参考博主原文和查看官方API理解。
对象模型:
QObject是以对象树的形式组织起来的。当创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。当父对象析构的时候,这个列表中的所有对象也会被析构。例如,一个按钮有一个QShortcut(快捷键)对象作为其子对象。当我们删除按钮的时候,这个快捷键理应被删除。又例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,属于这个对话框的按钮、图标等也一起被删除。
当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。Qt 保证的是,任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。如果QObject在栈上创建,Qt 保持同样的行为。
以下代码会产生二次析构:
根据栈后进先出原则,作为父对象的 window 会首先被析构,在析构过程中,它析构子对象。代码继续执行, quit 也是一个局部变量,在超出作用域的时候也需要析构,这时就造成了二次析构。
{ QPushButton quit("Quit"); QWidget window; quit.setParent(&window); }
我们最好从开始就养成良好习惯,在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。
布局管理器:
QT最常用 的布局管理器有以下几种:
QHBoxLayout:按照水平方向从左到右布局;
QVBoxLayout:按照竖直方向从上到下布局;
QGridLayout:在一个网格中进行布局,类似于 HTML 的 table;
QFormLayout:按照表格布局,每一行前面是一段文本,文本后面跟随一个组件(通常是输入框),类似 HTML 的 form;
QStackedLayout:层叠的布局,允许我们将几个组件按照 Z 轴方向堆叠,可以形成向导那种一页一页的效果。
使用QHBoxLayout进行的简单布局展示(使用QSpinBox和QSlider两个控件):
#include "mainwindow.h" #include <QApplication> #include <QSpinBox> #include <QSlider> #include <QHBoxLayout> int main(int argc, char *argv[]) { QApplication a(argc, argv); //MainWindow w; //w.show(); QWidget window; window.setWindowTitle("Enter your age"); //QSpinBox就是只能输入数字的输入框,并且带有上下箭头的步进按钮。QSlider则是带有滑块的滑竿。 QSpinBox *spinBox = new QSpinBox(&window); QSlider *slider = new QSlider(Qt::Horizontal, &window); spinBox->setRange(0, 130); slider->setRange(0,130); //将QSlider与QSpinBox值相连接 QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue); //将QSpinBox与QSlider值相连接,双向绑定,直接连接会报错,因为编译器认为QSpinBox::valueChanged是一个 overloaded 的函数。 //void valueChanged(int)与void valueChanged(const QString &),需要利用函数指针先显示指定一个函数 void(QSpinBox::*spinBoxSignal)(int) = &QSpinBox::valueChanged; QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue); spinBox->setValue(23); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(spinBox); layout->addWidget(slider); window.setLayout(layout); window.show(); return a.exec(); }
左边的QSpinBox和右边的QSlider相互绑定,输入数值会影响滑块位置,反之滑块移动也会改变数值。