[C++] 111 FLTK:子ウィジェットの座標 その2 モーダルダイアログ

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

“[C++] 31 FLTK:子ウィジェットの座標”の続編です。

親ウィンドウを動かした後に生成したモーダルダイアログが親ウィンドウの相対位置になっていない問題を解決することができました。

親ウィンドウのx_root, y_rootを取得すれば済む話でした。これはすぐに解らないといけない、と反省です。

Fl_Window *window;
modalDialog *dlg;

const char* msg = "該当する色はありません";
dlg = new modalDialog(400, 200, "Attention", msg);
dlg->hotspot(window);

int x_win = window->x_root();
int y_win = window->y_root();
cout<<"x_win "<< x_win <<" y_win "<< y_win <<endl;

dlg->resize(x_win+205, y_win+165,250,150);
dlg->set_modal();
dlg->show();

[C++] 110 FLTKアプリのApple公証 その2

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

“[C++] 08 FLTKアプリのApple公証”の続編です。前編を書いたのは今年3月ですから4ヶ月でC++関連記事を100書いたことになります。短編ばかりとは言え、書きも書いたりといったところです。

製作したアプリを配布するにはApple公証を取得する必要があります。新しいアプリの手続きをするのは昨年12月以来で大分忘れていました。再度この記事にまとめておきます。

Apple公証手続き方法

1.アプリ用パスワードを取得する。公式サイトの”How to generate an app-specific password”に従って作成する。
取得時のサイトの案内がとても分かりにくくてとまどいます。登録したいパスワードの入力を促している様にしか見えないので要注意です。
最初に入力するのは任意の名称です。パスワード自体はAppleが発行します。UIにはこだわるのにローカライズはいい加減なところが散見されます。

公式サイト

2.以下コマンドでパスワードを登録しておくと今後直に入力しなくて済みます。AC_PASSWORDは任意の登録パスワード名です。

xcrun altool --store-password-in-keychain-item "AC_PASSWORD" -u "開発者メールアドレス" -p アプリ用パスワード

3.アプリに署名し、アプリ用パスワードを使ってzipファイルを提出する。
下図の様なエラーになった場合は以下サイトにアクセスして内容に同意する。
https://appstoreconnect.apple.com/

4.”Your Mac software was successfully notarized.”というタイトルのメールが届いたら公証手続きは完了。アプリへの紐付けを行う。ステープラーで留めるとも言います。

[C++]109 FLTK : 静的ライブラリのリンク

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

配布したアプリの導入時にユーザーの方がHomebrewからFLTKをインストールするなどの作業をしなくても済む様、静的ライブラリとリンクさせました。

自製ライブラリも動的ライブラリから静的ライブラリに変更しています。静的ライブラリはビルド時にアプリ内に取り込まれます。

手順

1.コンパイルコマンドをチェックし、最低限必要なライブラリだけに絞り込む。

2.各ライブラリの静的ライブラリ(拡張子 a)を作成する。

# オブジェクトファイルを作成
clang++ -std=c++17 -I/code/cpp/mylib/include -g -o /code/cpp/mylib/lib/Split.o \
-c /code/cpp/mylib/src/Split.cpp

# 静的ライブラリを作成
ar r /code/cpp/mylib/lib/Split.a /code/cpp/mylib/lib/Split.o

3.Makefileでアプリをビルドする。

動的ライブラリの時は612KBだったアプリサイズが1.8MBになりました。単純な合計サイズより小さいのは、必要なクラスや関数だけ取り出しているためでしょう。

なおJava版は45.6MBになりますから、C++版の方がストレージへの負担はかなり小さくそして爆速です。起動が速すぎてちょっとビックリするレベルなので、可能なら少し遅めにしようかとも思っています。

[C++]108 FLTK : 表示色カウンターと履歴消去機能追加 

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

表示色が履歴の何番目かを示したカウンターと履歴消去機能を追加しました。カウンターのFl_Inputを右揃えにできず、やむなく左揃えで妥協しました。

これで搭載したい機能は全て実装完了です。後は配布に耐えうる堅牢性への強化でしょうか。

// counter
counter = new Fl_Input(625, 89, 27, 10,"");
counter->box(FL_FLAT_BOX);
counter->align(FL_ALIGN_INSIDE|FL_ALIGN_RIGHT); // 設定は効かず
counter->color(fl_rgb_color(238,238,238));
counter->textsize(10);

// 色表示関数内
string count = to_string(color_index) + "/" + to_string(selectColorList.size());
counter->value("");
counter->value(count.c_str());

[C++]107 FLTK : 表示色の履歴管理および順逆送り new演算子

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

手掛けてみたら予想通りのややこしさでしたが、運良くすんなり書けました。

C/C++ユーザーの方々には釈迦に説法ですが、変数やポインタのvectorを無処理で作成し履歴データとして蓄積しても勝手に上書きされるので失敗します。

new演算子でメモリを確保し、そこにデータを入れてからvectorを作成します。

確保したメモリをdelete演算子でどのようにどのタイミングで解放するのか、についてはこれから考えます。

vector<vector<const char*>> selectColorList;
const char *name_c, *roma_c, *code_c;
int color_index;

void selectColorListMake(const char* name, const char* roma, const char* code){
    color_index = selectColorList.size();

    vector<const char*> selectColor = {name, roma, code};
    selectColorList.push_back(selectColor);
    color_index += 1;
}

void prevColor(Fl_Widget*, void*){
    if (!(color_index < 2)){
        vector<const char*> prev_color = selectColorList[color_index -1 -1];
        name_c = prev_color[0];
        roma_c = prev_color[1];
        code_c = prev_color[2];
        cout << "name:" << name_c;
        cout << " roma:" << roma_c;
        cout << " code:" << code_c;
        color_index -= 1;
        cout << " index:" << (to_string(color_index)).c_str() << endl;;

        name_input->value("");
        name_input->insert(name_c);
        roma_input->value("");
        roma_input->insert(roma_c);
        code_input->value("");
        code_input->insert(code_c);

        output_line->insert(name_c);
        output_line->insert(" ");

        showColor();
    } else {
        cout << "記録はありません" << endl;
    }
}

void nextColor(Fl_Widget*, void*){
    if (!(color_index >= selectColorList.size())){
        vector<const char*> next_color = selectColorList[color_index -1 + 1];
        name_c = next_color[0];
        roma_c = next_color[1];
        code_c = next_color[2];
        cout << "name:" << name_c;
        cout << " roma:" << roma_c;
        cout << " code:" << code_c;
        color_index += 1;
        cout << " index:" << (to_string(color_index)).c_str() << endl;

        name_input->value("");
        name_input->insert(name_c);
        roma_input->value("");
        roma_input->insert(roma_c);
        code_input->value("");
        code_input->insert(code_c);

        output_line->insert(name_c);
        output_line->insert(" ");

        showColor();
    } else {
        cout << "記録はありません" << endl;
    }
}

色表示する関数内
// selectColor追加
const char* name_c2 = name_input->value();
char* name_c3 = new char[strlen(name_c2) + 1];
strcpy(name_c3, name_c2);

const char* roma_c2 = roma_input->value();
char* roma_c3 = new char[strlen(roma_c2) + 1];
strcpy(roma_c3, roma_c2);

const char* code_c2 = code_input->value();
char* code_c3 = new char[strlen(code_c2) + 1];
strcpy(code_c3, code_c2);

selectColorListMake(name_c3, roma_c3, code_c3);

[C++]105 FLTK : クリアボタンの配置 value関数

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

Window右側上下欄のクリアボタンを配置しました。Fl_Inputなどのvalue関数を使います。

開発は佳境に入っていて残すは表示色の記録および順送り、逆送りになります。

せっかくここまで作ったのですから、どこか国内向けの配布サイトに登録しようかと思っています。Microsoft StoreのJava版はスキル維持のためそのまま残すつもりです。

// C1ボタン
void clearUpper(Fl_Widget*, void*){
    name_input->value("");
    roma_input->value("");
    code_input->value("");
    location_input->value("");
}

// C2ボタン
void clearLower(Fl_Widget*, void*){
    output_line->value("");
    output_line2->value("");
}

[C++]104 FLTK : 正規表現におけるトラブル regex_search バイト列調査

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

appファイルではregex_searchを使ったひらがな抽出がうまくできないため、バイト列として何が抽出されているのか調べました。

その結果、常に2バイトのデータが返ってきていることが分かりました。本来は3バイト×ひらがな文字数のはずです。実行ファイルでは何の問題もないのに不思議な現象です。

これは仕様の問題にも思えますので、深入りしない方が良さそうです。ひらがな検索は保留としてローマ字検索に方向転換します。

// stringのバイト列への変換
void binary_convert(string str){
	for (int i = 0; i < str.length(); ++i) {
		bitset<8> bs(str[i]);
        string bs_str = bs.to_string();
		cout << str << " " << i+1 << "番目 " << bs << endl;

        output_line2->insert(bs_str.c_str());
        output_line2->insert("\n");
	}
	cout << "end"<< endl;
}

[C++]103 FLTK : 開発モードの設定 Fl_Sys_Menu_Bar

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

前回記事のFL_Window 2窓設定を開発モードとしてMacOSのシステムメニューから選択できるようにしました。配置していたトグルボタンを削除し、普段は通常モードとして使用します。

開発モードを選択する度にトグルボタンの様に表示/非表示が切り替わります。

Fl_Window *window2;
int mode = 0; // 0:通常モード, 1:開発モード

int main(int argc, char **argv) {

    static Fl_Menu_Item	items[] = {
    { "設定", 0, 0, 0, FL_SUBMENU },
    { "開発モード", 0, showSubWindow, 0, 0 },
    { 0 },
    { 0 }
    };
    Fl_Sys_Menu_Bar *menubar;
    menubar = new Fl_Sys_Menu_Bar(0, 0, 60, 20);
    menubar->box(FL_FLAT_BOX);
    menubar->menu(items);

    Fl_Window *window = new Fl_Window(50,50,660,480,"Color Sample");
    window->color(fl_rgb_color(238,238,238));

    <中略>
    
    window->end();
    window->show(argc, argv);
    
    // サブWindow
    window2 = new Fl_Window(750,50,360,480,"出力用");
    window2->color(fl_rgb_color(238,238,238));

    // output
    output_line2 = new Fl_Multiline_Output(0,0,360,480,"");
    output_line2->textsize(12);

    window2->end();

    return Fl::run();
}
extern Fl_Window *window2;
extern int mode;

void showSubWindow(Fl_Widget*, void*){
    if (mode == 1){
        mode = 0;
    } else {
        mode = 1;
    }

    if (mode == 1){
        window2->show();
    } else {
        window2->hide();
    }
}

[C++]102 FLTK : Fl_Windowの複数表示

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, NO IDE]

コンソールが表示される実行ファイルとappファイルで挙動が異なることが多いため、appファイルで出力を確認できる2窓の開発用アプリを用意しました。

Name欄から取得した文字列からひらがなを抽出してGUI内位置検索したものの、結果を表示させても該当なしになる現象を動画に収めています。右Windowから分かるように抽出したひらがなは文字化けしています。

Fl_Window *window2;
Fl_Toggle_Button *tgl_btn;

int main(int argc, char **argv) {

    Fl_Window *window = new Fl_Window(50,50,660,480,"Color Sample");
    window->color(fl_rgb_color(238,238,238));

    <中略>

    // サブWindow表示切り替え用トグルボタン
    tgl_btn = new Fl_Toggle_Button(602,227,50,15,"W表示");
    tgl_btn->labelsize(12);
    tgl_btn->callback(showSubWindow);

    window->end();
    window->show(argc, argv);
    
    // サブWindow
    window2 = new Fl_Window(750,50,360,480,"出力用");
    window2->color(fl_rgb_color(238,238,238));

    // output
    output_line2 = new Fl_Multiline_Output(0,0,360,480,"");
    output_line2->textsize(12);

    window2->end();
    window2->show(argc, argv);

    return Fl::run();
}
extern Fl_Window *window2;
extern Fl_Toggle_Button *tgl_btn;

void showSubWindow(Fl_Widget*, void*){
    int onoff_btn = tgl_btn->value();
    
    if (onoff_btn == 1){
        window2->hide();
    } else {
        window2->show();
    }
}