Flutterのお勉強(1)

モバイルアプリについて勉強しなければいけなくなったため、ど素人が独学で色々と調査した記録をまとめます。

 

勉強の最終目標

そもそもモバイルアプリの開発環境にはどんなものがあるのか?

ざっと調べただけですが、単純思考の私にはびっくりするほど複雑な世界でびっくりしましたね……。

私のようなど素人はネイティブ開発安定では?と思ったのですが、一旦クロスプラットフォーム開発に軽く触れてみようかと思います。
ネイティブ開発に関してはAndroid版アプリの作成を基礎研修で学んだため、最終的にはネイティブ開発で作成したものをクロスプラットフォーム開発して見栄えやソースなどを比較できたらと思います。

 

やろうやろうと思って手を付けられていなかったUnityをさっさと触っておけばよかったかもと少し後悔しています……。やるかぁ……。

 

 

モバイルアプリとは?

さて、まずはモバイルアプリについての学習です。

前項の内容が理解できない方はまず基礎について学ぶことをお勧めします。

モバイルアプリってどのように作成するのか、具体的にイメージできていますでしょうか?
例えば画面系ならツールはVisualStudioを使用して、フレームワークは.netで、データ収集ならマクロ、バッチやファイル操作ならjavaなんてなんとな~く作りたいものによって環境のイメージが付くかと思います。(私の経験上の話なので所説あります)

私も「Android用とiOS用で違うツール使うんだろうな~」程度で思っていました……最初は……しかしなんということでしょう……クロスプラットフォーム……?フレームワーク何種類あるの……?状態になりました。。。。

下記のサイト様がとてもわかりやすく、取っ掛かりからわからない、モバイルアプリのそもそもを学習されたい方にはぜひ読んでいただきたい内容です。

記事上部の「連載記事」に全部で4つのコラムに分かれてリンクが紹介されていますので、すべて読んだ上で開発方法について検討することを推奨します。

 

今回はクロスプラットフォーム環境を作成するため、以下のサイト様を参考にフレームワークを選択しました。
サイトによってFlutterの普及率が異なっており、ここはもう好みでよいかなというところです。初めての場合はサンプルコードや日本語の解説サイトが多いものを選んでおけば間違いなしって感じでしょうか……。

 

早速AndroidStudioとFlutterをインストールし、公式から提供されているチュートリアルを行っていきます。

 

チュートリアルの通りに行ってつまずいた箇所がいくつかあったので抜粋してまとめます。

別記事へ続く・・・・

【C#】テキストボックスの入力形式制限(リアルタイム版)

TextChangedは使いたくないな~~~!?!?!

 

というわけで前回からパワーアップし、入力中に制限をかけられないか模索中です。

 

  1. 【PreviewKeyDownイベント】現在のテキスト内容とカーソル位置を保持
  2. 【KeyPressイベント】前回の「入力制限(数値だったりマイナスだったりの制限)」を記述
  3. 【ここ模索中】入力値を含めたテキスト内容で「正規表現での制御」を記述。一致しなかった場合、1で保持しておいた元のテキストとカーソルの位置を描画する。
  4. 【Leaveイベント】カンマ区切りかつ小数部2桁のフォーマットを記述。

なんてやり方で試しているのですが。。。。
手順3で「入力値を含めたテキスト内容」を取得する方法がどうしても見つからず(力技でならいけるのかもしれませんが、どうしてもシンプルにすませたい病のため)苦戦中;;
TextChangedは手順4が通ったときも発動してしまうし、そもそも初期値を設定しただけでも動いてしまうイベントなのでできれば使いたくない……(便利と不便は紙一重だなとしみじみ)

 

力技だと。。。手順3を手順2に吸収し、カーソルの位置に入力文字(e.KeyChar)を挿入するって感じでしょうか……。

続きは明日。

 

 

 

 

というわけで続きです。

手順3を手順2に吸収し、カーソルの位置に入力文字(e.KeyChar)を挿入する

調べてみたらこれが1行で実現できたので試してみました。
結局KeyPressイベントですべてを処理しきってしまうのがあれこれ考える必要なさそうだったのでまとめています。

<余談>
KeyPressイベント、KeyUpイベント、KeyDownイベント、PressKeyDownイベントなど色々ありますが、高速で入力すると2個目のPressKeyDownイベントがスキップされたり処理に必ずしも通るとは限らない状態が生まれてしまい、使い勝手はよくなかったです……。
これらのイベントに関してはいつかまとめたいなと思ってます。

 

話が若干それましたが以下コードです。

  1:        private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
  2:        {
  3:
  4:            TextBox target = sender as TextBox;
  5:
  6:            // 入力時のカーソル位置
  7:            int inp_curpos = target.SelectionStart;
  8:            // 選択状態の文字数
  9:            int inp_sltLng = target.SelectionLength;
 10:            // 入力後の文字列形成
 11:            string aft_str = target.Text.Insert(inp_curpos, e.KeyChar.ToString()); 
 12:            if (inp_sltLng > 0) { aft_str = aft_str.Remove(inp_curpos + 1, inp_sltLng); } // 選択状態からの上書きであれば、上書きされた後の文字列を取得する
 13:            aft_str = aft_str.Replace(",", "");                                          // カンマが含まれている場合はカンマを取り除く
 14:            // 入力形式指定(正規表現
 15:            Regex r = new Regex(@"^-?\d{1,4}[.]\d{0,2}$|^-?\d{0,4}$");
 16:
 17:            // 制御文字は入力可
 18:            if (char.IsControl(e.KeyChar))
 19:            {
 20:                e.Handled = false;
 21:                label1.Text = "";
 22:                return;
 23:            }
 24:
 25:            // 「.」または「-」または数値1-9以外ははじいて処理終了
 26:            if (e.KeyChar == '.') 
 27:            {
 28:                if (((inp_sltLng != 0 && target.SelectedText.IndexOf('.') < 0)) && target.Text.IndexOf('.') > 0)  // 選択範囲に.がない or すでに.が使用されている
 29:                {
 30:                    e.Handled = true;
 31:                    return;
 32:                }
 33:            }else if (e.KeyChar == '-')
 34:            {
 35:                if (((inp_sltLng != 0 && target.SelectedText.IndexOf('-') < 0)) && target.Text.IndexOf('-') > 0) // 選択範囲に-がない or すでに-が使用されている
 36:                {
 37:                    e.Handled = true;
 38:                    return;
 39:                }
 40:            }else if (char.IsDigit(e.KeyChar) == false && e.KeyChar != '\b')
 41:            {
 42:                e.Handled = true;
 43:                return;
 44:            }
 45:
 46:            
 47:            // 入力形式判定
 48:            if (r.IsMatch(aft_str))
 49:            {
 50:                e.Handled = false;
 51:                label1.Text = "";
 52:            }
 53:            else
 54:            {
 55:                e.Handled = true;
 56:                label1.Text = "入力形式:整数1~4桁、小数点0~2桁";
 57:            }
 58:        }
 59:
 60:
 61:        private void textBox2_Leave(object sender, EventArgs e)
 62:        {
 63:            TextBox target = sender as TextBox;
 64:            //1文字目が「.」または「-」の場合、スルー
 65:            if(target.Text == "" || target.Text == "-." || target.Text.Length == 1 && 
 66:                                        (target.Text.Substring(0, 1) == "-" || target.Text.Substring(0, 1) == ".") || Math.Truncate(double.Parse(target.Text)).ToString().Length > 4) 
 67:            {
 68:                target.Text = "0";
 69:            }
 70:            target.Text = (double.Parse(target.Text)).ToString("N2");
 71:        }

 

前回からの違いは色々ありますが、大きく変更したのは以下3点

  • 入力中であることを考慮して正規表現を変更
  • 入力を受け付ける文字列の判定を変更(受け付けないパターンを判定条件としてreturnで抜ける)
  • 最期に正規表現判定

一方通行の入力なら問題ないのですが、入力して消して入力して消してという動作が取れる都合、「1234.56」と入力した後「-.56」という値に書き換えることもできてしまうわけです。
使う側にとっては不自然ではない動きでも、それがシステムエラーとなるようであれば入力を制限しなければなりません。
今回は入力への制限は極力なくし、フォーマットエラーの原因となる文字列を無理やり0にしています。めちゃくちゃ力技ですね^^

正直、backspaceを問答無用で受け付けてreturnしてしまってるせいで正規表現が2割型意味をなしていないんですよね……。そこをL65で無理やり矯正している感じです。

backspaceの考慮は色々と試しましたが、ただただコードが長くなるだけで解決方法が見えていないので一先ずこちらでフィニッシュとします;

 

2023/4/13 追記

L66について、考慮が足りないパターンがあったため変更しました。

 

 

続きを読む

【C#】小数点を含むテキストボックスの入力形式制限

テキストボックスの入力形式を制限する方法について、コード量の少なさと汎用性の高さという点で個人的に結論がでたのでまとめます。

 

今回の条件は

  • 整数部と小数部に桁数制限がかかっている
  • マイナスを許容する

だけ!

整数部と小数部の桁数をそれぞれ取得して……という方法も考えましたが、今回は正規表現で入力形式を定義して、一致しているか判定する方法で実現しました。
入力中に制限をかけるのは一筋縄ではいかなそうだったので、Leaveイベントに記載する前提で考えていきます。

 

<前準備>
1.usingで「using System.Text.RegularExpressions;」を指定しておいてください。
2.対象のテキストボックスは必要に応じて入力制限をかけておくとよいと思います。(参考:[C#]TextBoxに数字のみ入力可能にする
 諸事情で少しだけ改造しています。詳細は記事最下部をご参照。

 

例)整数部4桁、小数部2桁(マイナスを許容)

Regex r = new Regex(@"^-?\d{1,4}[.]\d{0,2}$|^-?\d{1,4}$|-?[.]\d{0,2}$");

if (r.IsMatch(textBox1.Text)){
 // 一致
}else{
   // 一致していない
}

ここからさらに、カンマ区切りで表示する処理を追加。

textBox1.Text = (double.Parse(textBox1.Text)).ToString("N2");

フォーマット関連の記述方法は色々あるので好きなものを使用するといいと思います。
(参考:書式を指定して数値を文字列に変換する

フォーマットって数値型からの変換でしか使えないんですかね・・・すごく不格好で何とかしたい;;;

 

入力形式に一致している場合としていない場合の処理を追加し処理を通すと以下のようになります。

 private void textBox1_Leave(object sender, EventArgs e)
        {
            Regex r = new Regex(@"^-?\d{1,4}[.]\d{0,2}$|^-?\d{1,4}$");
            if (r.IsMatch(textBox1.Text))
            {
                label1.Text = "入力OK";
                textBox1.Text = (double.Parse(textBox1.Text)).ToString("N2");

            }
            else
            {
                label1.Text = "整数4桁、小数点2桁で入力してください";
            }
        }

<補足>
0⇒0.00
0.→0.00
.→入力NG
.99⇒入力NG

 

と、ここで問題が。。。。
すでにカンマ区切りのテキストに対して正規表現判定を行おうとすると、当り前のようにNGになります。
例)1234.56⇒OK、1,234.56⇒NG

そのため、テキストボックスの入力値に対してカンマ表記を除いた状態で判定を行う必要があります。
安直に考えたらReplace関数かな……。

string str = textBox1.Text.Replace(",", "");

ということで、最終的に完成したものが下記。

private void textBox1_Leave(object sender, EventArgs e)
        {
            //正規表現
            Regex r = new Regex(@"^-?\d{1,4}[.]\d{0,2}$|^-?\d{1,4}$");

            // カンマが含まれている場合はカンマを取り除く
            string str = textBox1.Text.Replace(",", "");

            if (r.IsMatch(str))
            {
                label1.Text = "入力OK";
                textBox1.Text = (double.Parse(textBox1.Text)).ToString("N2");
            }
            else
            {
                label1.Text = "整数4桁、小数点2桁で入力してください";
            }
        }

 

<おまけ>
入力を数値のみに制限する処理の改造版

続きを読む