今回はレイヤーに読み込まれた画像を拡大したり縮小できるようにします。実際にビットマップを縮小してからもう一度拡大すると劣化した画像しか表示されないのでLayerクラスのBitmapプロパティは最初のオリジナル画像を保存しておき、表示サイズだけ変更するようにします。
こうなるとLayerクラスの既存のプロパティを変更するか新しいプロパティを作成する必要がありそうです。
前回、LayerクラスにWidthプロパティとHeightプロパティを作成しましたが、これはビットマップの幅と高さをそのまま返しているだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class Layer { // 他のプロパティは省略しています。 public int Width { get { if(Bitmap == null) return 0; else return Bitmap.Width; } } public int Height { get { if(Bitmap == null) return 0; else return Bitmap.Height; } } } |
最初はこれでいいとしてレイヤーのサイズを変更したときは別の値を設定できるようにしたほうがよさそうです。
BitmapプロパティがセットされたときはWidthプロパティとHeightプロパティはビットマップの幅と高さを返しますが、あとで任意の値に変更することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class Layer { [XmlIgnore] public Bitmap Bitmap { get { return bitmap; } set { bitmap = value; if(value != null) { Height = value.Height; Width = value.Width; } else { Height = 0; Width = 0; } } } Bitmap bitmap = null; public int Width { get; set; } public int Height { get; set; } } |
レイヤーを管理するためにFormManagementLayerクラスとダイアログを作成します。左側にあるのはツリービューです。右にあるのはピクチャーボックスです。
ここでも選択されたものがなにかわかるようにイメージをとなりのピクチャーボックスに表示させています。また左上の座標と幅、高さを変更することができるようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public partial class FormManagementLayer : Form { public List<Layer> Layers = null; public FormManagementLayer() { InitializeComponent(); treeView1.BeforeSelect += TreeView1_BeforeSelect; treeView1.AfterSelect += TreeView1_AfterSelect; numericUpDownX.Maximum = 10000; numericUpDownX.Minimum = -10000; numericUpDownY.Maximum = 10000; numericUpDownY.Minimum = -10000; numericUpDownWidth.Maximum = 10000; numericUpDownHeight.Maximum = 10000; numericUpDownWidth.ValueChanged += NumericUpDownWidth_ValueChanged; numericUpDownHeight.ValueChanged += NumericUpDownHeight_ValueChanged; checkBox1.CheckedChanged += CheckBox1_CheckedChanged; radioButtonHeight.CheckedChanged += RadioButtonHeight_CheckedChanged; radioButtonWidth.CheckedChanged += RadioButtonWidth_CheckedChanged; radioButtonWidth.Checked = true; radioButtonWidth.Enabled = false; radioButtonHeight.Enabled = false; buttonOK.DialogResult = DialogResult.OK; buttonCancel.DialogResult = DialogResult.Cancel; buttonOK.Click += ButtonOK_Click; } } |
ダイアログが表示されるときにツリービューにレイヤーの名前を挿入します。またアイテムが選択されたときにどのレイヤーが選択されているのかわかるようにTreeNode.Tagプロパティにレイヤーに関する情報をセットしています。
LayerInfoクラスを作成しているのは縦横の比率を維持したままサイズを変更することができるようにするためです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public partial class FormManagementLayer : Form { public class LayerInfo { public LayerInfo(Layer layer) { Layer = layer; OldWidth = layer.Width; OldHeight = layer.Height; } public Layer Layer = null; public int OldWidth = 0; public int OldHeight = 0; } private void FormManagementLayer_Load(object sender, EventArgs e) { if(Layers != null) { foreach(Layer layer in Layers) { TreeNode node = new TreeNode(layer.Name); LayerInfo info = new LayerInfo(layer); node.Tag = info; treeView1.Nodes.Add(node); } } } } |
ツリービューのアイテムが選択されたら対応するレイヤーの画像を表示させるとともにX座標とY座標、幅、高さを表示させます。またこれまで選択されていたレイヤーにはNumericUpDownコントロールで設定された値をセットします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public partial class FormManagementLayer : Form { private void TreeView1_AfterSelect(object sender, TreeViewEventArgs e) { TreeNode node = e.Node; if(node != null) { LayerInfo info =(LayerInfo)node.Tag; Layer layer = info.Layer; // NumericUpDown.Maximum NumericUpDown.Minimum を超えた値を取得したときの対策 if(numericUpDownX.Maximum < layer.X) numericUpDownX.Maximum = layer.X; if(numericUpDownX.Minimum > layer.X) numericUpDownX.Minimum = layer.X; if(numericUpDownY.Maximum < layer.Y) numericUpDownY.Maximum = layer.Y; if(numericUpDownY.Minimum > layer.Y) numericUpDownY.Minimum = layer.Y; if(numericUpDownWidth.Maximum < layer.Width) numericUpDownWidth.Maximum = layer.Width; if(numericUpDownHeight.Maximum < layer.Height) numericUpDownHeight.Maximum = layer.Height; numericUpDownX.Value = layer.X; numericUpDownY.Value = layer.Y; numericUpDownWidth.Value = layer.Width; numericUpDownHeight.Value = layer.Height; pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; pictureBox1.Image = layer.Bitmap; } } private void TreeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e) { TreeNode node = treeView1.SelectedNode; if(node != null) { LayerInfo info = (LayerInfo)node.Tag; Layer layer = info.Layer; layer.X = (int)numericUpDownX.Value; layer.Y = (int)numericUpDownY.Value; layer.Width = (int)numericUpDownWidth.Value; layer.Height = (int)numericUpDownHeight.Value; } } } |
縦横の比を維持したままサイズ変更をするためにはnumericUpDownWidthとnumericUpDownHeightのValueプロパティが変化したときに適切な値を設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public partial class FormManagementLayer : Form { private void NumericUpDownHeight_ValueChanged(object sender, EventArgs e) { TreeNode node = treeView1.SelectedNode; if(node != null && checkBox1.Checked && radioButtonHeight.Checked) { LayerInfo info = (LayerInfo)node.Tag; int height = (int)numericUpDownHeight.Value; int width = height * info.OldWidth / info.OldHeight; numericUpDownWidth.Value = width; } } private void NumericUpDownWidth_ValueChanged(object sender, EventArgs e) { TreeNode node = treeView1.SelectedNode; if(node != null && checkBox1.Checked && radioButtonWidth.Checked) { LayerInfo info = (LayerInfo)node.Tag; int width = (int)numericUpDownWidth.Value; int height = width * info.OldHeight / info.OldWidth; numericUpDownHeight.Value = height; } } } |
また縦横の比を維持したままサイズ変更する場合は片方のNumericUpDownコントロールを無効にする必要があります。そこでラジオボタンの状態が変更されたらNumericUpDownコントロールの有効無効を切り替えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public partial class FormManagementLayer : Form { private void CheckBox1_CheckedChanged(object sender, EventArgs e) { radioButtonWidth.Enabled = checkBox1.Checked; radioButtonHeight.Enabled = checkBox1.Checked; numericUpDownWidth.Enabled = !checkBox1.Checked || radioButtonWidth.Checked; numericUpDownHeight.Enabled = !checkBox1.Checked || radioButtonHeight.Checked; } private void RadioButtonWidth_CheckedChanged(object sender, EventArgs e) { if(checkBox1.Checked) { numericUpDownWidth.Enabled = radioButtonWidth.Checked; numericUpDownHeight.Enabled = !radioButtonWidth.Checked; } } private void RadioButtonHeight_CheckedChanged(object sender, EventArgs e) { if(checkBox1.Checked) { numericUpDownWidth.Enabled = !radioButtonHeight.Checked; numericUpDownHeight.Enabled = radioButtonHeight.Checked; } } } |
メニューで[レイヤーの情報を編集する]が選択されたらダイアログを表示させます。[OK]がクリックされたらFormManagementLayer.Layersの値をForm1.Layersにセットします。最後にPictureBox.Invalidate()メソッドを呼んで再描画させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form1 : Form { private void LayerInfoMenuItem_Click(object sender, EventArgs e) { FormManagementLayer form = new FormManagementLayer(); form.Layers = Layers.ToList(); if(form.ShowDialog() == DialogResult.OK) { Layers = form.Layers; pictureBox1.Invalidate(); } form.Dispose(); } } |
PictureBox.Invalidate()メソッドが呼ばれるとイベントハンドラpictureBox1_Paintが実行されます。pictureBox1_Paintのなかでは変更されたレイヤーの情報を参照して再描画をしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public partial class Form1 : Form { private void pictureBox1_Paint(object sender, PaintEventArgs e) { List<Layer> layers = Layers.ToList(); layers.Reverse(); foreach(Layer layer in layers) { if(layer.Bitmap != null) { Rectangle srcRect = new Rectangle(new Point(0, 0), new Size(layer.Bitmap.Width, layer.Bitmap.Height)); Rectangle destRect = new Rectangle(new Point(layer.X, layer.Y), new Size(layer.Width, layer.Height)); e.Graphics.DrawImage(layer.Bitmap, destRect, srcRect, GraphicsUnit.Pixel); } } } } |