Juce实现Table自定义
Juce实现Table自定义
一.总体展示概及概述
在项目中Juce中TableList往往无法满足用户需求,头部和背景及背景颜色设置以及在Cell中添加自定义按钮,所以需要自己实现自定义TabelList,该示例是展示实现自定义TableList,实现自定义标题头及Item,程序员在使用过程中可以自己修改颜色皮肤,按需求实现相关功能。总体展示示例如下:
二.实现步骤
1.实现自定义TableListModel
实现TableListModel的背景绘制,绘制单元格,及重新实现单元格生成的控件函数,绘制单元格边线。
#pragma once#include <JuceHeader.h>
#include "TabelLookAndFeel.h"
#include "TableLabel.h"
#include "TabelOperCell.h"
#include <vector>
using namespace juce;class CustomTableModel :public juce::TableListBoxModel,public Label::Listener,public TabelOperComponent::Listener
{
public:struct TableItemInfo{std::string str_time_;std::string str_name_;bool b_checked = false;TableItemInfo(const std::string& str_time, const std::string& str_name,bool bChecked=false):str_time_(str_time), str_name_(str_name),b_checked(bChecked){}};public:CustomTableModel(std::vector<TableItemInfo>& items):vec_table_item_(items){}~CustomTableModel(){}int getNumRows() override{return vec_table_item_.size();}void paintRowBackground(juce::Graphics& g, int rowNumber, int width, int height, bool rowIsSelected) override{// 绘制行背景颜色juce::Colour bgColour(2,75,96);// = juce::Colour(8, 82.120);/* rowNumber % 2 ? juce::Colours::white//: juce::Colour(0xfff8f8f8);*/if (rowIsSelected)bgColour = Colour(127,191,127);g.fillAll(bgColour);// 绘制行底部分隔线//g.setColour(Colour(52,110,127));//g.drawLine(0, height - 1, width, height - 1);}void paintCell(juce::Graphics& g, int rowNumber, int columnId, int width, int height, bool rowIsSelected) override{//if (columnId != 1) // 非复选框列{// 设置文本样式g.setFont(juce::Font(14.0f));//g.setColour(rowIsSelected ? juce::Colours::black : juce::Colours::darkgrey);g.setColour(Colours::white);if (vec_table_item_.size() > rowNumber){if (columnId == 1){g.drawText(std::to_string(rowNumber+1), juce::Rectangle<int>(0, 0, width, height),juce::Justification::centred, true);}//else if (columnId == 2)// g.drawText(vec_table_item_[rowNumber].str_name_.c_str(), juce::Rectangle<int>(0, 0, width, height),// juce::Justification::centred, true);else if (columnId == 3)g.drawText(vec_table_item_[rowNumber].str_time_.c_str(), juce::Rectangle<int>(0, 0, width, height),juce::Justification::centred, true);}}// 绘制方格线g.setColour(Colour(52, 110, 127));//g.drawRect(0, 0, width, height);//g.drawLine(0, 0, width, 0, 2); // 绘制上边线g.drawLine(0, 0, 0, height, 2); // 绘制左边线g.drawLine(0, height, width, height, 2);// 绘制下边线if (columnId == 4)g.drawLine(width, 0, width, height, 2); // 绘制右边线}juce::Component* refreshComponentForCell(int rowNumber, int columnId, bool isRowSelected,juce::Component* existingComponentToUpdate) override{if (columnId == 2) // 复选框列{TabelLabel* label = static_cast<TabelLabel*>(existingComponentToUpdate);if (label == nullptr){label = new TabelLabel();label->setRow(rowNumber);label->setText(vec_table_item_[rowNumber].str_name_.c_str(),dontSendNotification);label->setEditable(true, true, false);label->addListener(this);}if (rowNumber < data.size()){label->setText(data[rowNumber][columnId - 1], juce::dontSendNotification);}return label;}else if (columnId == 4){TabelOperComponent* oper = static_cast<TabelOperComponent*>(existingComponentToUpdate);if (oper == nullptr){oper = new TabelOperComponent();oper->setRow(rowNumber);}return oper;}return nullptr;}// 设置 TableListBox 指针void setTable(juce::TableListBox* tableListBox){table = tableListBox;}// 处理标签文本更改事件void labelTextChanged(juce::Label* label) override{TabelLabel* label_new = static_cast<TabelLabel*>(label);int row = label_new->getRow();}void itemClicked(TabelOperComponent* oper, int type) override{int row = oper->getRow();}
private:juce::Array<juce::StringArray> data;juce::TableListBox* table = nullptr;std::vector<TableItemInfo>& vec_table_item_;juce::Array<bool> toggleStates;//CustomToggleLookAndFeel customToggleLookAndFeel;JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CustomTableModel)
};
2.实现TableList的标题头
继承自LookAndFeel_V4 绘制Border,绘制列及绘制背景色
#pragma once
#include <JuceHeader.h>
using namespace juce;class CustomTableHeaderLookAndFeel : public juce::LookAndFeel_V4
{
public:void drawTableHeaderBackground(juce::Graphics& g, juce::TableHeaderComponent& header) override{// 绘制表头背景//auto color = ;auto color = Colours::black.fromFloatRGBA(0, 0, 0, 0.25);g.fillAll(color);}// 新增绘制表格边框的方法void drawTableBorder(juce::Graphics& g, juce::TableListBox& table){g.setColour(juce::Colour(52, 110, 127)); // 设置边框颜色juce::Rectangle<int> bounds = table.getLocalBounds();// 绘制上边框g.drawLine(bounds.getX(), bounds.getY(), bounds.getRight(), bounds.getY(), 1);// 绘制下边框//g.drawLine(bounds.getX(), bounds.getBottom(), bounds.getRight(), bounds.getBottom(), 1);// 绘制左边框//g.drawLine(bounds.getX(), bounds.getY(), bounds.getX(), bounds.getBottom(), 1);// 绘制右边框//g.drawLine(bounds.getRight(), bounds.getY(), bounds.getRight(), bounds.getBottom(), 1);}void drawTableHeaderColumn(juce::Graphics& g, juce::TableHeaderComponent& header,const juce::String& columnName, int columnId,int width, int height, bool isMouseOver,bool isMouseDown, int columnFlags) override{{// 其他列的文本绘制(与item文本样式一致)g.setFont(juce::Font(14.0f)); // 设置与item相同的字体大小g.setColour(juce::Colours::white);g.drawText(columnName, juce::Rectangle<int>(0, 0, width, height),juce::Justification::centred, true);}// 绘制列的边框线g.setColour(Colour(52, 110, 127)); // 设置边框线颜色//g.drawRect(0, 0, width, height, 1); // 绘制1px宽的边框线g.drawLine(0, 0, width, 0, 2); // 绘制上边线g.drawLine(0, 0, 0, height, 2); // 绘制左边线g.drawLine(0, height, width, height,2);if(columnId == 4)g.drawLine(width, 0, width, height, 2); // 绘制右边线}
};
3.在列中实现自定义button
在对应列中实现自定义component创建,如下所示:
对应自定义component的代码示例:简单实现了三个按钮,同学可以根据自己情况修改按钮,可以增加图标增加美观
class TabelOperComponent : public juce::Component,public juce::ToggleButton::Listener
{
public:static const int BTN_NUM = 3;class JUCE_API Listener{public:/** Destructor. */virtual ~Listener() = default;virtual void itemClicked(TabelOperComponent* oper,int type) = 0;};void addListener(Listener* newListener) {const ScopedLock sl(listenerLock);listeners.addIfNotAlreadyThere(newListener);}void removeListener(Listener* listenerToRemove) {const ScopedLock sl(listenerLock);listeners.removeFirstMatchingValue(listenerToRemove);}TabelOperComponent();~TabelOperComponent() override {}void setRow(int row) { row_ = row; }int getRow() { return row_; }void paint(juce::Graphics& g) override;void resized() override;virtual void buttonClicked(Button*) override;
private:int row_ = 0;CriticalSection listenerLock;Array<Listener*> listeners;juce::ToggleButton toggleButtons[BTN_NUM];JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TabelOperComponent)
};
#include "TabelOperCell.h"
TabelOperComponent::TabelOperComponent()
{for (int i = 0; i < 3; ++i){addAndMakeVisible(toggleButtons[i]);}
}
void TabelOperComponent::paint(juce::Graphics& g)
{//g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));auto area = getLocalBounds().toFloat();g.setColour(Colour(52, 110, 127));int width = area.getWidth();int height = area.getHeight();g.drawLine(0, 0, 0, height, 2); g.drawLine(width, 0, width, height, 2); g.drawLine(0, height, width, height, 2);
}void TabelOperComponent::resized()
{auto area = getLocalBounds();int width = (area.getWidth()-6)/3;for (auto& button : toggleButtons){button.setBounds(area.removeFromLeft(width).withSizeKeepingCentre(16,16));area.removeFromLeft(2);}
}void TabelOperComponent::buttonClicked(Button* ptr_btn)
{for (int i = 0; i < BTN_NUM; i++){if (ptr_btn == &toggleButtons[i]){ScopedLock lock(listenerLock);for (int j = listeners.size(); --j >= 0;)if (auto* l = listeners[j])l->itemClicked(this,i);}}
}
4.在MainCompoent中使用自定义TableList
使用Table和LookAndFeel并自定义了Item参数结构体,设置TableList的属性,并自定义添加Item条数。
示例代码如下:
#pragma once#include <JuceHeader.h>
#include "PresetTableComponent.h"
#include "TabelLookAndFeel.h"//==============================================================================
/*This component lives inside our window, and this is where you should put allyour controls and content.
*/
class MainComponent : public juce::Component
{
public://==============================================================================MainComponent();~MainComponent() override;//==============================================================================void paint (juce::Graphics&) override;void resized() override;private://==============================================================================// Your private member variables go here...juce::TableListBox table_;CustomTableModel* table_model_ = nullptr;CustomTableHeaderLookAndFeel customLookAndFeel;std::vector<CustomTableModel::TableItemInfo> vec_table_item_;//TableDemoComponent table;JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
#include "MainComponent.h"//==============================================================================
MainComponent::MainComponent()
{//addAndMakeVisible(&table);table_.setLookAndFeel(&customLookAndFeel);table_.getHeader().addColumn("ID", 1, 10);table_.getHeader().addColumn("Name", 2, 10);table_.getHeader().addColumn("Time", 3, 10 * 4);table_.getHeader().addColumn("Operation", 4, 60);table_.getHeader().setSize(getWidth(), 32);table_.setColour(juce::TableListBox::backgroundColourId, Colour(2, 75, 96));table_.getViewport()->setScrollBarsShown(false, false);table_.getHeader().setPopupMenuActive(false);table_.getHeader().addMouseListener(this, false);table_.getHeader().setColumnVisible(7, false); // hide the "length" column until the user shows ittable_.setMultipleSelectionEnabled(true);addAndMakeVisible(&table_);setSize(500, 500);
}MainComponent::~MainComponent()
{
}//==============================================================================
void MainComponent::paint (juce::Graphics& g)
{// (Our component is opaque, so we must completely fill the background with a solid colour)g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));g.setFont (juce::Font (16.0f));g.setColour (juce::Colours::white);g.drawText ("Hello World!", getLocalBounds(), juce::Justification::centred, true);
}void MainComponent::resized()
{auto area = getLocalBounds();if (table_model_){table_.setModel(nullptr);delete table_model_;table_model_ = nullptr;}vec_table_item_.clear();for (int i = 0; i < 10; i++){vec_table_item_.emplace_back("2025-04-17 13:56:00", "Name1");}if (!table_model_){table_model_ = new CustomTableModel(vec_table_item_);table_.setModel(table_model_);table_model_->setTable(&table_);}auto tab_area = area;int colum_with = tab_area.getWidth() / 8;table_.setRowHeight(32);table_.getHeader().setColumnWidth(1, tab_area.removeFromLeft(colum_with).getWidth()); table_.getHeader().setColumnWidth(2, tab_area.removeFromLeft(colum_with).getWidth());table_.getHeader().setColumnWidth(3, tab_area.removeFromLeft(4 * colum_with).getWidth());table_.getHeader().setColumnWidth(4, tab_area.getWidth());table_.getHeader().setSize(getWidth(), 32);table_.getHeader().getProperties().set("allSelected", false);table_.setBounds(area);
}
相关文章:

Juce实现Table自定义
Juce实现Table自定义 一.总体展示概及概述 在项目中Juce中TableList往往无法满足用户需求,头部和背景及背景颜色设置以及在Cell中添加自定义按钮,所以需要自己实现自定义TabelList,该示例是展示实现自定义TableList,实现自定义标…...
【25.06】fabric进行caliper测试加环境部署
前置条件 安装一个Ubuntu20+的镜像 基础环境安装 Git cURL vim jq sudo apt install -y git curl vim jq Docker和Docker-compose 这个命令会自动安装docker sudo apt install docker-compose sudo chmod +x /usr/bin/docker-compose docker versiondocker-compose vers…...

【后端高阶面经:架构篇】51、搜索引擎架构与排序算法:面试关键知识点全解析
一、搜索引擎核心基石:倒排索引技术深度解析 (一)倒排索引的本质与构建流程 倒排索引(Inverted Index)是搜索引擎实现快速检索的核心数据结构,与传统数据库的正向索引(文档→关键词࿰…...

Windows应用-音视频捕获
下载“Windows应用-音视频捕获”项目 本应用可以同时捕获4个视频源和4个音频源,可以监视视频源图像,监听音频源;可以将视频源图像写入MP4文件,将音频源写入MP3或WAV文件;还可以录制系统播放的声音。本应用使用MFC对话框…...

【OCCT+ImGUI系列】012-Geom2d_AxisPlacement
Geom2d_AxisPlacement 教学笔记 一、类概述 Geom2d_AxisPlacement 表示二维几何空间中的一个坐标轴(轴系),由两部分组成: gp_Pnt2d:原点(Location)gp_Dir2d:单位方向向量ÿ…...
优化WP外贸建站提升用户体验
WordPress作为一个强大的建站工具,通过合理的优化,可以提升用户体验,吸引更多潜在客户。本文将为您介绍一些优化WordPress外贸建站的实用建议。 1. 响应式设计 随着移动设备的普及,确保您的WordPress网站具有响应式设计变得至关…...

【C++高并发内存池篇】性能卷王养成记:C++ 定长内存池,让内存分配快到飞起!
📝本篇摘要 在本篇将介绍C定长内存池的概念及实现问题,引入内存池技术,通过实现一个简单的定长内存池部分,体会奥妙所在,进而为之后实现整体的内存池做铺垫! 🏠欢迎拜访🏠ÿ…...

mac下通过anaconda安装Python
本次分享mac下通过anaconda安装Python、Jupyter Notebook、R。 anaconda安装 点击👉https://www.anaconda.com/download, 点击Mac系统安装包, 选择Mac芯片:苹果芯片 or intel芯片, 选择苹果芯片图形界面安装&#x…...
第3篇:数据库路由模块设计与 SQL 路由策略解析
3.1 什么是数据库路由? 在分库分表或多数据库实例架构中,**数据库路由模块(SQL Router)**的作用是: 将客户端发来的 SQL 请求路由到正确的后端数据库实例或分片表中执行。 它是数据库中间件的核心组件之一。 3.2 数据…...
ARINC818编解码设计FPGA实现
一、设计内容 1.基于xilinx平台进行系列产品设计 2.基于GT高速进行进行设计 3.提供良好的技术支持和售后服务 4.比较详细的代码注释 二、模块设计内容 1.模块顶层设计 2.编码模块部分设计 内容包括: 帧信息产生/ojbect0帧格式产生和发送/object2_object3帧格式产生…...

微软PowerBI考试 PL300-Power BI 入门
Power BI 入门 上篇更新了微软PowerBI考试 PL-300学习指南,今天分享PowerBI入门学习内容。 简介 Microsoft Power BI 是一个完整的报表解决方案,通过开发工具和联机平台提供数据准备、数据可视化、分发和管理。 Power BI 可以从使用单个数据源的简单…...
逻辑回归知识点
一、逻辑回归概念 逻辑回归(Logistic Regression)是一种广泛应用于分类问题的统计方法,尤其适用于二分类问题。 注意: 尽管名称中有"回归"二字,但它实际上是一种分类算法。 解决二分类的问题。 API:sklearn.linear_model.Logis…...
YARN架构解析:大数据资源管理核心
一、YARN的设计目标 解耦资源管理与作业调度:将资源管理(Resource Management)和任务执行(Task Execution)分离,提升集群资源利用率。支持多种计算框架:不再局限于MapRedu…...
嵌入式学习笔记 - freeRTOS在程序开始在任务内创建任务的好处是什么
在FreeRTOS中,程序启动后优先在初始任务(而非main()函数)内创建其他任务是一种常见且推荐的设计模式,其主要优势包括以下几点: 以下来自deepseek的回答,很全面很正确: 🔧 1. 避免…...

Ubuntu22.04 安装 CUDA12.8
1.下载CUDA 由于我装完 Ubuntu22.04 后就自动带了最新的显卡驱动,就没有再去配置驱动。 先查看驱动能支持的CUDA最高版本,这里显示可支持到12.8。 nvidia-smi在CUDA的 说明文档 可查看CUDA对应的驱动版本要求。 在 CUDA Toolkit Archive 查找需要的 …...

Android的uid~package~pid的关系
UID : Linux 系统级用户标识,Android 中每个应用安装时分配唯一 UID(如 1000)。 Package: Android 应用包名(例如android),一个 UID 可关联多个 Package(共享 UID 场景如android:sharedUserI…...
线段树刷题记录
一篇讲解很好的线段树博客:数据结构--线段树篇_数据结构线段树-CSDN博客 一、区间查询 无修改: (一)最值问题: 1.P1816 忠诚 - 洛谷 思路: 模板。 注意: 无。 代码: #include …...

20250530-C#知识:万物之父Object
C#知识:万物之父Object Object类(即object)是所有类的基类,这里面的方法还是需要好好了解一下。 1、Object类 是顶级父类,其他类默认都是Object类的子类(自定义类也会默认继承Object类)可以用O…...

多元素纳米颗粒:开启能源催化新纪元
在能源转型的浪潮中,纳米催化剂正成为推动能源技术突破的关键力量。多元素纳米颗粒(Polyelemental Nanoparticles)凭借其独特的元素协同效应,展现出在能源催化领域的巨大潜力。然而,合成这些复杂体系的纳米颗粒面临着诸…...

分布式锁优化:使用Lua脚本保证释放锁的原子性问题
分布式锁优化(二):使用Lua脚本保证释放锁的原子性问题 💻黑马视频链接:Lua脚本解决多条命令原子性问题 在上一章节视频实现了一个可用的Redis分布式锁,采用SET NX EX命令实现互斥和过期自动释放机制&…...

电脑wifi显示已禁用怎么点都无法启用
一、重启路由器与电脑 有时候,简单的重启可以解决很多小故障。试着先断开电源让路由器休息一会儿再接通;对于电脑,则可选择重启系统看看情况是否有改善。 二、检查驱动程序 无线网卡驱动程序的问题也是导致WiFi无法启用的常见原因之一。我…...

【FPGA开发】Ubuntu16.04环境下配置Vivado2018.3—附软件包
文章目录 环境介绍关键步骤记录安装虚拟机及镜像安装vivadolicense导入 环境介绍 vivado:2018.3 虚拟机:vmware 16 pro 镜像:Ubuntu16.04 64位 所有相关软件压缩包: 链接:https://pan.quark.cn/s/fd2730b46b20 提取码…...

vue-seamless-scroll 结束从头开始,加延时后滚动
今天遇到一个大屏需求: 1️⃣初始进入页面停留5秒,然后开始滚动 2️⃣最后一条数据出现在最后一行时候暂停5秒,然后返回1️⃣ 依次循环,发现vue-seamless-scroll的方法 ScrollEnd是监测最后一条数据消失在第一行才回调ÿ…...
不同的数据库操作方式:MongoDB(NoSQL)和 MySQL/SQL
这两种写法分别使用了不同的数据库操作方式:第一种是 MongoDB(NoSQL) 的写法,第二种是 MySQL/SQL 的写法。我们来对比它们的区别,并给出优化建议。 1. MongoDB(NoSQL)写法 const user await d…...

0-EATSA-GNN:基于图节点分类师生机制的边缘感知和两阶段注意力增强图神经网络(code)
code:https://github.com/afofanah/EATSA-GNN. 文章目录 Abstract1. Introduction1.1.动态图场景1.2.EATSA-GNN框架的背景化2. Background2.1.GNN边缘感知挑战2.2.GNN的可解释性问题2.3.EATSA-GNN可解释性3. Related worksAbstract 图神经网络(GNNs)从根本上改变了我们处理和…...
大数据学习(124)-spark数据倾斜
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...

配置前端控制器
一、DispatcherServlet 详解 在使用 Spring MVC 框架构建 Web 应用时,DispatcherServlet是整个请求处理流程的核心。本文将深入解析DispatcherServlet的作用、工作原理及其在 Spring MVC 架构中的关键地位。 1.DispatcherServlet 是什么? DispatcherS…...

lua注意事项
感觉是lua的一大坑啊,它还不如函数内部就局部变量呢 注意函数等内部,全部给加上local得了...

Git的三种合并方式
在 Gitee(码云)中合并分支主要有三种方式:普通合并(Merge Commit)、压缩合并(Squash Merge)和变基合并(Rebase Merge)。每种方式适用于不同的场景,各有…...

从零到一:我的技术博客导航(持续更新)
作者:冰茶 最后更新:2025年6月3日 本文收录了我的C#编程学习心得与技术探索,将持续更新 前言 作为一名.NET开发者,C#语言的学习与探索一直是我技术成长的核心路径。本文集整理了我在C#学习过程中的思考与实践,希望能够…...