juce - 界面布局
在 JUCE 5.4.3 中实现界面控件自适应窗口大小,主要依靠布局管理器和响应式设计。以下是详细解决方案:
一、核心方法:使用布局管理器(推荐)
JUCE 提供了两种现代布局系统,优先推荐使用:
1. FlexBox 布局
-
类似 Qt 的 QBoxLayout:可实现水平和垂直方向的弹性布局
class MainComponent : public Component {
public:
MainComponent() {
addAndMakeVisible(button1);
addAndMakeVisible(slider1);
addAndMakeVisible(label1);
}
void resized() override {
FlexBox fb;
fb.flexDirection = FlexBox::Direction::column; // 垂直排列
fb.justifyContent = FlexBox::JustifyContent::spaceAround; // 均匀分布
fb.alignItems = FlexBox::AlignItems::stretch; // 拉伸填满
// 添加带弹性系数的组件
fb.items.addArray({
FlexItem(button1).withFlex(1).withMargin(10), // 弹性系数1
FlexItem(slider1).withFlex(2).withMargin(10), // 弹性系数2 (占双倍空间)
FlexItem(label1).withFlex(1).withMargin(10)
});
fb.performLayout(getLocalBounds());
}
private:
TextButton button1 {"Button"};
Slider slider1;
Label label1 {"Label", "Hello JUCE!"};
};
2. Grid 布局
-
类似 Qt 的 QGridLayout:网格布局系统
void resized() override {
Grid grid;
// 定义3列:1份弹性空间 | 固定100px | 2份弹性空间
grid.templateColumns = { Grid::Fr(1), Grid::Px(100), Grid::Fr(2) };
// 定义2行:自动高度 | 弹性高度
grid.templateRows = { Grid::auto, Grid::Fr(1) };
// 添加组件到网格位置
grid.items.addArray({
GridItem(button1).withArea(1, 1), // 第1行第1列
GridItem(slider1).withArea(1, 2).withSpan(2, 1), // 跨2行
GridItem(label1).withArea(2, 3) // 第2行第3列
});
grid.performLayout(getLocalBounds().reduced(10)); // 带边距
}
二、传统方法:手动计算布局
适用于简单场景:
void resized() override {
auto area = getLocalBounds().reduced(10); // 边距10px
// 顶部按钮 (高度固定40px)
button1.setBounds(area.removeFromTop(40));
// 中间滑块 (占剩余高度的30%)
slider1.setBounds(area.removeFromTop(area.getHeight() * 0.3f));
// 底部标签 (剩余空间)
label1.setBounds(area);
}
关键方法:
-
getLocalBounds(): 获取可绘制区域 -
removeFromTop()/removeFromLeft(): 切割区域 -
withTrimmed(): 内边距调整 withSizeKeepingCentre(): 居中元素
关键技巧:
-
比例分配
// 水平三等分 auto thirdWidth = getWidth() / 3; comp1.setBounds(0, 0, thirdWidth, getHeight()); comp2.setBounds(thirdWidth, 0, thirdWidth, getHeight()); -
响应缩放
void resized() override { const int margin = jmin(20, getWidth()/20); // 动态边距 // ... } -
嵌套布局
class ChildComponent : public Component { public: void resized() override { // 子组件自己的布局 } }; // 父组件布局 void parentResized() { childComp.setBounds(getWidth()/4, 10, getWidth()/2, getHeight()-20); }
最佳实践:
-
优先选择 FlexBox/Grid - 更易维护且支持复杂响应式布局
-
使用相对单位 - 避免固定尺寸,多用比例和弹性系数
-
处理边界情况:
void resized() override { if (getWidth() < 300) { // 小屏幕布局 // 垂直排列 } else { // 大屏幕布局 // 水平排列 } }
组件约束(可选):
slider1.setSize(200, 40); // 基础尺寸
slider1.setMaximumSize(400, 60); // 最大尺寸
slider1.setMinimumSize(100, 30); // 最小尺寸
这些方法组合使用可创建出:
-
按比例缩放的控件
-
动态排列的布局(横/竖屏自适应)
-
保持合理间距的响应式界面
-
适应不同分辨率的UI系统
建议从简单布局开始尝试,逐步组合复杂界面。JUCE的布局系统非常强大,熟练后可以轻松实现专业级的自适应界面。
JUCE 矩形切割函数详解:
removeFromTop()、removeFromLeft()、removeFromBottom()、removeFromRight()
这些函数都是juce::Rectangle类的成员函数,用于从当前矩形中切割出一部分,并修改原矩形。
每个函数的作用:
- removeFromTop(int height): 从当前矩形的顶部切割出一个高度为height的矩形,原矩形的高度减少height(原矩形的y坐标增加height,高度减少height)。
- removeFromLeft(int width): 从当前矩形的左侧切割出一个宽度为width的矩形,原矩形的宽度减少width(原矩形的x坐标增加width,宽度减少width)。
- removeFromBottom(int height): 从当前矩形的底部切割出一个高度为height的矩形,原矩形的高度减少height(原矩形的高度减少height,y坐标不变)。
- removeFromRight(int width): 从当前矩形的右侧切割出一个宽度为width的矩形,原矩形的宽度减少width(原矩形的宽度减少width,x坐标不变)。
注意:这些函数都会返回被切割出来的新矩形,同时修改调用函数的矩形对象本身(即原矩形会减去被切割掉的部分)。
在JUCE的布局系统中,这四个矩形操作函数是构建复杂界面的基础工具。它们允许你通过"切割"矩形区域来精确分配空间。下面我将详细解释每个函数的工作原理和使用方法。
核心概念:矩形切割原理
JUCE中的juce::Rectangle对象代表一个矩形区域。这些切割函数的核心特点是:
-
修改原始矩形:调用函数后会修改原始矩形
-
返回切割部分:函数返回被切割下来的矩形
-
保持剩余区域:原始矩形变为剩余部分
视觉化表示
初始矩形:
+-------------------+
| |
| |
| |
+-------------------+
1. removeFromTop() - 从顶部切割
功能
从矩形顶部切下一块指定高度的区域
语法
Rectangle<int> topPart = originalRect.removeFromTop(int height);
详细行为
-
从矩形顶部切下高度为
height的部分 -
返回被切下的顶部矩形
-
原始矩形的高度减少
height,Y坐标增加height
代码示例
void resized() override {
auto area = getLocalBounds(); // 假设为 400x300
// 切下顶部100像素
auto header = area.removeFromTop(100);
headerComponent.setBounds(header); // 设置header组件
// 剩余区域: 400x200 (Y从100开始)
mainContent.setBounds(area);
}
视觉变化
初始:
+-------------------+
| header | ← 切下的部分 (100px)
+-------------------+
| |
| remaining area | ← 修改后的原始矩形
| |
+-------------------+
2. removeFromBottom() - 从底部切割
功能
从矩形底部切下一块指定高度的区域
语法
Rectangle<int> bottomPart = originalRect.removeFromBottom(int height);
详细行为
-
从矩形底部切下高度为
height的部分 -
返回被切下的底部矩形
-
原始矩形的高度减少
height,Y坐标不变
代码示例
void resized() override {
auto area = getLocalBounds(); // 400x300
// 切下底部50像素
auto footer = area.removeFromBottom(50);
statusBar.setBounds(footer); // 设置footer组件
// 剩余区域: 400x250 (高度减少)
contentArea.setBounds(area);
}
视觉变化
初始:
+-------------------+
| |
| remaining area | ← 修改后的原始矩形
| |
+-------------------+
| footer | ← 切下的部分 (50px)
+-------------------+
3. removeFromLeft() - 从左侧切割
功能
从矩形左侧切下一块指定宽度的区域
语法
Rectangle<int> leftPart = originalRect.removeFromLeft(int width);
详细行为
-
从矩形左侧切下宽度为
width的部分 -
返回被切下的左侧矩形
-
原始矩形的宽度减少
width,X坐标增加width
代码示例
void resized() override {
auto area = getLocalBounds(); // 400x300
// 切下左侧150像素
auto sidebar = area.removeFromLeft(150);
navigationPanel.setBounds(sidebar); // 设置侧边栏
// 剩余区域: 250x300 (X从150开始)
mainContent.setBounds(area);
}
视觉变化
初始:
+-------------------+
| | |
| 切 | remaining |
| 下 | area |
| 的 | |
| 左 | |
| 侧 | |
+-------------------+
4. removeFromRight() - 从右侧切割
功能
从矩形右侧切下一块指定宽度的区域
语法
Rectangle<int> rightPart = originalRect.removeFromRight(int width);
详细行为
-
从矩形右侧切下宽度为
width的部分 -
返回被切下的右侧矩形
-
原始矩形的宽度减少
width,X坐标不变
代码示例
void resized() override {
auto area = getLocalBounds(); // 400x300
// 切下右侧80像素
auto toolbar = area.removeFromRight(80);
toolsPanel.setBounds(toolbar); // 设置工具栏
// 剩余区域: 320x300 (宽度减少)
editorArea.setBounds(area);
}
视觉变化
初始:
+-------------------+
| | |
| remaining | 切 |
| area | 下 |
| | 的 |
| | 右 |
| | 侧 |
+-------------------+
组合使用:完整布局示例
void resized() override {
auto area = getLocalBounds(); // 获取整个可用区域
// 顶部标题栏 (固定高度60px)
auto titleBar = area.removeFromTop(60);
titleComponent.setBounds(titleBar);
// 底部状态栏 (固定高度40px)
auto statusBar = area.removeFromBottom(40);
statusComponent.setBounds(statusBar);
// 左侧导航栏 (固定宽度200px)
auto sidebar = area.removeFromLeft(200);
navComponent.setBounds(sidebar);
// 右侧工具栏 (固定宽度80px)
auto tools = area.removeFromRight(80);
toolsComponent.setBounds(tools);
// 中间主内容区 (剩余所有空间)
contentComponent.setBounds(area);
}
动态尺寸布局技巧
比例切割
void resized() override {
auto area = getLocalBounds();
// 顶部占20%高度
int headerHeight = getHeight() * 0.2;
header.setBounds(area.removeFromTop(headerHeight));
// 左侧占30%宽度
int sidebarWidth = getWidth() * 0.3;
sidebar.setBounds(area.removeFromLeft(sidebarWidth));
// 剩余区域给主内容
mainContent.setBounds(area);
}
带间距的切割
void resized() override {
auto area = getLocalBounds();
// 顶部区域带10px下边距
auto top = area.removeFromTop(100);
topComponent.setBounds(top.withTrimmedBottom(10)); // 实际高度90px
// 剩余区域带10px上边距
area = area.withTrimmedTop(10);
// 左侧区域带5px右边距
auto left = area.removeFromLeft(150);
leftComponent.setBounds(left.withTrimmedRight(5));
// 主内容区
mainContent.setBounds(area);
}
高级链式操作
void resized() override {
auto area = getLocalBounds();
// 链式切割
titleBar.setBounds(area.removeFromTop(50)
.reduced(5); // 添加5px内边距
statusBar.setBounds(area.removeFromBottom(30)
.withTrimmedLeft(10) // 左侧留白
.withTrimmedRight(10); // 右侧留白
sidebar.setBounds(area.removeFromLeft(150));
// 在剩余区域中创建两个等高的面板
auto topPanel = area.removeFromTop(area.getHeight() / 2);
panel1.setBounds(topPanel.reduced(2));
panel2.setBounds(area.reduced(2));
}
JUCE中withSizeKeepingCentre函数详解:
withSizeKeepingCentre是JUCE矩形操作中一个非常有用的函数,它可以在保持矩形中心点不变的情况下改变矩形尺寸。这个函数在创建居中元素时特别有用,比如居中按钮、图标或其他UI组件。
函数定义和作用
函数签名
Rectangle<T> withSizeKeepingCentre(T newWidth, T newHeight) const noexcept;
核心功能
-
保持中心不变:新矩形的中心点与原矩形相同
-
改变尺寸:将矩形尺寸调整为指定的新宽度和新高度
-
不修改原矩形:返回一个新矩形,原始矩形保持不变
使用示例分析
让我们分解你提供的代码:
pTextButton[BTN_MUTE]->setBounds(r.removeFromTop(36).withSizeKeepingCentre(50, 20));
逐步解释
-
r.removeFromTop(36)-
从矩形
r中切下顶部36像素的区域 -
返回一个高度为36像素,宽度与
r相同的矩形
-
-
.withSizeKeepingCentre(50, 20)-
基于上一步得到的矩形创建一个新矩形
-
新矩形宽度为50像素,高度为20像素
-
新矩形的中心位置与原矩形中心相同
-
-
setBounds()-
将静音按钮放置在这个新创建的矩形区域内
-
视觉化表示
原始矩形r:
+-------------------+
| | ← 切下的36px区域
| |
+-------------------+
| |
| |
| |
+-------------------+
切下的顶部区域:
+-------------------+
| | ← 高度36px
| |
+-------------------+
应用withSizeKeepingCentre(50, 20):
+-------------------+
| +----+ | ← 新矩形50x20px
| | | | 居中显示
| +----+ |
+-------------------+

浙公网安备 33010602011771号