先看看main()代码:
// !!! Qt 5
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget window;
window.setWindowTitle("Enter your age");
/*引入了两个新的组件:QSpinBox和QSlider。QSpinBox就是只能输入数字的输入框,并且
带有上下箭头的步进按钮。QSlider则是带有滑块的滑竿。*/
QSpinBox *spinBox = new QSpinBox(&window);
QSlider *slider = new QSlider(Qt::Horizontal, &window);
//使用setRange()函数设置其范围。
spinBox->setRange(0, 130);
slider->setRange(0, 130);
//将 slider 的valueChanged()信号同 spinBox 的setValue()函数相连。
QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);
/*QSpinBox有两个信号:void valueChanged(int)和void valueChanged(const QString &)。
当使用&QSpinBox::valueChanged取函数指针时,编译器不知道应该取哪一个函数的地址,因
此报错。解决方法就是,我们创建一个函数指针,这个函数指针参数指定为 int。*/
void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged;
//将这个函数指针作为 signal,与 QSlider 的函数连接:
QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue);
spinBox->setValue(35);
/*创建一个QHBoxLayout对象,即布局管理器。然后将两个组件都添加到这个布局管理器,并
且把该布局管理器设置为窗口的布局管理器。*/
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(spinBox);
layout->addWidget(slider);
window.setLayout(layout);
window.show();
return app.exec();
}
Qt 5 中的5种布局管理器,上述代码中使用的是QHBoxLayout(按照水平方向从左到右布局):
QHBoxLayout:按照水平方向从左到右布局;
QVBoxLayout:按照竖直方向从上到下布局;
QGridLayout:在一个网格中进行布局,类似于 HTML 的 table;
QFormLayout:按照表格布局,每一行前面是一段文本,文本后面跟随一个组件(通常是输入框),类似 HTML 的 form;
QStackedLayout:层叠的布局,允许我们将几个组件按照 Z 轴方向堆叠,可以形成向导那种一页一页的效果。
Q&A:
1.博主 我想知道 为什么 把
QWidget window;
window.setWindowTitle(“Enter your age”);
的window的类型改成 QMainWindow之后添加上去的两个部件重叠在一起了?QMainWindow不是QWidget的派生类么?
QMainWindow 的确是继承自 QWidget,但是它同时添加了自己的 layout,正因为有 layout 的存在,所以你需要使用 setCentralWidget() 函数把一个 QWidget 设置为中心的组件,而不是把一个个的子组件用自己的 layout 添加进去(因为 QMainWindow 已经有了默认的 layout,你自己的 layout 才会不起作用)。
2.按照之前的对象树的概念,为什么不是传入new QHBoxLayout(&window)呢?而是使用空参数的折构方法呢?
这是因为调用 setLayout() 函数的时候,如果这个 layout 不属于调用 setLayout() 函数的组件,则会自动设置为该组件。因此,你可以在 new 的时候就添加 parent 指针参数,也可以通过 setLayout() 设置。需要注意的是,如果构造函数添加了 parent 指针,后来又调用了 setLayout() 函数,如果二者不相同,则 setLayout() 函数设置的 parent 指针会覆盖构造函数传入的。
3.window,spinBox,slider这几个,什么时候该用指针,什么时候不该用呢?还有layout。。。
所有 QObject 的子类,因为 Qt 可以利用 parent 指针进行半自动化管理,因此建议使用指针。因为由于QObject 的拷贝构造函数等都是私有的,只能以指针的形式保存到容器中,因而指针更为方便。容器之类一般都是使用栈。不过这一点并不是绝对的,还是具体情况具体分析最好。
4.如果将void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged;
这个函数指针用以下2句代码替换:
void (*spinBoxSignal)(int);
spinBoxSignal = &QSpinBox::valueChanged;
运行时就会指示:
error: no matches converting function ‘valueChanged’ to type ‘void (*)(int)’spinBoxSignal = &QSpinBox::valueChanged;
为什么会这样呢?
成员函数指针需要类实例去调用,因此成员函数指针和全局函数指针是不兼容的。你修改之后的代码:
void (*spinBoxSignal)(int);
定义了一个全局函数指针,是不能用成员函数 QSpinBox::valueChanged 进行赋值的,这也就是为什么编译器会报无法转换的错误。