C++ Builder XE4 > 違い > this->ScaleBy(100 / s_curFactor, 100); と this->ScaleBy(100, s_curFactor * 100); > 前者では計算誤差が生じる


動作環境
C++ Builder XE4

関連

上記にて作業中、IDEのバグによる誤差の蓄積に気づいた。

今後、同じ問題に遭遇するかもしれないので、記事として切出す。

症状と実装

  • フォントサイズを変更可能なソフト
  • ScaleBy()を使う
  • フォントサイズ変更を繰返すことで誤差が蓄積される
    • TButtonの横幅が狭くなる
Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

enum {
    FONT_SMALL = 0,
    FONT_MEDIUM,
    FONT_LARGE,
    FONT_EXTRA_LARGE,
    FONT_HUGE,
};

static float s_curFactor = 1.0; // 拡大率
static int s_cntChangeSize = 0; // フォントサイズ変更回数

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::CMB_fontSizeChange(TObject *Sender)
{
    s_cntChangeSize += 1;
    Label1->Caption = IntToStr(s_cntChangeSize);

//-----------
    int preH = this->Height;
    int preW = this->Width;

    this->ScaleBy(100 / s_curFactor, 100); // 拡大率を使って拡大するため、一旦1.0の倍率に戻す
//  this->ScaleBy(100, s_curFactor * 100); // 拡大率を使って拡大するため、一旦1.0の倍率に戻す

    switch(CMB_fontSize->ItemIndex){
    case FONT_SMALL:
        s_curFactor = 1.00; // 結果を見て調整する
        break;
    case FONT_MEDIUM:
        s_curFactor = 1.20; // 結果を見て調整する
        break;
    case FONT_LARGE:
        s_curFactor = 1.40; // 結果を見て調整する
        break;
    case FONT_EXTRA_LARGE:
        s_curFactor = 1.60; // 結果を見て調整する
        break;
    case FONT_HUGE:
        s_curFactor = 1.80; // 結果を見て調整する
        break;
    }

    this->ScaleBy(100 * s_curFactor, 100);

    // 元の高さ、幅に戻すことで、パネルのコンポーネントのサイズだけを拡大できる
    // (結果として、TChartは小さくなる)
    this->Height = preH;
    this->Width = preW;
}
//---------------------------------------------------------------------------

再現方法

  • 1. フォントサイズをHugeにする
  • 2. フォントサイズをSmallにする
  • 3. 手順1に戻る (s_cntChangeSizeが16になるまで)

ButtonのBの文字が半分消えてしまう。

対策

対策を行うが、以下を検討した。

  • IDEのバージョンアップ時にも問題がないような対策

バージョン固有の不具合対応は、将来のIDEバージョンアップ時にはまる。
どのバージョンでも問題がない実装が望ましい。

下記の方法で対処できることを見つけた。

//  this->ScaleBy(100 / s_curFactor, 100); // 拡大率を使って拡大するため、一旦1.0の倍率に戻す
    this->ScaleBy(100, s_curFactor * 100); // 拡大率を使って拡大するため、一旦1.0の倍率に戻す

ButtonのBの文字表示に問題がなくなった。