スポンサーリンク

ICUライブラリ+win32apiでutf16を一文字ずつ表示

ICUライブラリで文字を一文字ずつ切り出したい。しかし切り出した結果をコンソール出力するのはもろもろの事情で難しく、ファイル出力は確認がめんどくさいのでウィンドウに描画する。

#include <windows.h>

#include <unicode/ucnv.h>
#include <unicode/brkiter.h>

// 要リンク
#pragma comment(lib, "icuuc.lib")

// 以下のdllを要求される
// icudt69.dll
// icuuc69.dll

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
WCHAR szClassName[] = L"MY_ICU_TEST";  //ウィンドウクラス

LPCWSTR fontname = L"MS P ゴシック";

HFONT hFont1;

void WinPaint(HWND hWnd) {

  // 元の文字列の定義
  std::u16string u16s = u"aあغ山👨‍👧經经";

  /////////////////////////////
  // ICUの設定

  icu::UnicodeString usr(u16s.c_str());

  UErrorCode err;
  icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
    icu::Locale::getDefault(),err);
  bi->setText(usr);

  ////////////////////////////
  //フォトの設定
  HDC hdc;
  PAINTSTRUCT ps;
  hdc = BeginPaint(hWnd, &ps);
  SetTextColor(hdc, RGB(0, 0, 0));  //文字の色を設定
  SetBkColor(hdc, RGB(230, 230, 230));  //文字の背景色を設定
  HFONT backup = (HFONT)SelectObject(hdc, hFont1);  //フォントを適応
  TEXTMETRIC tm;
  GetTextMetrics(hdc, &tm);
  int TH = 10;

//////////////////////////// //文字を一文字(書記素)ずつ表示
int32_t current = bi->first(); while (current != icu::BreakIterator::DONE) { // 文字の長さを知る必要があるので、 // 「現在の文字の位置」と「前の文字の位置」が必要 int32_t prev = current; current = bi->next(); if (current == UBRK_DONE) { break; } int32_t count = current - prev;//文字の長さ //win32api のWCHARはutf16なのでただキャストするだけで変換できる TextOutW(hdc, 10, TH, (WCHAR*)(&u16s.data()[prev]), count);//文字を書く // こっちでもいい substr(現在位置,切り取る長さ) // std::u16string sub = u16s.substr(prev, count); // TextOutW(hdc, 10, TH, (WCHAR*)sub.data(), count);//文字を書く //改行 TH += tm.tmHeight+5; } SelectObject(hdc, backup); EndPaint(hWnd, &ps); }
////////////////////////////////////
////////////////////////////////////
// 表示用
////////////////////////////////////
////////////////////////////////////


int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) {
  MSG msg;
  BOOL bRet;
  WNDCLASSEX wc;
  HWND hWnd;
  ATOM atom;

  wc.cbSize = sizeof(WNDCLASSEX);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hCurInst;
  wc.hIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
  wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  wc.lpszMenuName = NULL;
  wc.lpszClassName = (LPCWSTR)szClassName;
  wc.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);

  if ((atom = RegisterClassEx(&wc)) == 0)return FALSE;

  hWnd = CreateWindow(
    MAKEINTATOM(atom), 
    L"icu test", 
    WS_OVERLAPPEDWINDOW, 
    CW_USEDEFAULT, CW_USEDEFAULT, 
    200, 500, // ウィンドウのサイズ
    NULL, NULL, hCurInst, NULL);

  if (!hWnd)return FALSE;

  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
    if (bRet == -1) {
      break;
    }
    else {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
  switch (msg) {
  case WM_CREATE:
    //Step1  フォント作成
    hFont1 = CreateFont(
      50, 0, //高さ, 幅
      0, 0, FW_BOLD,
      FALSE, FALSE, FALSE,
      SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
      CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
      VARIABLE_PITCH | FF_ROMAN, fontname);
    break;
  case WM_PAINT:
    WinPaint(hWnd);
    break;
  case WM_DESTROY:
    DeleteObject(hFont1);   //Step4. HFONTオブジェクトを破棄
    PostQuitMessage(0);
    break;
  default:
    return (DefWindowProc(hWnd, msg, wp, lp));
  }
  return 0;
}

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: