DOBON.NET DOBON.NETプログラミング掲示板過去ログ

固定文字列以外を自由に編集可能なテキストエディタを実現したい

環境/言語:[C#、.Net 3.5]
分類:[.NET]

こんにちは、いつも大変参考にさせていただいてます。
今回は表題のようなGUIをどうしても実装できなくて悩んでおります。
相談させてください。

【得たいアウトプット】
・固定文字列"000"を必ず含んでいるSingleLine文字列
 (例)"abc_000"、"aa000qwerty"、"000str"、"0101000"、など
・固定文字列"000"の先頭Index(固定文字列がどこに含まれているかがわかること)
 "000abc000123000"のように固定文字列が重複している場合、固定文字列の先頭Indexは[0]か[6]か[12]か判別したい

【実現したいGUI】
・固定文字列"000"(赤字表示)を含んだSampleテキストを表示し、固定文字列部分以外(黒字表示)はユーザが自由に編集できるテキストボックス    

これの意図は、ユーザが自由に編集した文字列の一部分に、3桁の連番を振りたいというのが目的です。
最終的にString.Formatに{0:000}を含んだユーザ指定の文字列を食わせるのが目的ですが、プログラムに縁のないユーザでも編集できるよう、
上記GUIを実装したく思っています。
Validate時に000が含まれてない場合警告を出すことも考えましたが、桁数が動的に変わることや、000が複数含まれているときにどこを
{0:000}にすればいいかを判別することを考え、現状は上記GUIを想定しております。


【書いてみたコード】
RichTextBoxのProtectを使って実装してみました。

    public partial class Form1 : Form
    {
        public string Format;
        private int NumIndex = 11;
        private string NumStr = "000";
        private string CurrentText = "";

        public Form1()
        {
            InitializeComponent();
            richTextBox1.Multiline = false;

            richTextBox1.AppendText("SampleText_");

            richTextBox1.SelectionColor = Color.Red;
            richTextBox1.AppendText(NumStr);
            richTextBox1.Select(NumIndex, NumStr.Length);
            richTextBox1.SelectionProtected = true;

            richTextBox1.Select(richTextBox1.Text.Length, 0);
            richTextBox1.SelectionColor = Color.Black;
            richTextBox1.SelectionProtected = false;

            CurrentText = richTextBox1.Text;
            richTextBox1.TextChanged += new EventHandler(richTextBox1_TextChanged);
            richTextBox1.SelectionChanged += new EventHandler(this.richTextBox1_SelectionChanged);
        }

        void richTextBox1_SelectionChanged(object sender, EventArgs e)
        {
            if (richTextBox1.SelectionLength == 0 && (richTextBox1.SelectionStart == 0 || richTextBox1.SelectionStart == richTextBox1.Text.Length))
                richTextBox1.SelectionProtected = false;
        }

        void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            int diff = richTextBox1.Text.Length - CurrentText.Length;
            if (NumStr.Length == 0 || richTextBox1.SelectionStart - diff <= NumIndex)
                NumIndex += diff;

            if (richTextBox1.SelectionStart == 1 || (richTextBox1.Text.Length > 0 && richTextBox1.SelectionStart == NumIndex + NumStr.Length + 1))
            {
                int tmp = richTextBox1.SelectionStart;
                richTextBox1.Select(richTextBox1.SelectionStart - 1, 1);
                richTextBox1.SelectionColor = Color.Black;
                richTextBox1.SelectionProtected = false;
                richTextBox1.Select(tmp, 0);
            }

            CurrentText = richTextBox1.Text;
        }

        private void buttonOK_Click(object sender, EventArgs e)
        {
            this.Format = NumStr.Length > 0 ? CurrentText.Substring(0, NumIndex) + "{0:" + NumStr + "}" + CurrentText.Substring(NumIndex + NumStr.Length) : CurrentText;
            this.Close();
        }
    }

これですと直接入力の場合は意図した通りに動作するのですが、日本語入力ができません。
protectされている赤字の000のみ残して他を削除し、それから000の前後に日本語を入力しようとすると、richTextBox1_SelectionChangedで
richTextBox1.SelectionProtected = falseしているのですが入力が効きません。

また、文字列が000のみのときに先頭に文字を挿入する場合、または000の直後に文字を追記する際、
   richTextBox1.Select(richTextBox1.Text.Length, 0);
   richTextBox1.SelectionColor = Color.Black;
などとしてあっても赤字になってしまうため、苦肉の策としてrichTextBox1_TextChanged内で入力された一文字目を黒にしています。
ただこれだと、一度に複数文字を挿入/追記されたら対応できないと思うので、日本語入力ができるようになったら改良の必要があるとは思っています。
が、現状後回しになっております^^;


ということで、上記GUIを実現するテクニック、不足している知識、または代替案、などについてお知恵をお貸しください。
Rtfを直接編集することも考えましたが、GUIとの連動が想像つかず、断念しております。

以上、よろしくお願いします。
■No30701に返信(Ritさんの記事)

いまひとつ理解出来てない気がするのですが
こんな感じでしょうか?(VB.NETですので置き換えて考えて下さい)


    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Dim value = "aaaa000bbbb000ccc000ddd000eee000"

        RichTextBox1.Text = value
        Dim idx = value.IndexOf("000")

        Do While idx >= 0
            RichTextBox1.Select(idx, 3)
            RichTextBox1.SelectionColor = Color.Red
            RichTextBox1.SelectionProtected = True
            idx = value.IndexOf("000", idx + 3)
        Loop

    End Sub
返信ありがとうございます。
説明がわかりづらくて申し訳ありません。

このGUIで得たい結果は、String.Format("ユーザ{0:000}が入力した文字列", count);のような感じで指定するフォーマッタ部分です。
たとえばユーザがテキストボックスに入力したのが"aaaa000bbbb000ccc000ddd000eee000"であり、GUI上で赤字(protectされている)部分が
index[12]の"000"だとすると、最終的に以下のような文字列を作り出したいのです。
aaaa000bbbb001ccc000ddd000eee000
aaaa000bbbb002ccc000ddd000eee000
aaaa000bbbb003ccc000ddd000eee000
aaaa000bbbb004ccc000ddd000eee000
・・・

(1)ユーザは任意の文字列を作成
(2)3桁の連番にしたい部分を"000"にする。
(3)OKすると、(1)で作成した文字列の(2)で指定した部分が連番となる複数の文字列が作成される

今回の相談は、(2)で必ずどこかに"000"を含ませるよう、GUI上で"000"をあらかじめ含んだサンプル文字列を表示しておき、
わかりやすいように赤字にして、ユーザが削除できないようにRichTextBoxでprotectしている、というものです。
protectしたとき、直接入力なら意図通りに"000"部分のみprotectされるのですが、日本語入力だと"000"の前後に文字を挿入できない状態です。
2012/07/09(Mon) 10:35:28 編集(投稿者)

■No30713に返信(Ritさんの記事)

提示された仕様だと『000』の数は増やしたり、減らしたりすることも可能な
きがしますがどうでしょう?
書式サンプルを別のリッチテキストボックスに表示だけしておいて
入力用はプロテクトをかけず、最後に正規表現などによりチェックを行うのは
どうでしょう?

この書式において
00000 は
(1)000 00
(2)0 000 0
(3)00 000
の3通りの解釈になってきますが、このような場合の仕様も決めたほうがよいと思います。
単に二つのテキストボックスで、固定の箇所(000)の前後を編集させればいいんじゃないかと。
フォーム上は
[ ]000[ ]
という感じ。出力サンプルを横にラベル表示すれば見やすいかな?
コンテナ(GroupBoxとか)に入れて、テキストボックスの枠線や背景を調整すれば、より見やすくなるかと思います。

DOBON.NET | プログラミング道 | プログラミング掲示板