【问题标题】:QLayout and discrete widget representation - how to?QLayout 和离散小部件表示 - 如何?
【发布时间】:2018-11-26 03:00:35
【问题描述】:

例如,我们在 QMainWindow 中有 QHBoxLayout。

让我们在上面的布局中设置小部件。

但是()很少有小部件具有离散的视觉表示。 换句话说,它们几乎没有依赖于可用空间的状态。

例如:

  1. 如果可用空间过多 - 它必须看起来像大图 + 一些文字
  2. 如果可用空间最小 - 它必须看起来像小图像
  3. 如果只有最小空间可用 - 它必须看起来像按钮 + 标签
  4. 等等……

因此,当用户更改主窗口大小时,我们的“动态”小部件必须根据可用空间显示自己的表示。

如何在 Qt 中实现?

UPD:Microsoft 功能区界面中最接近的行为

UPD2:下面的 gif 中出现的 QML 最接近的行为(在用户调整窗口大小的部分)

UPD3:更复杂的示例 - 菜单面板中的每个面板都会根据可用空间更改内容元素视图和计数

【问题讨论】:

  • sizeHint .. 对你有用吗?
  • 从您的描述看来,QHBoxLayout 中的每个 QWidget 都应该覆盖 QWidget::resizeEvent 并根据其新大小调整其内容/外观。
  • @"Jesper Juhl" 我看了看,但没有找到任何方法来检索新请求的大小。这个功能对我没有帮助:(
  • @G.M.我试过了,但是当我减小窗口大小时,当所有小部件完全适合所有窗口空间时,resizeEvent 停止触发。所以我无法比较请求的大小小于我的复杂小部件大小 -> 所以我无法更改小部件视图

标签: c++ qt layout qwidget


【解决方案1】:

对此没有神奇的解决方案。您需要实现在调整容器大小时要采取的事件/操作。它可以根据您的需要简单或复杂。有几种不同的方法可以实际实现它,具体取决于所涉及的复杂性和范围(它只是几个项目?整个 UI?等等...)。

这是一个非常基本(粗略但有效)的示例,它将工具栏移动到与另一个工具栏(对于更宽的窗口)在同一行(对于更宽的窗口)或移动到它自己的行(对于更窄的窗口)。 MdiChild 在这种情况下是一个 QWidget 实现,显然,它包含其他小部件并管理它们的布局。

void MdiChild::resizeEvent(QResizeEvent * event)
{
  QWidget::resizeEvent(event);
  if (size().width() > ui->topToolbarLayout->sizeHint().width() + ui->botToolbarLayout->sizeHint().width() + 30) {
    ui->botToolbarLayout->removeWidget(modelsToolbar);
    ui->topToolbarLayout->insertWidget(1, modelsToolbar);
  }
  else {
    ui->topToolbarLayout->removeWidget(modelsToolbar);
    ui->botToolbarLayout->insertWidget(0, modelsToolbar);
  }
}

如您所见,它必须考虑容器大小,最直接的方法是在QWidget::resizeEvent() 中。你可以在这里做任何你想做的事情......将文本按钮更改为图标,隐藏/显示/移动内容......随便。

您当然可以将信号/插槽连接到包含的小部件,而不是处理容器中的视觉变化......例如。自定义信号 emit availableSizeChanged(QSize size)resizeEvent() 处理程序 connect()ed 到包含的小部件。

您可能会发现 QStateMachine 可以方便地以正式的方式维护视觉状态(这是 QML 使用的 state[s] 属性和转换系统)。

您也可以按照其他人的建议实现自己的QLayout。尽管问题本身的范围表明您可能不需要。恕我直言,这个问题很笼统。提供的两个示例在复杂性方面存在巨大差异。

【讨论】:

  • Thx,我尝试了使用“resizeEvent”的方法 - 但存在一个巨大的问题:当主窗口的大小 == pLayout->sizeHint() 时,我尝试通过减小窗口大小鼠标 - 没有调用“resizeEvent”并且窗口大小没有改变。但是在您的示例中,比较继续进行公差 (30) - 这种解决方法非常有帮助。
  • 能否请您展示如何使用 QLayout 实现上述工具栏示例?我不明白它是怎么回事。
  • @AeroSun 在第一条评论中,您必须使用尺寸策略/约束和其他布局选项......听起来有一个最小尺寸超过它不会再缩小(因此没有调整事件)。
  • @AeroSun 至于自定义 QLayout,我实际上不确定这是否有意义。对我来说,听起来你的布局将是非常标准的(例如 HBox),但它的内部元素需要根据可用大小进行更改。因此,无论使用何种布局,我认为您需要重新实现将要更改状态的元素(在 MS 工具栏中,这些元素实际上是小部件组)。然后你“只是”需要一些方法来通知这些元素可用的大小。您可能希望/需要在这些自定义元素中重新实现 QWidget::sizeHint()
【解决方案2】:

对于这个答案,我将使用与 Qt 等效的术语,而不是官方的 MS Ribbon 术语。

概述

您实际上正在查看许多布局,其模式如下:

QToolbar
| (Layout)
+--> QGroupBox/QToolButton
|     | (Layout)
|     +----->Button
|     +----->Button
+--> QGroupBox/QToolButton

模式

让我们从只是开始,填充的QGroupBox 有助于将我们的按钮分类。

考虑到我们的组框可能包含我们的动态QToolButton 和常规小部件。当可用空间缩小时,布局:

  • 计算固定大小的小部件所需的最小空间以及没有固定大小策略的小部件的minimumSizeHint() 值。
  • 根据每个小部件的增长策略分配剩余空间。
  • 然而,我们的动态工具按钮可能会也可能不会根据可用空间改变大小。
  • 现在我们必须使用qobject_cast 开始检查布局的子级是否是动态的。
  • 当我们找到一个动态按钮时,我们必须确定它是否可以收缩。如果是,我们会缓存它及其首选的更小尺寸。
  • 如果要缩小,我们必须重新计算最小尺寸。
  • 然后我们必须继续前进,希望在调整大小期间缩小按钮不会导致任何棘手的决胜局。
  • Tie Breakers:如果两个按钮可以折叠成更小的尺寸,那么哪个按钮先走?我们也必须考虑那个。此外,MS 使用三个按钮的行。我们不能将一个从 Qt::ToolButtonTextBesideIcon 折叠到 Qt::ToolButtonIconOnly,我们必须折叠一组三个。
  • 三个水平按钮可以折叠成三个垂直按钮。这也需要计算和缓存。

还有希望。

我们可以通过使每个容器能够容纳动态工具按钮来简化。这样我们就不必处​​理固定大小的小部件等棘手的问题,我们只需要处理一种类型的小部件。

Microsoft 还帮助我们实现了此行为。您可以通过经验观察了解很多关于布局和子小部件的行为约束的信息。群体何时崩溃?如果一个组崩溃,其他组是否会扩展以占用空间? (顺便说一句,答案是否定的。)按钮在折叠时如何组合在一起?它们在折叠和展开的方式上是否有一些特殊之处(对其展开和折叠行为的限制)?

Qt 还实现了几种布局供我们研究并了解它们的工作原理以及它们的不同之处。 QGridLayout 是一个很有前途的基础,特别是如果您进行一些数学运算来动态更改小部件的行跨度(这是为了在按钮从垂直布局折叠为三个水平按钮的集合时对它们进行分组)。

总结

完全回答您的问题过于宽泛,无法成为 SO 的主题,但我希望这些信息能够指导您去往何处。

【讨论】:

  • 很好的逐步分解调整大小问题,确实不是一件小事。但这是现有 QLayouts 已经做的事情。此示例中的“动态”对象几乎是任何没有 QSizePolicy::Fixed 且位于可以更改大小(无约束)的布局单元格内的东西。这是布局的基本功能。我也同意你的总结,事实上我们甚至不知道工具栏是否真的是 OP 使用它的目的...... :) 还想知道树中的 QGroupBox/QToolButton 是什么意思(看起来像和/或者但是子按钮没有意义)。
  • @MaxPaperno 回复:QGroupBox/QToolButton:当父窗口水平收缩得足够多并且按钮折叠没有提供足够的空间时,组框会隐藏自身并在其位置静默插入 QToolButton。单击该工具按钮,然后将组框显示为弹出窗口。尝试调整 Windows 资源管理器窗口的大小,使其变得非常窄,看看组框是如何折叠成按钮的。
  • 关于动态对象:澄清一下,由于可用空间而折叠的工具按钮可能从需要 33x90 像素变为 23x60。这不是一个简单的 +/-。所以布局必须决定,“如果我将这三个(垂直)按钮分组”或“如果我从这三个(水平)按钮中删除文本”,必要的空间可能会发生很大变化。使这一切成为可能的一点是,“可用空间”实际上只是水平可用的——工具栏(以及它的内容)在垂直方向上是静态的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-03
  • 2018-10-20
  • 1970-01-01
  • 2015-10-09
相关资源
最近更新 更多