プログラムのお仕事をしていると、レイアウトだとかデザインといったものが後回しにされがちです。
ですが、実際に仕事で使う人(エンドユーザですね)にしてみれば
「中でどう動こうが知ったこっちゃない!それよりこのごちゃごちゃした画面何とかしてくれ!」
ってのが大半だったりします。(いやいや、内部の動きも知ってほしいんですけど(^_^;))もっとも、作るほうもごちゃごちゃした画面はキライです
時間はかかるしバグはできやすいしテスト項目多いし・・・
機能はシンプルに!ロジックは安定性を!ソースコードのコメントでケンカするな!(最後のはスルーで)
で、愚痴はここまで。
小さな画面で小さなプログラムを作っていると、どうしてもひとつのボタンに複数の機能を割り振らないと
スペース的にどうにもならん!ってことがあります
(アイコン画像+説明がセットで一個のボタン。みたいな)
でもそれ、一個一個手でグラフィック作ってたら気が遠くなりますし
画像ファイルの総数もバカバカ増えていき、
アイコン部分と文字部分を分けて作っても今度はプログラムがごちゃごちゃしていくという・・・
で、おいら自身ひどい仕様書のせいで死亡寸前な目にあったので
CompactFrameworkで動的にボタンに文字を描画するコントロールを作りました
イメージとしてはこんな感じです(貰った仕様書は文字のみの手書きでもっと難読化済み・・・)
左側の□はアイコン画像で、右側に文字を動的に描画します。
背景の黒部分が全体のサイズとなるので、アイコン部分、文字部分共に一個のボタンとして動作可能です。
通常のFrameworkならこんなことしなくても比較的楽にできますが、
CompactなのでPaint部分をオーバーライドして、ええ、コンパクトなもんで・・・
using System; using System.Linq; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; namespace TestButton { //文字表示機能付きボタンコントロール public class Button2 : System.Windows.Forms.Control { // プライベート メンバ private Image image; //表示したい画像を設定 private Point point; //画像の表示位置を設定 private Color color; //文字色を設定 private bool bPushed; // ボタンが押されたかどうかの状態を示すフラグ private Bitmap m_bmpOffscreen; //描画用のBitmap public Image Image { get { return image; } set { image = value; } } public Point Point { get { return point; } set { point = value; } } public Color Color { get { return color; } set { color = value; } } public Button2() { bPushed = false; // 既定の最小サイズ(あまり小さいとデザイン画面で行方不明に・・・) this.Size = new Size(21, 21); } protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { Graphics gxOff; // 画面上に表示されない画像 Rectangle imgRect; // 画像用の四角形 Brush backBrush; // 背景を設定するためのブラシ if (m_bmpOffscreen == null) // Dバッファリング用のビットマップ { m_bmpOffscreen = new Bitmap(ClientSize.Width, ClientSize.Height); } gxOff = Graphics.FromImage(m_bmpOffscreen); gxOff.Clear(this.BackColor); if (bPushed) //ボタンプッシュの判定 { // ボタンが押されたときも背景はそのまま。 backBrush = new SolidBrush(Color.Black); } else { backBrush = new SolidBrush(Parent.BackColor); } gxOff.FillRectangle(backBrush, this.ClientRectangle); if (image != null) { // コントロールの中央に画像を設定します。 int imageLeft = (this.Width - image.Width) / 2; int imageTop = (this.Height - image.Height) / 2; if (bPushed) { // ボタンが押された場合。 // 画像を 2 ピクセル移動します。 imgRect = new Rectangle(imageLeft + 2, imageTop + 2, image.Width, image.Height); } else { imgRect = new Rectangle(imageLeft, imageTop, image.Width, image.Height); } // 透過キーを設定します。 //フォーム自体の背景色が可変になっていたり、ボタンとしての背景色が一定でなかったりすると //四角い枠がそのまま出てきます。もっとも、そう表示したいのであれば透過は不要です ImageAttributes imageAttr = new ImageAttributes(); imageAttr.SetColorKey(BackgroundImageColor(image), BackgroundImageColor(image)); // 画像を描画します。 gxOff.DrawImage(image, imgRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, imageAttr); } if (bPushed) // ボタンが押された場合。押したという枠を出す { // 四角形を準備します。 Rectangle rc = this.ClientRectangle; rc.Width--; rc.Height--; // 四角形を描画します。 gxOff.DrawRectangle(new Pen(Color.Black), rc); } // メモリ内にあるビットマップから描画します。 e.Graphics.DrawImage(m_bmpOffscreen, 0, 0); Brush bBrush = new SolidBrush(Color); float x = Point.X; float y = Point.Y; if (bPushed) // ボタンが押された場合。 { x = x + 2; y = y + 2; } e.Graphics.DrawString(this.Text, this.Font, bBrush, x, y); base.OnPaint(e); } protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) { base.OnPaintBackground(e); } private Color BackgroundImageColor(Image image) { //透過色を左上ピクセルとしています Bitmap bmp = new Bitmap(image); return bmp.GetPixel(0, 0); } protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e) { bPushed = true; this.Invalidate(); } protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e) { bPushed = false; this.Invalidate(); } } }
描画の順番としては
最上:文字
中間:イメージ画像
最下:背景色
になっているので、グラフィックツール等で立体的なボタンイメージを作り
その上に動的に文字を描画するという使い方が一番メインでないかと
改めて見直すと、もうちょっとシンプルに作れるような気もしますが
ま、いっかъ( ゜ー^)♪
このへん参考です
http://msdn.microsoft.com/ja-jp/library/aa446518.aspx