ゲームエフェクトデザイナーのブログ (新)

レポート記事とかUE4のマテリアルとか。C#とかも触ったり。

C# よく使う文字列をコピペするための補助ツール

作りました。こちらからDLできます。

GitHubにも実行ファイルとソリューション一式をアップしています。
ライセンスは MIT License です。

「しばらくの間、同じような文字列を頻繁にコピペする」という時に使ってみてください。
ちなみに自分はバージョン管理ソフトのコメントコピペ集として使うために作りました。

f:id:moko_03_25:20180828025825p:plain

7つの項目xタブで3ページは固定です。

同梱している「Default.ini」にテキストの内容を記憶します。
ツールを終了する際の保存ダイアログに対応しました(2018.9/6)。

Vectorとか探せばもっと良いツールがあるかも知れませんが探していません。。

UserControlは超便利!


プログラムとしては、テキストボックスの内容を何らかのファイルに保存して読み書きする部分以外は「初めてツール作るよ」という人でも作れるくらい簡単だと思います。チュートリアルに向いているかもと思いました。

なにせツールの挙動周りでやってる主なことはこれだけです。

・CopyボタンでTextBoxの文字列をクリップボードにコピー
・ClearボタンでTextBoxの文字列を消去
・TextBox内で Ctrl+A を押すと文字列を全選択する
・ツール起動時にTexBox内にiniファイルから文字列を読み込む
・ツール終了時にTexBox内の文字列をiniファイルに書き込む


ただし大量に同じコントロールを配置していますが、これを私みたいな超初心者だと同じ命令をコントロールの数だけ根性で書いていきがちだと思います。そこを効率良く記述・管理するのに「UserControl」という機能を利用しました。こちら大変便利です!

ユーザーコントロールを作成する (C#プログラミング)

コントロールの集合体をまとめて1つのクラスにして、Form1に配置する際にインスタンスが生成される感じです。つまり下図のような1セットで1つのコントロールのように扱えます。

f:id:moko_03_25:20180905034136j:plain

こちらを利用すれば、Copyボタンの挙動、Clearボタンの挙動、TextBoxの挙動や文字列のiniからの読み込みと書き込みなどを、ひとつ分記述するだけで済むのでとても楽です。

一番最初は、それぞれの挙動を21個分ずらずらっと書いてました。こんな感じで‥。

f:id:moko_03_25:20180905033824j:plain

さすがにこれはひどいなと。。

UserControlのプロパティ


さて、UserControl内にコントロールを色々配置したは良いものの、ではTextBoxの文字列をForm1からアクセスしたい場合はどうしよう?と思いましたが、プロパティが便利でした。

// TextBoxの中身をプロパティでアクセス可能にする
[Browsable(true)]
public string TextBoxText
{
    get
    {
        return this.tbText.Text;
    }
    set
    {
        this.tbText.Text = value;
    }
}


このように記述すれば、Form1のデザイナーにUserControlを配置した際のプロパティウインドウにもちゃんと設定が表示されます。便利!

逆に隠蔽したい場合には Browsable(false) にしておけば良いようですね。

UserControlのクローズ処理


標準ではUserControl自身がクローズした際のイベントが用意されておらず、じゃあUserControl側からForm1のクローズイベントを受け取ろうと思っても、こちらも標準では用意されていないようで、ツール終了時にUserControl自身でiniファイルへ書き込むのに手間取りました。

ググると色んな方法があるようですが、こちらの記事で紹介されているコンストラクタ内でDisposeを使った方法が一番シンプルで良いと思います。

iniファイルのフォーマットは非常にシンプルです。こんな感じ。

[TextBox_00]
Text=A
[TextBox_01]
Text=B
[TextBox_02]
Text=C


[セクション]
キー = 保存する値

‥という感じです。

iniファイルへの書き込み・読み込みですが、セクション名をForm1に配置した各UserControl自身の名前にすることでやり取りをスムーズにしました。名前はTextBox_00~TextBox_20の21個になります。「this.Name」でUserControl自身がForm1に配置された際の名前を取得できます。

しかし、そうするとUserControlのコンストラクタで初期化時にiniから文字列を読み込みたくても、この時点ではまだ生成されてForm1配置時の名前が設定される前なので自身のインスタンスの名前を取得できません。

なのでコンストラクタではなく「userControl_Load」イベントでiniから読み込むようにするとうまくいきました。UserControlのクローズイベントは無いけどロードイベントはあったので助かりました。。

ただしDisposeでの終了時では「this.Name」で名前を取得しようとしてもすでにTextBoxが解放されているためか取得できません。そこで「TextChanged」イベントでTextBoxの内容が変わる度に変数に文字列を保存しておき、変数の内容をiniに書き込むようにすると大丈夫でした。つまり変数の値ならDispose時にちゃんと取得できたという感じです。

iniファイルを扱うクラス


今回、テキストの保存には初めてiniファイルを利用してみました。
ずっと以前から馴染みがある設定ファイルですし一度使ってみたかったんですよね。

ところが.netでは設定の外部保存はXML推奨みたいでiniファイルを扱うライブラリが用意されていないらしく、iniファイルを扱うための古いDLLを読んで、それを扱うためのコードを含めるのがちょいと面倒な感じでした。

iniファイルを扱うコードは検索すると色んな方の事例が出てきますが、こちらの記事の内容がシンプルで分かりやすかったので参考にさせていただきました!感謝です!

クラスを新規作成してこちらの記述をまるっと書くと良い感じです。
今回は文字列しか書き込まないので、読み書きのメソッドはstringのものだけにしています。

ただし二点注意があり、まずusingに下記の一文を追加する必要があります。

using System.Runtime.InteropServices;


また、iniファイルからは一行しか読まないため、改行部分「"\r\n"」を何かしら改行を表す文字列に置き換えてやる必要があります。

これはiniファイルを読み書きするメソッド内で置換を行うとなぜかうまくいかず、userControl内でTextBoxの文字列を扱う部分で置換させたら素直にいけました。

こんな感じです。

// 定数
// iniファイルで改行を表す記号をここで定義
const string rn = "<rn>";

// iniファイルからの読み込み
string s = ini.getValueString(myName, "Text");
// 独自の改行記号を改行に置換
tbText.Text = s.Replace(rn, "\r\n");

// 改行を独自に定義した改行記号に変更
myText = tbText.Text.Replace("\r\n", rn);


iniファイルの良いところは中身の記述がシンプルな点で、ユーザーがテキストエディタで開いた時に項目が一目で分かり編集しやすいところですね!

逆に言えば想定しない編集をされてしまう危険性もあると。。

お次はjsonファイルを試してみたいと思っています。

タブコントロールの利用


タブは標準では背景色を変えるプロパティが無いなど色々不便です。
そしてググっても情報もあまり出てきません。

ツール起動時にiniファイルの文字列を各タブの名前に設定する方法が軽くググっても出てこなかったのですが、「Form1_Load」イベントに下記のように記述するとうまくいきました。

private void Form1_Load(object sender, EventArgs e)
{
    // iniファイルを扱うクラスのインスタンスを生成
    nifileUtils ini = new InifileUtils();

    // iniファイルからタブ名を読み込んで設定
    tabControl1.TabPages[0].Text = ini.getValueString("Tab0", "Text");
    tabControl1.TabPages[1].Text = ini.getValueString("Tab1", "Text");
    tabControl1.TabPages[2].Text = ini.getValueString("Tab2", "Text");
}


タブコントロールにはページをいくつも増やせるため、各ページの情報はコレクションの形で格納されているようです。なので TabPages[0] のようにindexを指定した上で .Text と続けてやればタブのボタン部分の文字列のプロパティにアクセスできました。

以上、色々と詰まったところなどでした。