[C++] 119 FLTK : 名前を付けて保存 Fl_File_Chooser

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

色表示履歴をcsvファイルに保存する際、自分でファイル名を付けることもできるようにしました。Fl_File_ChooserをCREATEタイプで使用します。

OKボタン以外をクリックすると異常終了するので、まだ手を入れる必要があります。

static Fl_Menu_Item	items[] = {
        { "★", 0, 0, 0, FL_SUBMENU },
        { "読込", 0, loadFavList, 0, 0 },
        { "保存", 0, 0, 0, FL_SUBMENU },
        { "名前を付けて保存", 0, saveFavListManu, 0, 0 },
        { "自動保存", 0, saveFavListAuto, 0, 0 },
        { 0 },
        { "消去", 0, deleteFavList, 0, 0 },
        { 0 },
        { "履歴", 0, 0, 0, FL_SUBMENU },
        { "消去", 0, deleteHistory, 0, 0 },
        { 0 },        
    #ifdef DEV
        { "開発", 0, 0, 0, FL_SUBMENU },
        { "開発モード", 0, showSubWindow, 0, 0 },
        { 0 }
    #else
    #endif
    };
    
    Fl_Sys_Menu_Bar *menubar;
    menubar = new Fl_Sys_Menu_Bar(0, 0, 60, 20);
    menubar->box(FL_FLAT_BOX);
    menubar->menu(items);
--------------------------------------------------
#include <csvProcessChar.h>
#include <filesystem>

namespace fs = std::filesystem;
using std::cout; using std::endl;
using std::string; using std::to_string;

vector<vector<const char*>> selectColorList;

void saveFavListManu(Fl_Widget*, void*){
    cout << "saveFavListManu" << endl;

    homedir = getenv("HOME");
    cout << "homedir " << homedir << endl;

    string cs = "/ColorSample";
    string appdir = string(homedir) + cs;

    if (!fs::exists(appdir)){
        fs::create_directory(appdir);
    }

    Fl_File_Chooser chooser(".",      // directory
                            "*",      // filter
                            Fl_File_Chooser::CREATE, // chooser type
                            "File_Chooser");   // title
    chooser.show();

    while(chooser.shown())
        { Fl::wait(); }

    const char* filePath = chooser.value();

    if (filePath == nullptr){
        return;
    }

    csvProcessChar::make(filePath,selectColorList);
}

[C++] 118 FLTK : 色表示履歴をCSVファイルに保存

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

色表示履歴(2次元vector)をホームディレクトリ直下のアプリ用ディレクトリにCSVファイルとして保存できるようにしました。

前々回記事で作成した静的ライブラリのconst char*版 csvProcessChar.aを使用しています。今のところappファイルのサイズは1.8MBです。

ファイル名は仮にtest.csvとしていますが、2208011200_FavList.csvのように日時を付加したファイル名にしたいところです。

さすがに秒数まで加えると長すぎるので付けません。ただ同じ分内で複数作成した時に上書きにならないよう工夫が必要になります。

static Fl_Menu_Item	items[] = {
        { "★", 0, 0, 0, FL_SUBMENU },
        { "読込", 0, loadFavList, 0, 0 },
        { "保存", 0, saveFavList, 0, 0 },
        { "消去", 0, deleteFavList, 0, 0 },
        { 0 },
        { "履歴", 0, 0, 0, FL_SUBMENU },
        { "消去", 0, deleteHistory, 0, 0 },
        { 0 },        
    #ifdef DEV
        { "開発", 0, 0, 0, FL_SUBMENU },
        { "開発モード", 0, showSubWindow, 0, 0 },
        { 0 }
    #else
    #endif
    };
    
Fl_Sys_Menu_Bar *menubar;
    menubar = new Fl_Sys_Menu_Bar(0, 0, 60, 20);
    menubar->box(FL_FLAT_BOX);
    menubar->menu(items);
--------------------------------------------------
#include <csvProcessChar.h>
#include <filesystem>

namespace fs = std::filesystem;
using std::cout; using std::endl;
using std::string; using std::to_string;

vector<vector<const char*>> selectColorList;

void saveFavList(Fl_Widget*, void*){
    cout << "saveFavList" << endl;

    homedir = getenv("HOME");
    cout << "homedir " << homedir << endl;

    string cs = "/ColorSample";
    string appdir = string(homedir) + cs;

    if (!fs::exists(appdir)){
        fs::create_directory(appdir);
    }

    string path = appdir + "/test.csv";
    csvProcessChar::make(path,selectColorList);
}

[C++] 117 ホームディレクトリの取得、ディレクトリの存在確認・作成

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

ホームディレクトリ直下に任意のディレクトリを作成するコードを書きました。直下にColorSampleディレクトリがなければ、これを作成します。

filesystemヘッダはC++17以降で使えます。

#include <iostream>
#include <vector>
#include <filesystem>

namespace fs = std::filesystem;

using std::string; using std::vector;
using std::cout; using std::endl;

int main () {
    const char *homedir;

    homedir = getenv("HOME");
    cout << "homedir " << homedir << endl;

    string cs = "/ColorSample";
    string appdir = string(homedir) + cs;

    if (!fs::exists(appdir)){
        fs::create_directory(appdir);
    }
}

[C++] 116 2次元vectorからCSVファイルを作成・読込する動的・静的ライブラリを作る

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

前回、前々回の成果を合わせてCSVファイルを作成・読み込みする動的・静的ライブラリを作成しました。

#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <sstream>

using std::string; using std::vector;
using std::cout; using std::endl;

class csvProcess {
public:
static void make(string path, vector<vector<string>> vec2D);
static vector<vector<string>> load(string path);
};
#include <csvProcess.h>

vector<vector<string>> csvProcess::load(string path) {
    string eles;
    string ele;
    vector<vector<string>> vec2D;

    // csvファイル指定
    std::ifstream file(path);

    while (getline(file, eles)) {
        vector<string> vec;  
        std::istringstream line(eles);

        while (getline(line, ele, ',')) {
            vec.push_back(ele);
        }
        
        vec2D.push_back(vec);
    }

    int line_num = 1;
    for (const auto &items : vec2D) {
        for (const auto &item : items) {
            cout << line_num << " " << item << endl;
        }
        line_num += 1;
    }

    return vec2D;
}

void csvProcess::make(string path, vector<vector<string>> vec2D) {
    // ファイル名指定
    std::ofstream file(path);

    // データ取り込み
    for (const auto &data : vec2D) {
        int num = 0;
        for (const auto &ele : data){
            int len = data.size();
            if (num < len -1){
                file << ele << ",";
            } else {
                file << ele << "\n";
            }
            num += 1;
        }
    }

    // ファイル出力完了
    file.close();
}
# 動的ライブラリ作成コマンド
clang++ -dynamiclib -o csvProcess.dylib csvProcess.cpp \
-I/code/cpp/mylib/include -std=c++17

# 静的ライブラリ作成コマンド
clang++ -std=c++17 -I/code/cpp/mylib/include -g -o csvProcess.o \
-c csvProcess.cpp

ar r csvProcess.a csvProcess.o
#include <csvProcess.h>

int main () {
    vector<vector<string>> vec2D;

    // vector作成
    vector<string> data1 = {"cadetblue","-","0x5F9EA0"};
    vector<string> data2 = {"若竹色","わかたけいろ","0x68BE8D"};
    vec2D.push_back(data1);
    vec2D.push_back(data2);

    string path = "test.csv";

    csvProcess::make(path, vec2D);
}

[C++] 115 CSVファイルから2次元vectorへ変換

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

[C++]114の逆変換です。こちらは少しだけ手間取りました。

ところでstd::stringを使う時は<string>をインクルードしがちですが、<iostream>だけでOKです。

#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <sstream>

using std::string; using std::vector;
using std::cout; using std::endl;

int main () {
    string eles;
    string ele;
    vector<vector<string>> vec2D;
  
    // csvファイル指定
    std::ifstream file("test.csv");

    while (getline(file, eles)) {
        vector<string> vec;  
        std::istringstream line(eles);

        while (getline(line, ele, ',')) {
            vec.push_back(ele);
        }
        
        vec2D.push_back(vec);
    }

    // vec2Dの内容確認
    int line_num = 1;
    for (const auto &items : vec2D) {
        for (const auto &item : items) {
            cout << line_num << " " << item << endl;
        }
        line_num += 1;
    }
}
--------------------------------------------------
出力例
--------------------------------------------------
1 cadetblue
1 -
1 0x5F9EA0
2 若竹色
2 わかたけいろ
2 0x68BE8D

[C++] 114 2次元vectorからCSVファイル作成

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

2次元vectorからCSVファイルを作成しました。Pythonより簡単で拍子抜けです。

#include <iostream>
#include <fstream>
#include <vector>
#include <utility>

using std::string; using std::vector;

int main()
{
    // ファイル名指定
    std::ofstream file("test.csv");
    vector<vector<string>> vec;

    // vector作成
    vector<string> data1 = {"cadetblue","-","0x5F9EA0"};
    vector<string> data2 = {"若竹色","わかたけいろ","0x68BE8D"};
    vec.push_back(data1);
    vec.push_back(data2);

    // データ取り込み
    for (auto &&data : vec) {
        file << data[0] << ',' << data[1] << ',' << data[2] << '\n';
    }

    // ファイル出力完了
    file.close();
}

[C++] 113 FLTK : メニュー追加 Fl_Menu_Item

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

ここ最近、課題が増えてきて整理しているところです。

カラーアプリについてはWindows11への移植に着手したものの、Explorerのファイラーとしての物足りなさを改めて実感し、秀丸ファイラーClassicを使い始めました。

Macの方もCommander Oneというシェアウェアを導入しました。どちらも複数タブ表示機能があります。秀丸ファイラーClassicにこの機能が搭載されたのが2010年ですから、そんなに新しいものでもないようです。

ここで新たな課題として自分仕様のファイラーを作ってみようと思い、Mac版の言語をObjective-C++、Swift、あるいはC++にするか考えを巡らせています。

一方、カラーアプリで追加したい機能もあり、まずこちらに優先して取り組みます。

繰り返し使う色のカラーコードをファイルで保管するために履歴関連機能を強化します。履歴の保存、読込機能になります。エクスポート、インポート機能のようなものです。ファイルタイプはCSV、JSON、XMLあたりでしょうか。

とりあえずFl_Menu_Itemを書き換えました。開発モードは別メニューに分離させています。

static Fl_Menu_Item	items[] = {
        { "履歴", 0, 0, 0, FL_SUBMENU },
        { "読込", 0, loadHistory, 0, 0 },
        { "保存", 0, saveHistory, 0, 0 },
        { "消去", 0, deleteHistory, 0, 0 },
        { 0 },
#ifdef DEV
        { "開発", 0, 0, 0, FL_SUBMENU },
        { "開発モード", 0, showSubWindow, 0, 0 },
        { 0 }
#else
#endif
};
    
Fl_Sys_Menu_Bar *menubar;
menubar = new Fl_Sys_Menu_Bar(0, 0, 60, 20);
menubar->box(FL_FLAT_BOX);
menubar->menu(items);

[C++] 112 FLTK : 条件付きコンパイル #ifdef

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

通常モードと開発モードによってGUIの内容を変えるため条件付きコンパイルを設定しました。

#ifdefは様々な公開ソースコードで目にする機会が多く、前から使ってみたいと思っていました。共同開発ではメンテナンス性に影響するとのことであまり好まれない現場もあるようです。

これまでFl_Inputなどに隠しコマンドを設定してウィンドウを出現させたりしていましたが、コードの可読性が損なわれるので控えるようにします。

#ifdef DEV
    static Fl_Menu_Item	items[] = {
    { "設定", 0, 0, 0, FL_SUBMENU },
    { "履歴消去", 0, deleteHistory, 0, 0 },
    { "開発モード", 0, showSubWindow, 0, 0 },
    { 0 },
    { 0 }
    };
#else
    static Fl_Menu_Item	items[] = {
    { "設定", 0, 0, 0, FL_SUBMENU },
    { "履歴消去", 0, deleteHistory, 0, 0 },
    { 0 },
    { 0 }
    };
#endif
--------------------------------------------------
#ifdef DEV
    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();
#else
#endif
# オプション設定 -D+マクロ名
CPPFLAGS = -std=c++17 -DDEV

[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.”というタイトルのメールが届いたら公証手続きは完了。アプリへの紐付けを行う。ステープラーで留めるとも言います。