JUCE类库String类详解

String字符串类的重要性无需多言。该类其实也是一种数据容器(char类型的数据容器),只不过由于比较特殊和重要,将其单列一节。JUCE类库的String类与C++标准库的string类的功能与使用基本一致,但又有差别。JUCE::String内部使用了引用计数技术,多了一批实用和方便的成员函数,而又不臃肿,使用时更加顺手和高效。

JUCE String与C++标准库std::string互相转换的语法为:

标准库std::string转换为JUCE::String:

std::string s;     	
String js (s.c_str());

JUCE::String转换为标准库std::string:

String js;
std::string s (js.toUTF8());

String类有一大批静态函数和成员函数,这些函数的命名非常清晰规范,顾名即可思义。常用的有:(略)

示例

double型秒数转换为“时:分:秒:毫秒”字符串:

/* 返回字符串常量的静态函数,将double型秒数(函数参数)转换为“时:分:秒:毫秒”:*/
static const String timeToTimecodeString (const double seconds) 
{
    // 首先对原始秒数进行绝对值转换
    const double absSecs = fabs (seconds);

    // 计算时分秒
    const int hours = (int) (absSecs / (60.0 * 60.0));
    const int mins  = ((int) (absSecs / 60.0)) % 60;
    const int secs  = ((int) absSecs) % 60;

    // 定义一个字符串对象
    String s;

    // 秒数为负数,则字符串最左侧先赋一个负号,而后继续追加文本...
    if (seconds < 0)  
        s = "-";

    // 将指定的字符(1参)重复添加到字符串s的开始处,直到总长度达到所指定的长度(2参)。
    s << String (hours).paddedLeft ('0', 2) << ":"
      << String (mins).paddedLeft ('0', 2) << ":"
      << String (secs).paddedLeft ('0', 2) << ":"

    /* 原始秒数乘1000,而后四舍五入取整,处理后模1000,余数为毫秒,保留三位数。左侧不足处补“0”。这一步的思路是处理秒数的小数部分。*/
      << String (roundToInt (absSecs * 1000) % 1000).paddedLeft ('0', 3);       

    return s;   // 执行完毕,传值返回字符串对象
}

嘀嗒值转换为节拍文本

/* 返回字符串常量的静态函数。本函数的1参为要转换的double型秒数,2参为小节的嘀嗒值,3参为每几分音符为1拍(拍号的分子),4参为每小节几拍(拍号的分母) */
static const String ppqToBarsBeatsString (double ppq,
                                          double lastBarPPQ, 
                                          int numerator,
                                          int denominator)
{
    // 若无拍号,则直接返回一个字符串
    if (numerator == 0 || denominator == 0)
        return "1|1|0";

    // 定义两个常量。一个是每小节的拍数,此处用于转换复合节拍。一个是double型的节拍数。
    const int ppqPerBar = (numerator * 4 / denominator);
    const double beats = (fmod (ppq, ppqPerBar) / ppqPerBar) * numerator;

    // 定义三个整型常量,分别是:小节数,拍数,嘀嗒值(按960算)
    const int bar = ((int) ppq) / ppqPerBar + 1;
    const int beat = ((int) beats) + 1;
    const int ticks = ((int) (fmod (beats, 1.0) * 960.0));

    // 定义一个字符串对象,数值和文本一并输出给该对象
    String s;
    s << bar << '|' << beat << '|' << ticks;

    return s;
}

根据参数对象的数据成员的值,更新标签文本。

void PluginProcessorEditor::displayPositionInfo (
                 const CurrentPositionInfo& pos) 
{
    // 参数给本类的数据成员赋值
    lastDisplayedPosition = pos;

    // 定义一个字符串对象,预先分配128个字节
    String displayText;
    displayText.preallocateBytes (128);

    // 字符串对象追加内容,最后显示的文本为:120拍,4/4 - 时:分:秒:毫 - 12|3|480
    displayText << String (pos.bpm, 2) << " bpm, "
                << pos.timeSigNumerator << '/' << pos.timeSigDenominator
                << "  -  " << timeToTimecodeString (pos.timeInSeconds)
                << "  -  " << ppqToBarsBeatsString (
                          pos.ppqPosition, pos.ppqPositionOfLastBarStart, 
                          pos.timeSigNumerator, pos.timeSigDenominator);

    // 继续追加内容。根据当前是否正在录音,追加对应的文本
    if (pos.isRecording)
        displayText << "  (recording)";

    else if (pos.isPlaying)
        displayText << "  (playing)";

    // 文本标签更新所显示的内容
    infoLabel.setText (displayText, false);
}