そらのうきぶくろ

Blog - Permalink

ゆとりでもできる!C#15分クッキング

あらすじ
うちがMacのAlfredというコマンドランチャのカスタムサーチ機能を使ってALCで検索できるようにしたところ、横で見ていた友人が「うわーそれWindowsにもほしー!」と言ってたので、うちが「こんな機能1時間もありゃ自作できるんじゃね?」と思い立ったが吉日、実際にやってみることにしたら、基本機能が15分で仕上がったので、改めてC#のゆとりっぷりを再確認したのであった。

というあらすじはまぁどうでもよくて、とりあえずこんな感じのプログラムを作る方法を順を追って説明していくつもりだよ。
多分、プログラミングなんて全然知らない人でもできるはずだよ。

Enterキーか送信ボタンを押すと、既定のWebブラウザが開き、ALCで単語検索をした結果が表示される。
これが基本的な機能である。

作ってみる
まずはゆとり言語の最先端を行くVisual C# 2010 Expressをマイクロソフトのページから無料でダウンロードし、インストールをしておこう!
話はそれからだ。

インストールが完了したら早速実行!


新しいプロジェクトをクリック、で全てが始まる!


Windows フォーム アプリケーションがデフォルトで選ばれてるのでそれはそのままにして、自分だけのアプリの名前を考えて下に入力してOKをクリックだ!
場所:で、今から作るソフトの保存先を指定できるので、デフォルトの保存先が不満なら適当に変えておくといいね!


すると、こんなお絵かきソフトみたいな画面になる!
ここに、ペタペタと必要部品を貼っていくことにしよう!
左のツールボックスで配置したい部品を選択し、画面中央のフォーム上でマウスの左ボタンをドラッグ&ドロップすると、部品が配置されていくようになっている!簡単だ!
配置した部品やフォームの大きさは、部品やフォームを選択した時に周りに出てくる□をドラッグ&ドロップすることで変更できるぞ!


さて、配置できたはいいが、label1やbutton1では何がなんだか訳が分からない!
そこで登場するのが画面右下にある「プロパティ」ウィンドウだ!

「プロパティ」ウィンドウでは、現在選択している部品のプロパティ(property: 特性・性質といった意味)を設定できる!
例を挙げると、ボタンの上に表示されている文字だとか、ボタンの大きさだとか、フォームの場合は最大化ボタンを表示するかどうか、等々、あらゆる設定を行える!
というわけで、今回は次のように設定したぞ!

Form1(フォーム):
AcceptButton: button1
FormBorderStyle: FixedSingle
MaximizeBox: False
MinimizeBox: False
StartPosition: CenterScreen
Text: “アルクで検索するソフト”
label1(ラベル):
Text: “単語:”
textBox1(テキストボックス):
特に何も変更していない
button1(ボタン):
Text: “送信”

さて、一つずつ詳しく解説していくと大変なので、一つずつ簡単に解説することにしよう!
AcceptButtonは、フォーム上でEnterキーを押すと「押したことになるボタン」を設定することができるのだ!
Windowsを使っていて、何かの設定ダイアログ等が開いたとき、いちいちOKボタンの上にカーソルを移してクリックしている人もいるかもしれないが、大抵の場合OKボタンはここでいう所のAcceptButtonに指定されており、Enterキーを押すだけでOKボタンを押したことになる!豆知識だよ。
FormBorderStyleは、フォームの外見の設定だ!あと、プログラムの実行中にユーザーが勝手にフォームのサイズを変えられるかどうかの設定も含まれている!FixedSingleはフォームのサイズが固定という意味だよ!
MaximizeBoxやMinimizeBoxは、それぞれ最大化ボタンと最小化ボタンを表示するかの設定だ!このプログラムにはそんなものは必要ないのでFalse(偽、プロパティにこれが設定されていると大抵「無効」の意味になる)にさせてもらった!
StartPositionは、プログラムを実行した時にフォームが画面のどこに表示されるかを強制的に指定できる!左上とかに出てくるのも癪なので常に画面中央に出てくるように設定してみたぞ!


さて……何だか今にも動き出しそうな気がする外観になった!
しかし残念ながら現時点では1行も命令を書いていないので何も動くわけがないのだ!
ではいよいよコーディングの作業に入るが、何も身構える必要はない!ゆとり言語だからな!
画面上の送信ボタンをダブルクリックしてみよう!


ゴチャゴチャうるせー感じの画面が表示されるはずだ!
private void button1_Click(object sender, EventArgs e)の中カッコ内に、「ボタンがクリックされた時何をするか」の命令を書いていくことにする!

このプログラムの基本機能は、Enterキーか送信ボタンを押すと、既定のWebブラウザが開き、ALCで単語検索をした結果が表示される。というものだった。
でも……既定のWebブラウザを開いて、更に検索まで勝手にやらせるなんて、そんなやり方さっぱりわかんねーよ!ゆとりに分かるわけないだろ、カスゴミが!
そう思ったあなたは、まず「分からない事はGoogleで検索する」ということを覚えよう!
それがC#上達への近道だ!

そうだなー、ひとまず、C# ブラウザ URL 開くとでも検索してみれば良いんじゃないかな?

検索結果のサイトの情報によると、既定のWebブラウザを開いて指定したURLを表示するには、

System.Diagnostics.Process.Start("[URL]");

と1行書くだけで良いらしい!なるほど!今知ったぜ!
というわけで早速そのサンプルソースをコピー&ペーストだ!

さて、別に勘がよくない方だったとしても、さすがにこのサンプルソースを見れば「Startの次のカッコ内に書いた、”(ダブルクォーテーション)で囲んだURLに飛ぶ」という事くらいは理解できたのではないだろうか!
その認識は大体合ってるけど少し違うのだ!
実は”で囲んだ部分の文字列は「文字列リテラル」と呼び、……あーそんなもん覚えたくねー、めんどくせー、と思うかもしれないが、確かにその通りだ!
手っ取り早く「テキストボックスに入力したURL」をブラウザで表示できるようにするには、こうすればいいのだ!

System.Diagnostics.Process.Start(textBox1.Text);

ここまで書いたら何も考えずにF5キーを押してみよう!
するとプログラムが開始される!


さっきまで絵に描いた餅だったものが、実際にWindowsアプリケーションとして動き出した瞬間だ!


http://www.google.co.jp/と入力し、Enterキーをクリックすると……


なんとGoogleが出てきた!
やったね!
これで全機能の20%くらいは実装完了したといえよう!
とりあえず、実行したプログラム上の×ボタンを押すかShift+F5を押してコード入力画面に戻ろう!

さらっと解説しておくと、textBox1.Textというのは若干語弊はあるが変数であり、テキストボックスに入力されている文字列のことだ!

今度は、「テキストボックスに入力した単語をALCで検索し、その結果をブラウザに表示」させてみることにしよう!
でも「検索」なんて難しそう……だなんて、勝手に思い込んではいないだろうか!
実際に検索してみると、その謎はすぐに解決する。


ALCを開き、試しに何か検索してみよう!

検索結果が表示されるが、結果よりもそのページのURLに注目して欲しい!
例えばhelloを検索したのならば、URLはhttp://eow.alc.co.jp/hello/UTF-8/?ref=saという感じになっている!
ここまで言えば、もうhttp://eow.alc.co.jp/[検索したい単語]/UTF-8/?ref=saを単純にWebブラウザで開けば良いという事に気付くはずだ!
つまり、さっきの命令をこのように書き換えるだけ!

System.Diagnostics.Process.Start("http://eow.alc.co.jp/" + textBox1.Text + "/UTF-8/?ref=sa");

ここで、何だこの記述法は、と思った人がいるかもしれない。
http://eow.alc.co.jp/までが一つの文字列リテラルであり、それとテキストボックスの内容(変数)、もう一つの文字列リテラルである/UTF-8/?ref=saを連結して、URLを動的に生成しているのだ!
某C言語とかいうプログラミング言語では文字の連結という作業はとても厄介なものなのだが、C#ではこのように分かりやすく記述することができるぞ!

さてこれでF5キーを押して実行だ!


調べたい単語を入れ、Enterキーを押すと……


やった!出てきた!
(データの転載は禁じられています、と書いてあったから中身は表示してないけど)

ここまでで基本的な機能は実装できた!
しかし、理想の挙動に近づけるにはまだ足りないものがある!

プログラムを起動すると、普段は隠れているが、何かホットキー(Alt+スペースキー等)を押すとウィンドウが現れ、即座に単語を入力できるようになる。
調べたい単語を送信するとウィンドウはまた隠れる。

こんな感じにしてみたいところだ!
まぁ、落ち着いて、順を追って実装していくことにしよう!

1. プログラムを起動すると、普段は隠れている
現在、ソースコードを書く画面になっていると思うが、これを再び部品配置画面(デザイン画面等と言う)にしよう!
上の方にあるForm1.cs [デザイン]をクリックすると、デザイン画面に戻るぞ!

そこで、フォームの「何も置いてない場所」……タイトルバーあたりをダブルクリックしてみよう!
するとまた性懲りも無くソースコードを入力する画面に戻り、そこにはprivate void Form1_Load(object sender, EventArgs e)と表示されているはずだ!
ここには、プログラムが起動した時(正確には違うんだが)に行う処理を書くことができるぞ!
普段は隠れている状態にしなければならないので、とりあえずプログラム開始時には隠れている状態にすればよい!

C# フォーム 隠す
とでも検索すれば、方法なんてすぐに分かるはずだ!

private void Form1_Load(object sender, EventArgs e)
{
    this.Hide();
}

こう書けば良いのか!なるほど!
と思うかもしれないが、実は違う!
Loadというのは、「読み込んだだけだが、表示はしていない」という時に発生する処理なのだ!
再度デザイナ画面に戻り、フォームの部品が置いてない場所をクリックし、右下のプロパティウィンドウが、Form1を指している事を確認したら、稲妻のアイコンをクリックだ!


するとこんな画面になる!
Shownという項目を探し、ダブルクリックしよう!
すると、Loadの時と同じようにソースコードを書く画面になり、Form1_Shownというものが追加されているので、

private void Form1_Shown(object sender, EventArgs e)
{
    this.Hide();
}

こうしておこう!
ちなみにForm1_Loadの方も後で使うので、カッコの中身は空のまま残しておいてほしい!

2. 何かホットキー(Alt+スペースキー等)を押すとウィンドウが現れ
さて、これはちょっと難しいぞ!
といっても、答えの9割以上はやはりGoogleで検索することで分かる。

C# ホットキー
ほら、出てきたでしょ?

ただし、これは単にコピペするだけじゃエラーが出てしまう!
部分的にコピペする必要がある!

まず最初に、using System.Runtime.InteropServices;をコピペする!
ペーストする場所はどこかというと……ソースコードの上の方にusing~で始まるものが沢山並んでいる場所があると思うが、そこの直後で良い!

次に、using~の直後からprivate void Form1_Load~の直前までを、ソースコード中の

    public partial class Form1 : Form
    {

の直後あたりにコピペする!
これはプログラムというよりは、プログラムに必要な定数や命令の宣言だが、あまり深く考えなくていい!

次に、サンプルソースにはForm1_Load内にRegisterHotKey(~という行があるが、これを先程作ったForm1_Load内にコピペだ!

private void Form1_Load(object sender, EventArgs e)
{
    RegisterHotKey(this.Handle, HOTKEY_ID, MOD_ALT | MOD_SHIFT, (int)Keys.A) ;
}

このような感じになれば良い!

ホットキーというのは、一度登録した後、「後始末」として登録情報を抹消しなければならない!
というわけで、フォームが閉じた時の処理が必要となる!
そこで、一度デザイン画面に戻り……Form1_Shownを追加した時の事を思い出しながら、今度はFormClosedという項目を探し、見つかったらその項目をダブルクリックだ!

すると、Form1_FormClosedというものがソースコードに追加された!
というわけで、その場所にホットキーの登録を抹消する命令をコピペしよう!

private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
    UnregisterHotKey(this.Handle, HOTKEY_ID);
}

あとは、protected override void WndProc~以降を、FormClosedの閉じカッコの直後にペーストするだけ!

さて、ホットキーの登録をコピペで済ませてしまったわけだが、このままだとサンプルソースのAlt+Shift+Aが登録されてしまうので、これをAlt+スペースキーに変更しよう!

RegisterHotKey(this.Handle, HOTKEY_ID, MOD_ALT | MOD_SHIFT, (int)Keys.A);

となっている所を

RegisterHotKey(this.Handle, HOTKEY_ID, MOD_ALT, (int)Keys.Space);

と変更するだけで完了する!
Alt, Shift, Controlは特殊なキーなのでMOD_ALT, MOD_SHIFT, MOD_CONTROLという風に設定する必要があるらしい!
また、その特殊な3つのキーを組み合わせる場合は|(パイプ)を使っているのだが、これは実はOR演算と……あー、めんどくせー、まぁ|で連結すれば良いって覚えればいいんだ!
また、スペースキーを指定する時に(int)Keys.Spaceという特殊な書き方をしているが、これは実はKeysという列挙型……あー、めんどくせー、とりあえず.Spaceを消して.(ドット)打ってみろ!


ソースコードをCtrl+C→Ctrl+Vせず、律儀に手入力していた人は気づいたかもしれないが、このようなリストが開く!
これはマイクロソフトの開発環境にかなり昔からある伝統的な入力補助機能、IntelliSenseというものだ!
カーソルキーの上下で選び、Enterキーかスペースキーを押すことで入力しようとしたものを確定できる優れものだ!すごいぞかっこいいぞー!

さて、ホットキーをAlt+スペースキーにしたところで、後はホットキーが押された時の処理を書くだけだ!
幸いにも/* ホットキーの処理 */というコメントがあるので分かりやすい!その部分に命令を書いていくことにする!

少し前に、this.Hide()という命令でフォームを隠すことにしたが、これの真逆の命令としてthis.Show()というものがある!
つまり、this.Show()を追加してあげれば、それだけで表示されるのだが………

3. 即座に単語を入力できるようになる。
この仕様も同時に満たすために、テキストボックスにフォーカスを与えてやることにする!
よって

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == WM_HOTKEY)
    {
        if ((int)m.WParam == HOTKEY_ID)
        {
            /* ホットキーの処理 */
            this.Show();
            textBox1.Focus();
        }
    }
}

このように書けばOKだ!

4. 調べたい単語を送信するとウィンドウはまた隠れる。
これも極めて簡単!
ボタンを押したとき、つまりbutton1_Clickの処理中に、先ほどのthis.Hide()を追加すれば良いだけだからだ!
ついでに、テキストボックスに入力した内容を綺麗に消去しておこう!
すると

private void button1_Click(object sender, EventArgs e)
{
    System.Diagnostics.Process.Start("http://eow.alc.co.jp/" + textBox1.Text + "/UTF-8/?ref=sa");
    this.Hide();
    textBox1.Text = "";
}

このように書くことができるな!


ここまでの作業を行うと、こんな感じのソースコードができているはずだ!
できていたら、早速F5キーを押して実行!
何も出てこないが、Altを押しながらスペースキーを押すとしっかりウィンドウが出てくることを確認し、更に検索するとウィンドウも閉じていることも確認できたら、とりあえずShift+F5キーでデバッグを終了しよう!

問題点の解決
何度か使ってみると、いくつかの問題点に気がつくのではないだろうか!

1. ホットキーで呼び出したはいいが、やっぱり要らない時、×ボタンを押すとプログラムが終了してしまい、またホットキーを押しても、プログラムを手動で起動するまでは出てこなくなってしまう。
2. ホットキーで呼び出しても画面の最前面に出てくれない。

これも順番に解決していこう!

1の問題は、ホットキーを押した後、呼び出したらそれっきりになってしまっている事が原因だ!
呼び出した後、またホットキーが押されたら隠れるようになれば良いのではないだろうか!
というわけで、ホットキーが押された時に、フォームが表示されているか否かで処理を変えることにしよう!

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == WM_HOTKEY)
    {
        if ((int)m.WParam == HOTKEY_ID)
        {
            /* ホットキーの処理 */
            if (this.Visible)
                this.Hide();
            else
                this.Show();
            textBox1.Focus();
        }
    }
}

ホットキーが押された時、もしフォームが表示されているなら隠し、隠されているなら表示する、たったそれだけの命令だ!

2を解決するのはもっと簡単だ!
上の処理の、textBox1.Focus();の下に、this.Activate();と書くだけ!

あとは、解決したかどうかF5キーを押して試してみるといい!

Form1.csのソースコードは以下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace QuickAlc
{
    public partial class Form1 : Form
    {
        const int MOD_ALT = 0x0001;
        const int MOD_CONTROL = 0x0002;
        const int MOD_SHIFT = 0x0004;
        const int WM_HOTKEY = 0x0312;

        const int HOTKEY_ID = 0x0001;  // 0x0000~0xbfff 内の適当な値でよい
        // 0xc000~0xffff は DLL 用なので 使用不可!
        [DllImport("user32.dll")]
        extern static int RegisterHotKey(IntPtr HWnd, int ID, int MOD_KEY, int KEY);
        // 返り値:  成功 = 0以外,  失敗 = 0(既に他が登録済み)

        [DllImport("user32.dll")]
        extern static int UnregisterHotKey(IntPtr HWnd, int ID);
        // 返り値:  成功 = 0以外,  失敗 = 0
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://eow.alc.co.jp/" + textBox1.Text + "/UTF-8/?ref=sa");
            this.Hide();
            textBox1.Text = "";
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            RegisterHotKey(this.Handle, HOTKEY_ID, MOD_ALT, (int)Keys.Space);
        }
        private void Form1_Shown(object sender, EventArgs e)
        {
            this.Hide();
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            UnregisterHotKey(this.Handle, HOTKEY_ID);
        }
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);

            if (m.Msg == WM_HOTKEY)
            {
                if ((int)m.WParam == HOTKEY_ID)
                {
                    /* ホットキーの処理 */
                    if (this.Visible)
                        this.Hide();
                    else
                        this.Show();
                    textBox1.Focus();
                    this.Activate();
                }
            }
        }
    }
}

はい。上手にできましたー♪


と、このように、C#はプログラムの半分以上がコピペで構成されていても問題なく「完成」する。
しかもC#はオブジェクト指向言語であるにも関わらず、そんな事を一切気にせずともプログラムは「完成」した。とりあえずは。
もちろん、上記のような作り方はプログラミングを本気で勉強したい人はやってはいけない
当然ながら何の勉強にもならないからである。
それでもとりあえずプログラムを作れてしまうあたりが、ゆとり言語C#なんだなぁ……。

ただ、GUIのデザインをする時に「お絵かきソフトのよう」と例えたように、GUIアプリケーションの製作効率は非常に高い。
まずはJavaのCUIベースアプリケーションでまずはオブジェクト指向の何たるかを学んでから、それからGUIアプリケーションを作りたくなってきたな、という時期にC#の習得を始めると効率的にプログラムを作る事ができるのではないかと思う。

あ、ちなみに、この記事を書いた人もまた、平成生まれ・ゆとり世代だよ。うん。どうでもいいか。

プログラミング | 君はコメントしてもいいししなくても良い

ゆとりでもできる!C#15分クッキングへのコメント (0)

コメントを書く


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>