[C++] 88 FLTK : Fl_Tabsのインデックス値取得

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

Fl_Tabsのインデックス値を取得し、押下したカラーボタンの内容を3次元配列データから取り出すようにしました。

Tabのインデックス値取得はfor文内で変数に代入する方法ではうまくいかず、関数の戻り値にするとあっさり出来ました。

ようやく次の段階に移ることができます。選択した色の表示、カラーコードの変換などです。

extern Fl_Tabs *tabs;
extern string colorList[3][140];
extern string colorList2[4][3][120];
extern vector<string> tab_names;

int getIndex(vector<string> &input, string searched) {
    for (int i = 0; i < input.size(); i++) {
        if (input[i] == searched) {
            return i;
        }
    }
    return -1;
}

void getColor(Fl_Widget*, long num){
    cout << "num " << num << endl;

    Fl_Widget * tab = tabs->value();
    const char* lbl = tab->label();
    cout << "lbl " << lbl << endl;
    string lbl_str = (string)lbl;

    int tab_num = getIndex(tab_names,lbl_str);
    cout << "tab_num " << tab_num << endl;

    if (tab_num == 0){
        string* name = &(colorList[0][num]);
        const char* name_c = name->c_str();
        name_input->value("");
        name_input->insert(name_c);

        const char* romaji_c = "-";
        romaji_input->value("");
        romaji_input->insert(romaji_c);

        string* color = &(colorList[2][num]);
        const char* color_c = color->c_str();
        code_input->value("");
        code_input->insert(color_c);

    } else {
        string* name = &(colorList2[tab_num-1][0][num]);
        const char* name_c = name->c_str();
        name_input->value("");
        name_input->insert(name_c);

        string* romaji = &(colorList2[tab_num-1][1][num]);
        const char* romaji_c = romaji->c_str();
        romaji_input->value("");
        romaji_input->insert(romaji_c);

        string* color = &(colorList2[tab_num-1][2][num]);
        const char* color_c = color->c_str();
        code_input->value("");
        code_input->insert(color_c);
    }
}

[C++] 87 FLTK : 長整数型を引数とするcallback関数

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

for文で一気に作成するButtonのcallback関数の書き方で難航しました。左側Tab内のButtonを押して、色名やカラーコードなどその内容を右上のFl_inputに表示します。

Fl_Callback1(Fl_Widget *, long)という長整数型データを第2引数とするcallback関数を使うことで解決しました。第2引数としてButtonのインデックス(通し番号)を設定しています。

今回は有りもので何とかなりましたが、Fl_Callbackを継承すれば好きなデータ型で独自のクラスを作れるでしょう。

Java(Swing)の場合はfor文の中でActionListenerを使えたものの、さすがにFLTKではcallback関数の定義をfor文内に埋め込みできず、加えてButtonのラベルをうまく取得できなくてさすがに詰んだのではないかと一時は諦めかけました。

最大の難関をクリアできたので、後は何とかなると思います。

void getColor(Fl_Widget*, long num){
    cout << "num " << num << endl;

    Fl_Widget* tab = tabs->value(); // 有効なタブのポインタ
    const char* lbl = tab->label(); // タブのラベル
    cout << "lbl " << lbl << endl;
    string lbl_str = (string)lbl;

    if (lbl_str == tab_names[0]){
        string* color_name = &(colorList[0][num]);
        const char* color_name_p = color_name->c_str();
        name_input->insert(color_name_p);
    } 
}

<中略>

button->callback(getColor,(long)num);

[C++] 86 FLTK : カラーアプリ移植 各種ウィジェット配置

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

カラーアプリの右側に各種ウィジェットを配置しました。

Java版であまり使わなかったアルファ値、色調整機能、登録機能、メモ欄を削除し、色コードから色名やアプリ内位置を検索する機能を追加します。

ここまでの内容を1ファイル200行程度で書けており、超初心者だったSwingでの作成時に比べて大分要領が良くなっています。

当時はGridBagLayoutに相当悩まされました。ウィンドウサイズ固定であれば座標で位置決めするのが結局一番速いように思いますね。

[C++] 85 FLTK : カラーアプリ移植 Fl_Button labelcolor

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

ラベルを読みやすくするため、背景色に合わせてラベル色を変えました。

RGBの合計値やGreen値で条件分岐しています。

if (green > 200 && sum < 486){
		button->labelcolor(fl_rgb_color(128,128,128));
} else if(green > 180 && sum < 480){
		button->labelcolor(fl_rgb_color(128,128,128));
} else if(sum < 508){
		button->labelcolor(fl_rgb_color(245,245,245));
} else{
		button->labelcolor(fl_rgb_color(105,105,105));
}

[C++] 84 FLTK : カラーアプリ移植 Fl_Align

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

ボタンのラベルを左寄せにし、はみ出した部分は表示しないようにしました。

JavaのSwingでしたら、中央揃え・はみ出し非表示にしてなおかつ左の文字が切れないようにしてくれます。FLTKではそのような芸当はできないようなので左寄せにしました。

[C++] 83 FLTK : カラーアプリ移植 多次元配列

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

Javaアプリの移植に着手しました。

このアプリを完成させた1月下旬時点と比べてプログラミングスキルはアップしているので、成果を反映させながらグレードアップさせたいです。

まずは配列を3次元にして各要素にアクセスできるようにしました。

[C++] 82 FLTK : Fl_ButtonのFl_Boxtype設定

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

Fl_buttonのFl_BoxtypeはデフォルトでFL_UP_BOXになっていて出っ張った形状になっています。

これをFl_Widgetから継承したbox関数で変更できます。FL_FLAT_BOXでボタン周囲の枠がなくなります。

この方法が分からなかったためにJava(Swing)で製作したカラーサンプルアプリの移植を進められなかったのですが、これで本格的に着手できます。

Swingの特徴であるLook & Feelは外観に統一感を持たせるのに便利なものの、その分自由度が抑えられてしまう点が引っかかってました。

Java版はサイズが45.6MBなので、どこまで軽量、高速化できるのか楽しみです。

Fl_Button *button = new Fl_Button(loc_x, loc_y, 75, 15);
    button->box(FL_FLAT_BOX);
    button->color(fl_rgb_color(red,green,blue));
    button->labelcolor(fl_rgb_color(169,169,169));
    button->labelsize(10);

[C++] 81 連続整数の文字列配列作成 iota関数

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

C++11から標準ライブラリに採用のiota関数を使って連続整数の文字列配列を作成しました。

GUIアプリで整数を表示させる際にこのような配列が必要になったりします。

なおiota関数を使った直後の変数 testはintの配列なので、これはこれで使い道はあります。

最近は変数に型を付けないと物足りなくなってきました。コードを量産するには型推論が便利でしょうが、趣味レベルで楽しむ分には型付けはあまり苦になりません。

C++のように確実に型付けするか、Pythonのようにいさぎよく何も書かないか、どちらもスタンスがハッキリしていて好みですね。

#include <iostream>
#include <numeric>
#include <array>

using std::cout;

// 11から連続整数10個の文字列リスト作成
int main(int argc, char **argv) {
	int start_num = 11; // 開始数
	const unsigned long nums = 10;  // 個数

	int test[nums];
	std::iota(test, test + nums, start_num);

	// 以下でも可能
	// std::array<int, nums> test;
	// std::iota(test.begin(), test.end(), start_num);

	int i = 0;
	for (int num : test){
		if (i == 0){
			cout << "{\"" << num << "\", " ;
		} else if (i > 0 && i < (nums -1)){
			cout << "\"" << num << "\", " ;
		} else {
			cout << "\"" << num << "\"}" ;
		}

		i++;
	}
}
--------------------------------------------------
出力
--------------------------------------------------
{"11", "12", "13", "14", "15", "16", "17", "18", "19", "20"}

[C++] 80 FLTK : Fl_Color全256色

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

FLTKはFl_Colorクラスで独自に256色を設定しています。

主要色やグレースケール等で構成する56色とRGB値を等分して作成した200色です。Fl_Color(色番号)で簡単に色付けできます。

ただ番号だけではどのような色か分からないので、FLTKが公開しているカラーマップをより見やすくするためにツールを作成しています。

virtual colormap

[C++] 79 FLTK : 画像加工アプリにPythonモジュール導入 / Pillow

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

画像加工アプリにPythonのライブラリPillowの機能を導入し、単色アイコンの色変更ができるようにしました。

今回で2度目のPythonモジュール導入になり、引数が1つから5つに増えています。比較的スムーズに実装できました。

OpenCVを使えばC++で同じ機能を実装できるはずですが、開発速度を優先しました。追々OpenCVに切り替えるつもりです。

久しぶりにFinal Cut Pro試用版を使いましたが、プロジェクトの再生時に画質が悪くなるのは仕様あるいはスペック不足のせいでしょうか。画面全体にモザイクが掛かったのかと勘違いしました。

ピクセル化を選択した後に範囲を狭めたにもかかわらずこうなってしまうのは明らかに不具合じゃないかと思います。3ヶ月後に36800円を払うか、無料のDaVinci Resolveに変更するか迷いどころです。

#define PY_SSIZE_T_CLEAN
#include "colorConvert.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>

using std::string; using std::to_string;
using std::cout; using std::endl;

int colorConvert(const char* path, int red, int green, int blue, const char* name) {
    Py_Initialize();

    // pyファイルの指定(imageColorConvert.py)
    PyObject* myModuleString = PyUnicode_FromString((char*)"imageColorConvert");

    // pyファイルのモジュール化
    PyObject* myModule = PyImport_Import(myModuleString);

    // pyファイル内の関数を指定
    PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"color_convert");

    // 関数の引数を設定(5個)
    PyObject* args = PyTuple_Pack(5,PyUnicode_FromString(path),PyUnicode_FromString((to_string(red)).c_str()),PyUnicode_FromString((to_string(green)).c_str()),PyUnicode_FromString((to_string(blue)).c_str()),PyUnicode_FromString(name));

    // 関数を実行
    PyObject* myResult = PyObject_CallObject(myFunction,args);

    return 0;

    Py_Finalize();
}
#include "split.h" // 自製文字列分割関数を含むsplitクラス

class split spt; // 自製クラスのオブジェクト化

void color_convert_func(){
    const char *path = input_line->value();
    const char *name = name_input->value();
    const char *rgb = rgb_input->value();

    string rgb_str = string(rgb);
    vector<string> list_rgb = spt.splits(rgb_str, ',');
    
    string red0 = list_rgb[0];
    string green0 = list_rgb[1];
    string blue0 = list_rgb[2];

    cout << "red0 " << red0 << endl;
    cout << "green0 " << green0 << endl;
    cout << "blue0 " << blue0 << endl;

    vector<string> list_red = spt.splits(red0, '(');
    vector<string> list_blue = spt.splits(blue0, ')');

    int red = stoi(list_red[1]);
    int green = stoi(green0);
    int blue = stoi(list_blue[0]);

    cout << "red " << red << endl;
    cout << "green " << green << endl;
    cout << "blue " << blue << endl;

    colorConvert(path,red,green,blue,name); // Pythonモジュール

    output_line->insert("colorConvert is success!\n");
    cout << "colorConvert is success!" << endl;

}
--------------------------------------------------
出力例:
RGB(106,90,205)から数字を抽出しPythonモジュールの引数として使用
--------------------------------------------------
red0 RGB(106
green0 90
blue0 205)
red 106
green 90
blue 205
colorConvert is success!