资讯详情

QT 布局管理器

所谓 GUI 界面,归根结底,就是一堆组件的叠加。我们创建了一个窗口,把按钮放在上面,把图标放在上面,从而成为一个界面。组件的位置在放置时尤为重要。为了使窗口能够按照我们需要的方式渲染,我们必须指定组件放在哪里。这涉及到组件定位的机制。Qt 提供绝对定位和布局定位两种组件定位机制。

顾名思义,绝对定位是最原始的定位方法:给出该组件的坐标和长宽值。这样,Qt 知道把组件放在哪里,如何设置组件的大小。但这样做的一个问题是,如果用户改变了窗口的大小,如点击最大化按钮或使用鼠标拖动窗口的边缘,绝对定位的组件将没有响应。这也很自然,因为你没有告诉我 Qt,当窗口变化时,组件是否需要更新以及如何更新。例如,在最大化时,如果需要自动更新组件,Word 总是放大稿纸区域,拉长工具栏——编写相应的函数来响应这些变化。或者,更简单的方法是禁止用户改变窗口大小。但这不是长远之计。

针对这种变化的需求,Qt 为解决这个问题提供了另一种机制-布局。只需将组件放入某种布局,布局由专门的布局管理器管理。当需要调整大小或位置时,Qt 使用相应的布局管理器进行调整。以下是一个例子:

// !!! Qt 5   int main(int argc, char *argv[]) {     QApplication app(argc, argv);       QWidget window;     window.setWindowTitle("Enter your age");       QSpinBox *spinBox = new QSpinBox(&window);     QSlider *slider = new QSlider(Qt::Horizontal, &window);     spinBox->setRange(0, 130);     slider->setRange(0, 130);       QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue);     void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged;     QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue);     spinBox->setValue(35);       QHBoxLayout *layout = new QHBoxLayout;     layout->addWidget(spinBox);     layout->addWidget(slider);     window.setLayout(layout);       window.show();       return app.exec(); } 

这个例子还是值得解释的。我们可以先看看操作结果:

当我们拖动窗口时,我们可以看到组件自动变化:

本代码中介绍了两个新组件:QSpinBoxQSliderQSpinBox输入框只能输入数字,步进按钮上下箭头。QSlider它是带滑块的滑杆。我们可以从上面的截图中清楚地区分这两个组件。当我们创建这两个组件的例子时,我们使用它们setRange()设置函数的范围。由于我们的窗口标题是Enter your age(输入年龄) range(范围)设置为 0 到 130 应该够了。

有趣的部分在下面connect()函数。我们已经知道了connect()因此,我们写了函数的使用

QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue); 

将 slider 的valueChanged()信号同 spinBox 的setValue()函数连接。这是我们熟悉的。然而,当我们直接写作时

QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue); 

编译器会报错:

no matching function for call to 'QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int)) 

这是怎么回事?从错误信息可以看出,编译器认为QSpinBox::valueChanged是一个 overloaded 函数。让我们看看QSpinBox的文档发现,QSpinBox有两个信号:

  • void valueChanged(int)
  • void valueChanged(const QString &)

当我们使用&QSpinBox::valueChanged编译器指针时,编译器不知道应该取哪个函数(记住我们之前介绍过的,已经 moc 预处理后,signal 它也是一个普通的函数。)地址,所以报告错误。解决方案很简单,编译器不能确定哪个函数吗?然后我们显式地指定了一个函数。方法是创建一个函数指针,指定为 int:

void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged; 

然后我们把这个函数指针作为指针 signal,与 QSlider 函数连接:

QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue); 

避免编译错误。

仔细观察这两个connect()它们实际上完成了双向数据绑定。当然,对于 Qt 我们可以放心使用自己的信号函数。但是,如果是自己的信号,就要注意避免无限循环!

我们创建了下面的代码QHBoxLayout对象。显然,这是一个布局管理器。然后将这两个组件添加到布局管理器中,并将布局管理器设置为窗口。这些代码似乎是合乎逻辑的,应该很容易理解。此外,布局管理器聪明地做出了正确的行为:保持QSpinBox宽度不变,自动拉伸QSlider的宽度。

Qt 为我们选择提供了几种布局管理器:

  • QHBoxLayout:按照水平方向从左到右布局;
  • QVBoxLayout:从上到下按垂直方向布局;
  • QGridLayout:布局在网格中,类似于 HTML 的 table;
  • QFormLayout:根据表格布局,每行前面有一段文本,文本后面有一个组件(通常是输入框),类似 HTML 的 form;
  • QStackedLayout:层叠布局允许我们根据几个组件进行分层布局 Z 轴向堆叠可以形成一页一页的导向效果。

当然,我们也可以使用它 Qt 4 编译上正如你应该想到的,我们必须编译上述代码connect()函数修改:

// !!! Qt 4   int main(int argc, char *argv[]) {     QApplication app(argc, argv);       QWidget window;     window.setWindowTitle("Enter your age");       QSpinBox *spinBox = new QSpinBox(&window);     QSlider *slider = new QSlider(Qt::Horizontal, &window);     spinBox->setRange(0, 130);     slider->setRange(0, 130);       QObject::connect(slider,  SIGNAL(valueChanged(int)),                      spinBox, SLOT(setValue(int)));     QObject::connect(spinox, SIGNAL(valueChanged(int)),
                     slider,  SLOT(setValue(int)));
    spinBox->setValue(35);
 
    QHBoxLayout *layout = new QHBoxLayout;
    layout->addWidget(spinBox);
    layout->addWidget(slider);
    window.setLayout(layout);
 
    window.show();
 
    return app.exec();
}

        这里我们强调一下,上面的代码在 Qt 5 中同样可以编译通过。不过,我们减少了使用函数指针指定信号的步骤。也就是说,在 Qt 5 中,如果你想使用 overloaded 的 signal,有两种方式可供选择:

  1. 使用 Qt 4 的SIGNALSLOT宏,因为这两个宏已经指定了参数信息,所以不存在这个问题;
  2. 使用函数指针显式指定使用哪一个信号。

        有时候,使用 Qt 4 的语法更简洁。但是需要注意的是,Qt 4 的语法是没有编译期错误检查的。这也是同 Qt 5 的信号槽新语法不同之处之一。

标签: 襄樊滑竿电位器延安滑竿电位器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台