tolower

tolowerは、指定された文字がアルファベットの大文字の時、小文字に変換する。

Man page of TOUPPER
C言語関数辞典 - tolower

入力された文字列に大文字があったらすべて小文字に変換する。

textのi番目、text[i]をtolowerに渡して、戻り値をtext[i]に代入し直す。

$ vi tolower.c
$ gcc tolower.c -o tolower
$ ./tolower
ABC
abc
$ ./tolower
AbCdE
abcde
$ ./tolower
aB123Cd
ab123cd
$ ./tolower
Ab1+c2-D3E4
ab1+c2-d3e4
$

このようにすべて小文字になっている。

Sample/c/tolower/tolower/src/tolower at master · bg1bgst333/Sample · GitHub

MVVM

データバインディングを利用して、ViewとViewModelを連携させることで、ViewとModelを分離する手法をMVVMという。

Webアプリケーション開発者から見た、MVCとMVP、そしてMVVMの違い - Qiita

前回のデータバインディングをベースに、C++とLinuxCUIで、疑似的なMVVMを作り始めて1週間・・・。
ようやく完成したので貼っておく・・・。
今回も実装は超複雑なので割愛・・・。

実行すると、

$ g++ main.cpp view.cpp custom_view.cpp -o main
$ ./main
value_ = str1
value_ = str2
value_ = str3
binding_command_update
action start
action end
value_ = ABCDE
value_ = XYZ
value_ = ABCDEXYZ
binding_command_update
action start
action end
value_ = abc
value_ = xyz
value_ = abcxyz
$

こうなる・・・。

Sample/designpattern/mvvm/mvvm/src/mvvm at master · bg1bgst333/Sample · GitHub

データバインディング

同じデータを複数のビューから参照し、データが変更されたら、紐づいたビューが一気に更新されるような機構をデータバインディングという。

第5回 WPFの「データ・バインディング」を理解する (1/3):連載:WPF入門 - @IT

MVVMをやる上でこれは欠かせないが、C言語C++はデータバインディングを持たないので、C++で疑似的なデータバインディングを、

Win32APIアプリケーションでデータバインディングしてみる - Qiita

を参考につくってみた。
今回、実装は大変複雑なので割愛して、どんなものかという実験だけ・・・。

class_input_formが入力フォームのコントロールだとする。
class_binding_variableが入力フォームと紐づける変数。
基本的には文字列を持っていて、文字列をセットするセッターや取得するゲッターなども指定されている。
初期化で"ABC"を持つ。
一方、入力フォームはform1が"hoge"、form2が"foo"、form3が"bar"を持つ。
それぞれのフォームの値を出力。

form2に"AAA"をセットして、またそれぞれ出力。

binding_strと各formをbindし、また値をそれぞれ出力。

form3に"BBB"をセットして、また値を出力。

form1に"CCC"をセットして、また出力。

実行すると、

$ ls
binder.h  binding_variable.h  comparator.h  getter.h  input_form.h
key_binder.h  main  main.cpp  mediator.h  member.h  setter.h
$ g++ main.cpp -o main
$ ./main
value_ = hoge
value_ = foo
value_ = bar
-----
value_ = hoge
value_ = AAA
value_ = bar
-----
value_ = ABC
value_ = ABC
value_ = ABC
-----
value_ = BBB
value_ = BBB
value_ = BBB
-----
value_ = CCC
value_ = CCC
value_ = CCC
$

"AAA"をセットした時は、まだbindされてないので、form2しか変わらない。
しかし、bindされた後は、binding_strの"ABC"に全部変わっている。
form3を"BBB"に変えると、他も"BBB"になり、form1を"CCC"に変えると、他も"CCC"になる。

Sample/designpattern/data_binding/data_binding/src/data_binding at master · bg1bgst333/Sample · GitHub

OneLang32/OneLang32Console(0, 0, 0, 7/Nishi-Funabashi #7) -SyntaxAnalyzerの追加. etc...

構文解析器SyntaxAnalyzerと構文情報を持つSyntaxInfoを追加した。

SyntaxInfo.hは、

構造体にした。
まだ、IDしか実装してない。

SyntaxAnalyzer.hは、

SyntaxInfoのvector、m_vecsiSyntaxTableに各文(もしくはそれらの集まり)の構文情報がリストで入る。
AnalyzeでCLexicalAnalyzerのポインタを引数に取る。

SyntaxAnalyzer.cppは、

とりあえず今回は、トークンの0番目だけ出力。

LexicalAnalyzer.hは、

GetTokenが増えた。

LexicalAnalyzer.cppでは、

GetTokenの実装では、uiNo番目のトークンを返す。

トークンの出力をいったんコメントアウト

main.cppでは、

構文解析を追加。

実行すると、

argv[1] = test.1
CLexicalAnalyzer::Analyze!
----- start -----
----- end -----
CSyntaxAnalyzer::Analyze Start
GetToken(0) = /
CSyntaxAnalyzer::Analyze End
続行するには何かキーを押してください . . .

構文解析で最初のトークン"/"だけ出力してる。

-SyntaxAnalyzerの追加. · bg1bgst333/OneLang32@1a96101 · GitHub

electron-rebuild

ElectronでC++拡張モジュールを呼び出せるかやってみる。

electron/using-native-node-modules.md at master · electron/electron · GitHub

まず、npm init。

$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (app_)
version: (1.0.0)
description: electron-rebuild sample
entry point: (index.js) main.js
test command: start
git repository: -
keywords: -
author: B.G
license: (ISC) MIT
About to write to
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/package.json:

{
  "name": "app_",
  "version": "1.0.0",
  "description": "electron-rebuild sample",
  "main": "main.js",
  "scripts": {
    "test": "start"
  },
  "repository": {
    "type": "git",
    "url": "-"
  },
  "keywords": [
    "-"
  ],
  "author": "B.G",
  "license": "MIT"
}


Is this OK? (yes)
$

package.jsonを作成したら、
main.jsで、

デベロッパーツールを起動するようにしておく。
index.htmlは、

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>app_</title>
  </head>
  <body>
    <h1>ABCDE</h1>
    <button onclick="run()">Run</button>
    <script>
      document.write(process.versions.electron);
      function run(){
        var nativeExt = require('./build/Release/native_ext.node');
        var str = nativeExt.get_abc();
        alert(str);
      }
    </script>
  </body>
</html>

ネイティブ拡張を参照できるようにしておく。
package.jsonは、

{
  "name": "app_",
  "version": "1.0.0",
  "description": "electron-rebuild sample",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "repository": {
    "type": "git",
    "url": "-"
  },
  "keywords": [
    "-"
  ],
  "author": "B.G",
  "license": "MIT"
}

npm startで"electron ."を起動できるように。
electronをインストールする。

$ vi main.js
$ vi index.html
$ vi package.json
$ npm install electron

> electron@4.1.0 postinstall /home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/electron
> node install.js

Downloading tmp-4643-1-SHASUMS256.txt-4.1.0
[============================================>] 100.0% of 4.74 kB (4.74 kB/s)
npm notice created a lockfile as package-lock.json. You should commit this file.
+ electron@4.1.0
added 145 packages from 141 contributors and audited 201 packages in 81.199s
found 0 vulnerabilities



   ╭───────────────────────────────────────────────────────────────╮
   │                                                               │
   │       New minor version of npm available! 6.4.1 → 6.9.0       │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.9.0   │
   │               Run npm install -g npm to update!               │
   │                                                               │
   ╰───────────────────────────────────────────────────────────────╯

$

続いて、node-gypのインストール。

$ ls
index.html  main.js  node_modules  package-lock.json  package.json
$ npm install node-gyp
+ node-gyp@3.8.0
added 35 packages from 10 contributors and audited 384 packages in 4.585s
found 0 vulnerabilities

$

binding.gypはnode-gypのトピックで使ったものと同じものを使用した。
また、native_ext.ccでは、

get_abcの中でsleepで5秒休止するようにした。
node-gyp configureする。

[bg1@localhost app_]$ vi binding.gyp
[bg1@localhost app_]$ vi native_ext.cc
[bg1@localhost app_]$ ./node_modules/.bin/node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/bg1/.node-gyp/10.15.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/bg1/.node-gyp/10.15.0',
gyp info spawn args
'-Dnode_gyp_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp',
gyp info spawn args
'-Dnode_lib_file=/home/bg1/.node-gyp/10.15.0/<(target_arch)/node.lib',
gyp info spawn args
'-Dmodule_root_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok
$

node-gyp buildする。

$ ./node_modules/.bin/node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
に入ります
  CXX(target) Release/obj.target/native_ext/native_ext.o
In file included from ../native_ext.cc:2:
/home/bg1/.node-gyp/10.15.0/include/node/node.h:570:43: 警告: cast
between incompatible function types from ‘void
(*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void
(*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’}
[-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/home/bg1/.node-gyp/10.15.0/include/node/node.h:604:3: 備考: in
expansion of macro ‘NODE_MODULE_X’
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../native_ext.cc:28:1: 備考: in expansion of macro ‘NODE_MODULE’
 NODE_MODULE(native_ext, init);
 ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/native_ext.node
  COPY Release/native_ext.node
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
から出ます
gyp info ok
$

ビルドすると、

$ ls
binding.gyp  build  index.html  main.js  native_ext.cc  node_modules
package-lock.json  package.json
$ cd build/
$ cd Release/
$ ls
native_ext.node  obj.target
$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/Release
$

build/Releaseの下にnative_ext.nodeができる。
npm startすると、

起動時
起動時

このように表示される。
右の開発ツールでConsoleのタブをクリック。

Console
Console

いまのところは問題なさそうだが、"Run"ボタンを押すと、

エラー
エラー

エラーが発生。
実は、ElectronのNODE_MODULEとNode.jsのNODE_MODULEのバージョンには違いがあり、それが原因でネイティブモジュールを呼び出せない。
そこで、electron-rebuildを使って、"ElectronのヘッダでNode.jsをリビルドする"という作業を行う。
(ここ、よくわからないとおもうが、次のようにすればうまくいくと思えばいい・・・。)
まず、electron-rebuildをインストール。

$ ls
binding.gyp  build  index.html  main.js  native_ext.cc  node_modules
package-lock.json  package.json
$ npm install --save-dev electron-rebuild
+ electron-rebuild@1.8.4
added 75 packages from 53 contributors and audited 679 packages in 9.573s
found 0 vulnerabilities

$

ビルド時にしか使わないので、"--save-dev"でインストール。
npmの--save, --save-dev, --save-optionalの違い - how to code something

electron-rebuildコマンドを実行し、configureとbuild。

$ ./node_modules/.bin/electron-rebuild
✔ Rebuild Complete
$ ./node_modules/.bin/node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn /usr/bin/python2
gyp info spawn args [
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args
'/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/bg1/.node-gyp/10.15.0/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/bg1/.node-gyp/10.15.0',
gyp info spawn args
'-Dnode_gyp_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/node_modules/node-gyp',
gyp info spawn args
'-Dnode_lib_file=/home/bg1/.node-gyp/10.15.0/<(target_arch)/node.lib',
gyp info spawn args
'-Dmodule_root_dir=/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.' ]
gyp info ok
$ ./node_modules/.bin/node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@10.15.0 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
に入ります
  CXX(target) Release/obj.target/native_ext/native_ext.o
In file included from ../native_ext.cc:2:
/home/bg1/.node-gyp/10.15.0/include/node/node.h:570:43: 警告: cast
between incompatible function types from ‘void
(*)(v8::Local<v8::Object>)’ to ‘node::addon_register_func’ {aka ‘void
(*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)’}
[-Wcast-function-type]
       (node::addon_register_func) (regfunc),                          \
                                           ^
/home/bg1/.node-gyp/10.15.0/include/node/node.h:604:3: 備考: in
expansion of macro ‘NODE_MODULE_X’
   NODE_MODULE_X(modname, regfunc, NULL, 0)  // NOLINT (readability/null_usage)
   ^~~~~~~~~~~~~
../native_ext.cc:28:1: 備考: in expansion of macro ‘NODE_MODULE’
 NODE_MODULE(native_ext, init);
 ^~~~~~~~~~~
  SOLINK_MODULE(target) Release/obj.target/native_ext.node
  COPY Release/native_ext.node
make: ディレクトリ '/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_/build'
から出ます
gyp info ok
$

そうすると、

$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ cd bin
$ ls
linux-x64-69
$ cd linux-x64-69/
$ ls
app_.node
$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/src/app_/bin/linux-x64-69
$

bin/linux-x64-69の下にapp_.nodeができる。これがリビルドされたモジュールなのでこれを参照するようにする。

このように書き換えたら、npm startしてみる。

$ pwd
/home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ vi index.html
$ ls
bin  binding.gyp  build  index.html  main.js  native_ext.cc
node_modules  package-lock.json  package.json
$ npm start

> app_@1.0.0 start /home/bg1/project/cloud/github.com/Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_
> electron .

で起動し、

起動時
起動時

このようになるので、Runボタンを押す。

エラーが出ず、へこんだままになる。
エラーが出ず、へこんだままになる。

今度は、エラーが出ず、へこんだままになるので、5秒待つ。
5秒経つと、

alertで&quot;ABC&quot;が表示される。
alertで"ABC"が表示される。

alertで"ABC"が表示される。
このように、Electronからネイティブ拡張を使う場合は、electron-rebuildが必要になる。

Sample/electron-rebuild/electron-rebuild/electron-rebuild/src/app_ at master · bg1bgst333/Sample · GitHub

Form.Load

アプリケーションが起動し、フォームが初めて表示される直前にForm.Loadイベントが発生する。
(このフォームがロードされた時のイベント。)

Form.Load Event (System.Windows.Forms) | Microsoft Docs

ここでコントロールの初期化処理などを行う。

プロジェクト作成
プロジェクト作成

プロジェクト作成したら、

TextBox選択
TextBox選択

TextBoxを選択。

配置
配置

こんな風に配置して、

Form1のイベント
Form1のイベント

Form1のイベントを表示するようにする。

Load
Load

Loadイベントの項目をダブルクリックすると、

イベントハンドラ、Form1_Loadが追加されるので、textBox1.Textに"ABCDE"をセットするコードを追加。

Form1.Designer.csを見ると、確かにLoadイベントにForm1_Loadが追加されてる。

実行時
実行時

実行すると、"ABCDE"がセットされている。

Sample/dotnet/Form/Load/src/Form_ at master · bg1bgst333/Sample · GitHub

Container.paint

画面の描画処理は、paintメソッドで行う。
これは、Frameクラスの親のWindowクラスの親のContainerクラスのメソッドである。

Container (Java Platform SE 6)
GUIアプリケーション(AWT その2)
AWTとSwingのペイント(paint)の仕組み

Frameを継承したクラスMainFrameで、paintをオーバーライドして、直線を描画する。
まずは、CustomAdapter.javaで、

ウィンドウを閉じた時の処理を書く。
WindowAdapterの継承クラスに書いておけば、すべてのイベント処理を書く必要はなくなる。
MainFrame.javaで、

コンストラクタにて、addWindowListenerで、newで生成したCustomAdapterのインスタンスをセット。
これで先程のウィンドウのイベント処理が行われる。

今回の本題であるpaint。
Graphicsオブジェクトgが渡されるので、g.drawLineで(100, 100)-(200, 200)の直線を引く。
あとは、MainClass.javaで、

MainFrameオブジェクトmainFrameを生成して表示する。

直線
直線

ちゃんと直線が描画されている。

Sample/java/Container/paint/src/Container at master · bg1bgst333/Sample · GitHub