見出し画像

Notes C API探訪: 数値をテキストにコンバートする

前回までの「Qt5再入門」15回シリーズでお届けしたコンバートシミュレーターダイアログで、Qt5のウィジェット開発機能を使ったGUIを構築してきました。このダイアログはあくまでUI、入出力の手段であって、本命は今回以降の「数値、日時とテキストとの相互コンバート」になります。今回は数値からテキストへのコンバートについて扱います。

前回の記事で紹介したソースコードに、以下の記述がありました。

// convertsimulatordialog.cppから抜粋

void ConvertSimulatorDialog::convertNumberToText() {
  nxpp::NumberToTextConverter converter;
  setIntlFormat(&converter);
  setNumberFormat(&converter);

  try {
    bool ok = false;
    double num = ui->numberToTextSrcLineEdit->text().toDouble(&ok);
    if (!ok) {
      consoleLog(tr("Unable to convert numbers to text."));  // throwもあり
      return;
    }
    nxpp::Lmbcs text = converter(&num);
    ui->numberToTextDestLineEdit->setText(fromLmbcsQ(text));
  }
  // Notesステータスがスローされたらそのエラーメッセージに変換して表示
  catch (nxpp::Status &status) {
    consoleLog(nxpp::qt::fromStatus(status.error()));
  }
  // それ以外の例外ならそのメッセージを表示
  catch (std::exception &ex) {
    std::string what(ex.what());
    consoleLog(QString::fromStdString(what));
  }
}

この中に、nxpp::NumberToTextConverter という、私が定義したクラスがあります。これは数値からテキストに変換するクラスで、 operator () を備えているので、「関数オブジェクト」として使用することができます。
まずは定義を見ていきます。

// nxpp/include/nxpp/nxpp_number.hpp
// ...

namespace nxpp {
// ...

class NumberToTextConverter
   : public NumberConverter
{
public:
 NumberToTextConverter() : NumberConverter() {}

 NumberToTextConverter(
     intl::SettingsPtr iPtr,
     NumberFormatPtr nPtr
     )
   : NumberConverter(iPtr, nPtr)
 {}

 Lmbcs operator () (NUMBER *pNum) const {
   char buffer[MAXALPHANUMBER] = "";
   WORD len = 0;
   Status status = ConvertFLOATToText(
         !intlSettingsPtr_ ? nullptr : intlSettingsPtr_->data(),
         !formatPtr_ ? nullptr : formatPtr_->data(),
         pNum,
         buffer,
         MAXALPHANUMBER,
         &len
         );
   if (!status) { throw status; }
   return Lmbcs(buffer, len);
 }
};

// ...
} // namespace nxpp
// ...

関数オブジェクトの「関数機能」実装がメインで、NUMBERポインタを受け取り、ConvertFLOATToText関数を呼び出して、数値をテキストに変換し、LMBCS文字列として返しています。

ConvertFLOATToText関数は、INTLFORMATとNFMTを受け入れることができるので、このオブジェクト関数のオブジェクト内に、設定があればそれらを使用し、なければヌルポインタでConvertFLOATToText関数を呼び出すようになっています。

さて、この関数オブジェクトクラスの継承元 NumberConverter はどうなっているのか見てみます。

// nxpp/include/nxpp/nxpp_number.hpp
// ...

namespace nxpp {
// ...

using NumberFormatPtr = std::shared_ptr<NumberFormat>;

class NumberConverter
   : public intl::ConverterBase<NumberFormat>
{
public:
 NumberConverter() : intl::ConverterBase<NumberFormat>() {}

 NumberConverter(
     intl::SettingsPtr iPtr,
     NumberFormatPtr nPtr
     )
   : intl::ConverterBase<NumberFormat>(iPtr, nPtr)
 {}
};

// ...
} // namespace nxpp
// ...

コード中の NumberFormat は、以前紹介したNFMT構造体のラップクラスです。
このクラスは、さらに intl::ConverterBase テンプレートクラスを継承元にしていますので、これも定義を見てみます。

// nxpp/include/nxpp/nxpp_intl.hpp
// ...

namespace nxpp::intl {
// ...

using SettingsPtr = std::shared_ptr<Settings>;

template <class T>
class ConverterBase
{
protected:
 SettingsPtr intlSettingsPtr_;
 std::shared_ptr<T> formatPtr_;

public:
 ConverterBase() : intlSettingsPtr_() , formatPtr_() {}

 ConverterBase(
     intl::SettingsPtr iPtr,
     std::shared_ptr<T> tPtr
     )
   : intlSettingsPtr_(iPtr)
   , formatPtr_(tPtr)
 {}

 void setIntlSettings(SettingsPtr sPtr) {
   intlSettingsPtr_ = sPtr;
 }

 void setFormat(std::shared_ptr<T> ptr) {
   formatPtr_ = ptr;
 }
};

// ...
} // namespace nxpp::intl
// ...

メンバ変数として、INTLFORMATをラップしたクラスのスマートポインタと、NFMTまたはTFMTをラップしたクラスのスマートポインタを有します。これらは、デフォルトではヌルポインタとなっています。API関数 Convert***ToText、またはConvertTextTo***では、ヌルポインタは「設定なし」と見立てて処理できるので、その仕様に合わせています。
フォーマットを調整して適用したい場合、それぞれのスマートポインタを受け入れられるようにもなっています。

まとめ

今回は、ご紹介予定の関数オブジェクトクラスのうちから1つだけ紹介しました。

1. 数値 → テキスト (今回紹介済み)
2. テキスト → 数値
3. 日時 → テキスト
4. テキスト → 日時

残りの3つも、原則今回のクラスの設計と同じようなスタイルを踏襲しています。予定としては、次回に2番を、以降に3と4をご紹介する予定です。
実は、3と4は日時が絡みますが、Qtの日時ウィジェットからNotes C APIのTIMEDATE構造体に変換したり、その逆の変換もしなくてはいけません。API自体は「Notes C API探訪: TIME(データ型)」の回でご紹介しているので、そのラップコードも一緒にご紹介していきたいと思います。

この記事が気に入ったらサポートをしてみませんか?