Juce - 按钮贴背景图片(DrawableButton)

环境:juce5.4.3、vs2019

方式一:不推荐

资源文件目录:

 

示例代码:

MainComponent.h

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"

//==============================================================================
class MainComponent : public Component,
    public Button::Listener  // 注意这里是public继承
{
public:
    //==============================================================================
    MainComponent();
    ~MainComponent();

    //==============================================================================
    void paint(Graphics&) override;
    void resized() override;

    // Button::Listener回调
    void buttonClicked(Button* button) override;

private:
    //==============================================================================
    ScopedPointer<DrawableButton> toggleButton;  // JUCE 5使用ScopedPointer
    ScopedPointer<Drawable> onImage;
    ScopedPointer<Drawable> offImage;
    bool isOn = false;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent)
};

MainComponent.cpp

#include "MainComponent.h"

//==============================================================================
MainComponent::MainComponent()
{


    // 获取当前可执行文件所在目录
    File exeDir = File::getSpecialLocation(File::currentApplicationFile).getParentDirectory();

    // 构建完整资源路径
    File resourcesDir = exeDir.getChildFile("Resources");
    File onFile = resourcesDir.getChildFile("on.png");
    File offFile = resourcesDir.getChildFile("off.png");

    // 显示当前路径信息(调试完成后可删除)
    AlertWindow::showMessageBoxAsync(AlertWindow::InfoIcon,
        "Debug Info",
        "Executable path: " + File::getSpecialLocation(File::currentApplicationFile).getFullPathName()
        + "\nResources path: " + resourcesDir.getFullPathName()
        + "\non.png exists: " + String(onFile.existsAsFile() ? "Yes" : "No")
        + "\noff.png exists: " + String(offFile.existsAsFile() ? "Yes" : "No"));

    // 检查文件是否存在(调试用)
    jassert(onFile.existsAsFile());
    jassert(offFile.existsAsFile());

    // 使用FileInputStream加载图片
    {
        FileInputStream onStream(onFile);
        Image onImageFile = ImageFileFormat::loadFrom(onStream);

        FileInputStream offStream(offFile);
        Image offImageFile = ImageFileFormat::loadFrom(offStream);

        // 创建Drawable对象
        onImage = new DrawableImage();
        offImage = new DrawableImage();
        static_cast<DrawableImage*>(onImage.get())->setImage(onImageFile);
        static_cast<DrawableImage*>(offImage.get())->setImage(offImageFile);
    }

    // 创建按钮(添加额外样式设置)
    toggleButton = new DrawableButton("PowerButton", DrawableButton::ImageAboveTextLabel);
    toggleButton->setImages(offImage);
    toggleButton->setColour(DrawableButton::backgroundColourId, Colours::transparentBlack);
    toggleButton->setColour(DrawableButton::backgroundOnColourId, Colours::transparentBlack);
    toggleButton->addListener(this);
    addAndMakeVisible(toggleButton);

    // 设置默认大小(根据图片尺寸自动调整)
    setSize(400, 300);
}

MainComponent::~MainComponent()
{
    toggleButton->removeListener(this);
}

//==============================================================================
void MainComponent::paint(Graphics& g)
{
    g.fillAll(Colours::darkgrey);  // 使用更直观的颜色设置
}

void MainComponent::resized()
{
    int buttonSize = 64;
    toggleButton->setBounds(0,0, buttonSize, buttonSize);
}

void MainComponent::buttonClicked(Button* button)
{
    if (button == toggleButton)
    {
        isOn = !isOn;

        // 切换图片(JUCE 5的设置方式)
        toggleButton->setImages(onImage->createCopy());
        toggleButton->setToggleState(isOn, dontSendNotification);

        // 根据状态设置不同图片
        if (isOn) {
            toggleButton->setImages(onImage);
        }
        else {
            toggleButton->setImages(offImage);
        }
    }
}

运行效果:

 

方式二:二进制资源嵌入方式

资源管理方面,使用二进制嵌入资源会更可靠,避免路径问题。此外,用户可能需要处理高DPI显示,确保图片在不同分辨率下清晰。

另外,用户可能没有处理图片加载失败的情况,增加错误处理会提升健壮性。还有,按钮的状态切换可能会有更多的视觉反馈,比如颜色变化或工具提示。代码结构方面,将路径处理和图片加载封装成函数可以提高可维护性。

1、使用juce打开A1.jucer工程

2、打开后是如下图所示的,然后在项目中创建一个名为 res 的资源文件夹

3、创建好之后,右键点击res文件夹,添加.png图片资源

图片资源的路径

4、添加好图片后,使用vs打开项目juce会自动生成BinaryData.h、BinaryData.cpp文件

5、打印图片大小:

 

6、使用图片资源:

MainComponent.h

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"

class MainComponent : public Component,
    public Button::Listener
{
public:
    MainComponent();
    ~MainComponent();

    void paint(Graphics&) override;
    void resized() override;
    void buttonClicked(Button* button) override;

private:
    //连接按钮
    juce::ScopedPointer<juce::DrawableButton> connectButton; 
    //图片资源
    juce::ScopedPointer<juce::DrawableImage> onImage;
    juce::ScopedPointer<juce::DrawableImage> offImage;
    juce::ScopedPointer<juce::DrawableImage> hoverImage;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent)
};

MainComponent.cpp

#include "MainComponent.h"


//==============================================================================
MainComponent::MainComponent()
{
    // 创建DrawableImage对象
    onImage = new juce::DrawableImage();
    offImage = new juce::DrawableImage();
    hoverImage = new juce::DrawableImage();
    // 加载二进制数据到Image对象
    juce::Image onImageData = juce::ImageFileFormat::loadFrom(BinaryData::on_png, BinaryData::on_pngSize);
    juce::Image offImageData = juce::ImageFileFormat::loadFrom(BinaryData::off_png, BinaryData::off_pngSize);
    juce::Image hoverImageData = juce::ImageFileFormat::loadFrom(BinaryData::hover_png, BinaryData::hover_pngSize);
    // 验证图像有效性
    if (!onImageData.isValid() || !offImageData.isValid())
    {
        juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::WarningIcon, TRANS("error"), TRANS("Failed to load the image asset!"));
        jassertfalse;
    }
    // 设置图像
    onImage->setImage(onImageData);
    offImage->setImage(offImageData);
    hoverImage->setImage(hoverImageData);

	// 添加并设置连接按钮
    connectButton = new juce::DrawableButton("connectButton", juce::DrawableButton::ImageRaw);
    connectButton->setClickingTogglesState(true);
    // 必须显式设置按钮文本
    connectButton->setButtonText(TRANS("connectButton"));
    connectButton->setImages(
        offImage,      // 未激活状态 - 正常显示
        hoverImage,    // 未激活状态 - 鼠标悬停
        onImage,       // 未激活状态 - 按下时 (新增!)
        nullptr,       // 未激活状态 - 禁用时
        onImage,       // 激活状态 - 正常显示 (修正!)
        hoverImage,    // 激活状态 - 鼠标悬停
        onImage,       // 激活状态 - 按下时
        nullptr        // 激活状态 - 禁用时
    );
    // 设置字体颜色
    connectButton->setColour(juce::DrawableButton::textColourId, juce::Colours::black);
    connectButton->setColour(juce::DrawableButton::textColourOnId, juce::Colours::white);
    connectButton->setColour(juce::DrawableButton::backgroundColourId, juce::Colours::transparentBlack);// 按钮背景颜色
    connectButton->setColour(juce::DrawableButton::backgroundOnColourId, juce::Colours::transparentBlack);// 按钮按下时背景颜色
    connectButton->addListener(this);// 注册按钮监听
	addAndMakeVisible(connectButton);

    setSize(400, 300);
}

MainComponent::~MainComponent()
{
    connectButton->removeListener(this);
}

void MainComponent::paint(Graphics& g)
{
    // 渐变色背景
    g.setGradientFill(ColourGradient(Colours::darkgrey.brighter(0.1f),getWidth() / 2.0f, getHeight() / 2.0f,Colours::darkgrey.darker(0.2f),-100.0f, -100.0f,true));
    g.fillRect(getLocalBounds());
}

// resized()函数
void MainComponent::resized()
{
    connectButton->setBounds(0,0,64,64);
}

void MainComponent::buttonClicked(Button* button)
{
	if (button == connectButton)
	{
        int ret = connectButton->getToggleState();
        if (ret)
        {
        }
        else
        {
        }
	}
}

运行效果:

 

posted @ 2025-04-11 10:45  [BORUTO]  阅读(15)  评论(0)    收藏  举报