【C#】Windowsフォーム アプリケーションで拡大・縮小ラベルユーザコントロール
今回はWindowsフォーム アプリケーションで前回に作成した角丸コーナーラベルを使用して拡大、縮小するラベルっぽいものを作りたいと思います。
プロパティで指定した基準点(左上、左下、中央、右上、右下)から拡大、縮小します。
TableLayoutPanelを利用してそれっぽくというか力技で拡大、縮小しています。速度を求める場合はしっかり計算してレンダリングし直した方が良いでしょう。
using System; using System.Drawing; using System.Windows.Forms; namespace ZoomingSample { /// <summary> /// ダブルバッファクラス /// </summary> public class DoubleBuffer : IDisposable { #region メンバ変数 /// <summary> /// ダブルバッファリングオブジェクト /// </summary> private BufferedGraphics _Buffer = null; /// <summary> /// バッファリングを行うコントロール /// </summary> private Control _Control = null; #endregion #region プロパティ /// <summary> /// グラフィックオブジェクト /// </summary> public Graphics Graphics { get { return this._Buffer.Graphics; } } #endregion #region コンストラクタ /// <summary> /// クラスの新しいインスタンスを初期化します。 /// </summary> /// <param name="control">バッファリングを行うコントロール</param> public DoubleBuffer(Control control) { this.Dispose(); var currentContext = BufferedGraphicsManager.Current; this._Buffer = currentContext.Allocate(control.CreateGraphics(), control.DisplayRectangle); if (this._Control != null) { this._Control.Paint += new System.Windows.Forms.PaintEventHandler(this.Paint); } } #endregion #region デストラクタ /// <summary> /// デストラクタ /// </summary> ~DoubleBuffer() { Dispose(); } #endregion #region publicメソッド /// <summary> /// 解放処理を行います。 /// </summary> public void Dispose() { if (this._Buffer != null) { this._Buffer = null; } if (this._Control != null) { this._Control.Paint -= new System.Windows.Forms.PaintEventHandler(this.Paint); } } /// <summary> /// 更新を行います。 /// </summary> public void Refresh() { if (this._Buffer != null) { this._Buffer.Render(); } } #endregion #region privateメソッド /// <summary> /// 描画処理を行います。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Paint(object sender, PaintEventArgs e) { Refresh(); } #endregion } }
角丸コーナーラベルの実装コードです。
namespace ZoomingSample { partial class RoundCornerLabel { /// <summary> /// 必要なデザイナー変数です。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 使用中のリソースをすべてクリーンアップします。 /// </summary> /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region コンポーネント デザイナーで生成されたコード /// <summary> /// デザイナー サポートに必要なメソッドです。このメソッドの内容を /// コード エディターで変更しないでください。 /// </summary> private void InitializeComponent() { this.pic = new System.Windows.Forms.PictureBox(); ((System.ComponentModel.ISupportInitialize)(this.pic)).BeginInit(); this.SuspendLayout(); // // pic // this.pic.BackColor = System.Drawing.Color.Transparent; this.pic.Dock = System.Windows.Forms.DockStyle.Fill; this.pic.Location = new System.Drawing.Point(0, 0); this.pic.Margin = new System.Windows.Forms.Padding(0); this.pic.Name = "pic"; this.pic.Size = new System.Drawing.Size(200, 150); this.pic.TabIndex = 0; this.pic.TabStop = false; // // RoundCornerLabel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.pic); this.Margin = new System.Windows.Forms.Padding(0); this.Name = "RoundCornerLabel"; this.Size = new System.Drawing.Size(200, 150); ((System.ComponentModel.ISupportInitialize)(this.pic)).EndInit(); this.ResumeLayout(false); } #endregion private System.Windows.Forms.PictureBox pic; } }
using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace ZoomingSample { /// <summary> /// 角丸ラベルユーザコントロール /// </summary> public partial class RoundCornerLabel : UserControl { #region メンバ変数 /// <summary> /// ダブルバッファクラス /// </summary> private DoubleBuffer _DoubleBuffer = null; /// <summary> /// コントロールに関連付けられたテキスト /// </summary> private string _DisplayText = ""; /// <summary> /// 文字列の配置 /// </summary> private ContentAlignment _TextAlign = ContentAlignment.MiddleCenter; /// <summary> /// コーナーの角丸のサイズ(直径) /// </summary> private int _CornerR = 10; /// <summary> /// コーナーの線の太さ /// </summary> private int _PenWidth = 5; /// <summary> /// コーナーの線の色 /// </summary> private Color _CornerColor = Color.Blue; /// <summary> /// 矩形内の背景色 /// </summary> private Color _InnerColor = SystemColors.Window; #endregion #region プロパティ /// <summary> /// コントロールに関連付けられたテキスト /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールに関連付けられたテキストです。")] public string DisplayText { get { return this._DisplayText; } set { this._DisplayText = value; Refresh(); } } /// <summary> /// コントロールに表示される文字列の配置 /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールに表示される文字列の配置です。")] public ContentAlignment TextAlign { get { return this._TextAlign; } set { this._TextAlign = value; Refresh(); } } /// <summary> /// 角の丸さ /// </summary> [Browsable(true)] [Category("表示")] [Description("角の丸さを指定します。(半径)")] public int CornerR { get { return (int)(this._CornerR / 2); } set { if (0 < value) { this._CornerR = value * 2; } else { // 0以下が設定された場合、強制的に1にする this._CornerR = 1; } //RenewPadding(); Refresh(); } } /// <summary> /// 枠線の色 /// </summary> [Browsable(true)] [Category("表示")] [Description("外枠の色を指定します。")] public Color CornerColor { get { return this._CornerColor; } set { this._CornerColor = value; Refresh(); } } /// <summary> /// 枠線の幅を指定します。 /// </summary> [Browsable(true)] [Category("表示")] [Description("枠線の太さを指定します。")] public int PenWidth { get { return this._PenWidth; } set { if (0 <= value) { this._PenWidth = value; } else { // 0以下が指定された場合、強制的に0にする this._PenWidth = 0; } //RenewPadding(); Refresh(); } } /// <summary> /// コントロールの矩形内の背景色 /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールの矩形内の背景色を指定します。")] public Color InnerColor { get { return this._InnerColor; } set { this._InnerColor = value; Refresh(); } } #endregion #region コンストラクタ /// <summary> /// クラスの新しいインスタンスを初期化します。 /// </summary> public RoundCornerLabel() { InitializeComponent(); // コントロールのサイズが変更された時にPaintイベントを発生させる SetStyle(ControlStyles.ResizeRedraw, true); SetStyle(ControlStyles.SupportsTransparentBackColor, true); // ピクチャボックスでダブルバッファを行うようにインスタンス生成 this._DoubleBuffer = new DoubleBuffer(this.pic); this.BackColor = Color.Transparent; } #endregion #region override /// <summary> /// PaintBackground イベントを発生させます。 /// </summary> /// <param name="e">イベント引数</param> protected override void OnPaintBackground(PaintEventArgs e) { // バックグランドの描画を行うとWhiteの挿入がされるため // 何もしないようにする } /// <summary> /// Load イベントを発生させます。 /// </summary> /// <param name="e">イベント引数</param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); } /// <summary> /// Paint イベントを発生させます。 /// </summary> /// <param name="e">イベント引数</param> protected override void OnPaint(PaintEventArgs e) { Draw(e.Graphics); } #endregion #region private /// <summary> /// 描画を行います。 /// </summary> /// <param name="g">グラフィックオブジェクト</param> private void Draw(Graphics g) { // 描画品質設定 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; // 背景用のImageオブジェクトを作成する var backrect = new Rectangle(0, 0, this.Width, this.Height); var backColor = this.Parent != null ? this.Parent.BackColor : SystemColors.Control; using (var brush = new SolidBrush(backColor)) { g.FillRectangle(brush, backrect); } using (var cornerPen = new Pen(this._CornerColor, this._PenWidth)) { // 変数初期化 var harfPenWidth = GetHarfPenWidth(); // ペンとブラシ初期化 var offset = this._PenWidth; var rect = new Rectangle(offset, offset, this.Width, this.Height); using (var brush = new SolidBrush(this._InnerColor)) using (var graphPath = new GraphicsPath()) { graphPath.AddArc(harfPenWidth, harfPenWidth, this._CornerR, this._CornerR, 180, 90); graphPath.AddArc(this.Width - this._CornerR - harfPenWidth, harfPenWidth, this._CornerR, this._CornerR, 270, 90); graphPath.AddArc(this.Width - this._CornerR - harfPenWidth, this.Height - this._CornerR - harfPenWidth, this._CornerR, this._CornerR, 0, 90); graphPath.AddArc(harfPenWidth, this.Height - this._CornerR - harfPenWidth, this._CornerR, this._CornerR, 90, 90); graphPath.CloseFigure(); // パス塗り g.FillPath(brush, graphPath); // ペンの太さが1以上なら外枠描画 if (0 < this._PenWidth) { g.DrawPath(cornerPen, graphPath); } } // テキストが設定されている場合は文字を書く var size = new Size(this.Width - offset * 2, this.Height - offset * 2); var fontSize = CalcFontSize(this._DisplayText, size, g); if (fontSize <= 0) { fontSize = 0.1F; } var font = new Font(this.Font.Name, fontSize); var stringFormat = new StringFormat(); var num = (Int32)System.Math.Log((Double)this._TextAlign, 2); stringFormat.LineAlignment = (StringAlignment)(num / 4); stringFormat.Alignment = (StringAlignment)(num % 4); // 文字描画用のブラシを生成する using (var foreColorBrush = new SolidBrush(this.ForeColor)) { // 微妙に右にずれるため-3して補正する rect.X = rect.X - 3; g.DrawString(this._DisplayText, font, foreColorBrush, rect, stringFormat); } } } /// <summary> /// Paddingサイズを更新します。 /// </summary> private void RenewPadding() { var harfCornerR = (int)(this._CornerR / 2); var adjust = (int)(System.Math.Cos(45 * System.Math.PI / 180) * harfCornerR); this.Padding = new Padding(harfCornerR + this._PenWidth + 2 - adjust); } /// <summary> /// コーナー線の幅の1/2の値を取得します。 /// </summary> /// <returns>コーナー線の幅の1/2の値</returns> private int GetHarfPenWidth() { return (int)System.Math.Floor((double)(this._PenWidth) / 2 + 0.5); } /// <summary> /// 指定されたグラフィックオブジェクトに描画する最適なフォントサイズを算出します。 /// </summary> /// <param name="str">出力する文字列</param> /// <param name="size">サイズ</param> /// <param name="g">描画するグラフィックオブジェクト</param> /// <returns>フォントサイズ</returns> private float CalcFontSize(string str, Size size, Graphics g) { var s = new SizeF(0.1F, 0.1F); var a = 0.1F; var b = 0.1F; if (!string.IsNullOrEmpty(str)) { s = g.MeasureString(str, new Font(this.Font.Name, 1)); a = (size.Width / s.Width); b = (size.Height / s.Height); } return (a < b) ? a : a; } #endregion } }
拡大、縮小ラベルの実装コードです。拡大、縮小時に割込みをブロックしていません。実際に利用する場合は拡大中、縮小中か判定して処理の割込みはしないよう考慮した方が良いでしょう。
namespace ZoomingSample { partial class ZoomingLabel { /// <summary> /// 必要なデザイナー変数です。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 使用中のリソースをすべてクリーンアップします。 /// </summary> /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region コンポーネント デザイナーで生成されたコード /// <summary> /// デザイナー サポートに必要なメソッドです。このメソッドの内容を /// コード エディターで変更しないでください。 /// </summary> private void InitializeComponent() { this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); this.SuspendLayout(); // // tableLayoutPanel // this.tableLayoutPanel.BackColor = System.Drawing.Color.Transparent; this.tableLayoutPanel.ColumnCount = 3; this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel.Font = new System.Drawing.Font("メイリオ", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128))); this.tableLayoutPanel.Location = new System.Drawing.Point(0, 0); this.tableLayoutPanel.Margin = new System.Windows.Forms.Padding(0); this.tableLayoutPanel.Name = "tableLayoutPanel"; this.tableLayoutPanel.RowCount = 3; this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); this.tableLayoutPanel.Size = new System.Drawing.Size(400, 300); this.tableLayoutPanel.TabIndex = 0; // // ZoomingLabel // this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 28F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Transparent; this.Controls.Add(this.tableLayoutPanel); this.Font = new System.Drawing.Font("メイリオ", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(128))); this.Margin = new System.Windows.Forms.Padding(0); this.Name = "ZoomingLabel"; this.Size = new System.Drawing.Size(400, 300); this.ResumeLayout(false); } #endregion private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; } }
using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace ZoomingSample { /// <summary> /// 拡大縮小ラベルユーザコントロール /// </summary> public partial class ZoomingLabel : UserControl { #region Enum定義 /// <summary> /// 拡大するときの方向を示す定義 /// </summary> public enum ZoomDirection { /// <summary> /// 右下方向(左上を基準点にして拡大します) /// </summary> RightDown = 0, /// <summary> /// 右上方向(左下を基準点にして拡大します) /// </summary> RightUp = 1, /// <summary> /// 左下方向(右上を基準点にして拡大します) /// </summary> LeftDown = 2, /// <summary> /// 左上方向(右下を基準点にして拡大します) /// </summary> LeftUp = 3, /// <summary> /// 全方向(中心点を基準点にして拡大します) /// </summary> AllSide = 4 } #endregion #region メンバ変数 /// <summary> /// コントロールに関連付けられたテキスト /// </summary> private string _DisplayText = ""; /// <summary> /// 文字列の配置 /// </summary> private ContentAlignment _TextAlign = ContentAlignment.MiddleCenter; /// <summary> /// コーナーの角丸のサイズ(直径) /// </summary> private int _CornerR = 10; /// <summary> /// コーナーの線の太さ /// </summary> private int _PenWidth = 5; /// <summary> /// コーナーの線の色 /// </summary> private Color _CornerColor = Color.Blue; /// <summary> /// 矩形内の背景色 /// </summary> private Color _InnerColor = SystemColors.Window; /// <summary> /// 拡大を行う方向 /// </summary> /// <remarks>デフォルトは中心点から全方向拡大</remarks> private ZoomDirection _Direction = ZoomDirection.LeftDown; /// <summary> /// テーブルレイアウトパネルの縮小・拡大時の刻み幅 /// </summary> private float _PitchWidth = 0.0F; /// <summary> /// テーブルレイアウトパネルの縮小・拡大時の刻み高さ /// </summary> private float _PitchHeight = 0.0F; /// <summary> /// テーブルレイアウトパネルの元の幅 /// </summary> private float _OriginalWidth = 0.0F; /// <summary> /// テーブルレイアウトパネルの元の高さ /// </summary> private float _OriginalHeight = 0.0F; /// <summary> /// 拡大・縮小時のアニメーションの更新間隔 /// </summary> private int _AnimationInterval = 1; /// <summary> /// 拡大・縮小で利用するタイマー /// </summary> private Timer _ZoomTimer; #endregion #region プロパティ /// <summary> /// コントロールに関連付けられたテキスト /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールに関連付けられたテキストです。")] public string DisplayText { get { return this._DisplayText; } set { this._DisplayText = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// コントロールに表示される文字列の配置 /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールに表示される文字列の配置です。")] public ContentAlignment TextAlign { get { return this._TextAlign; } set { this._TextAlign = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// 矩形内の背景色 /// </summary> [Browsable(true)] [Category("表示")] [Description("コントロールの矩形内の背景色を取得または設定します。")] public Color InnerColor { get { return this._InnerColor; } set { this._InnerColor = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// 角の丸さ /// </summary> [Browsable(true)] [Category("表示")] [Description("角の丸さを指定します。(半径)")] public int CornerR { get { return this._CornerR; } set { this._CornerR = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// 枠線の色 /// </summary> [Browsable(true)] [Category("表示")] [Description("外枠の色を指定します。")] public Color ConerColor { get { return this._CornerColor; } set { this._CornerColor = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// 枠線の幅を指定します。 /// </summary> [Browsable(true)] [Category("表示")] [Description("枠線の太さを指定します。")] public int PenWidth { get { return this._PenWidth; } set { this._PenWidth = value; SetRoundCornerLabel(); this.Refresh(); } } /// <summary> /// 拡大時の方向を指定します。 /// </summary> [Browsable(true)] [Category("表示")] [Description("拡大時の方向を指定します。")] public ZoomDirection Direction { get { return this._Direction; } set { this._Direction = value; CreateTebleLayout(); this.Refresh(); } } /// <summary> /// 拡大・縮小時のアニメーションの更新間隔を指定します。 /// </summary> [Browsable(true)] [Category("動作")] [Description("拡大・縮小時のアニメーションの更新間隔を指定します。")] public int AnimationInterval { get { return this._AnimationInterval; } set { this._AnimationInterval = value; } } #endregion #region コンストラクタ /// <summary> /// コンストラクタ /// </summary> public ZoomingLabel() { InitializeComponent(); this.BackColor = Color.Transparent; this.tableLayoutPanel.BackColor = SystemColors.Control; this.DoubleBuffered = true; // 元の角丸ラベルユーザコントロールのサイズを保持しておく this._OriginalWidth = this.Width / 2; this._OriginalHeight = this.Height / 2; CreateTebleLayout(); CalcPitch(); } #endregion #region override /// <summary> /// Load イベントを発生させます。 /// </summary> /// <param name="e"></param> protected override void OnLoad(EventArgs e) { base.OnLoad(e); } /// <summary> /// FontChanged イベントを発生させます。 /// </summary> /// <param name="e"></param> protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); SetRoundCornerLabel(); this.Refresh(); } /// <summary> /// BackColorChanged イベントを発生させます。 /// </summary> /// <param name="e"></param> protected override void OnBackColorChanged(EventArgs e) { base.OnBackColorChanged(e); this.tableLayoutPanel.BackColor = this.BackColor; this.Refresh(); } /// <summary> /// Resize イベントを発生させます。 /// </summary> /// <param name="e"></param> protected override void OnResize(EventArgs e) { base.OnResize(e); // 元の角丸ラベルユーザコントロールのサイズを保持しておく this._OriginalWidth = this.Width / 2; this._OriginalHeight = this.Height / 2; CreateTebleLayout(); CalcPitch(); } #endregion #region public /// <summary> /// 指定された方向へ拡大処理を行います。 /// </summary> /// <remarks>拡大済の場合、それ以上大きくはならない</remarks> public void ZoomIn() { this._ZoomTimer = new Timer(); this._ZoomTimer.Interval = _AnimationInterval; this._ZoomTimer.Tick += new EventHandler(this.ZoomInTimer_Tick); this._ZoomTimer.Enabled = true; } /// <summary> /// 拡大時の処理を行います。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ZoomInTimer_Tick(object sender, EventArgs e) { var control = this.tableLayoutPanel.Controls[0] as RoundCornerLabel; var h1 = 0.0F; var w1 = 0.0F; var h2 = 0.0F; var w2 = 0.0F; var col1 = 0; var row1 = 0; var col2 = 0; var row2 = 0; if (this._Direction == ZoomDirection.RightDown) { // 左上基準、右下方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[1].Height - this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[1].Width - this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[0].Height + this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[0].Width + this._PitchWidth; row1 = 1; col1 = 1; } else if (this._Direction == ZoomDirection.RightUp) { // 左下基準、右上方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[0].Height - this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[1].Width - this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[1].Height + this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[0].Width + this._PitchWidth; row2 = 1; col1 = 1; } else if (this._Direction == ZoomDirection.LeftDown) { // 右上基準、左下方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[1].Height - this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[0].Width - this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[0].Height + this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[1].Width + this._PitchWidth; row1 = 1; col2 = 1; } else if (this._Direction == ZoomDirection.LeftUp) { // 右下基準、左上方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[0].Height - this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[0].Width - this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[1].Height + this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[1].Width + this._PitchWidth; row2 = 1; col2 = 1; } else { h1 = this.tableLayoutPanel.RowStyles[0].Height - 0.5F; w1 = this.tableLayoutPanel.ColumnStyles[0].Width - 0.5F; h2 = this.tableLayoutPanel.RowStyles[1].Height + 0.5F; w2 = this.tableLayoutPanel.ColumnStyles[1].Width + 0.5F; } // コントロールのサイズ以上となった場合、Timerを停止し拡大を終える if ((this.Width <= w2 || this.Height <= h2) || (w1 <= 0 || h1 <= 0)) { this._ZoomTimer.Enabled = false; this._ZoomTimer.Tick -= this.ZoomOutTimer_Tick; return; } if (this._Direction != ZoomDirection.AllSide) { this.tableLayoutPanel.RowStyles[row1].Height = h1; this.tableLayoutPanel.ColumnStyles[col1].Width = w1; this.tableLayoutPanel.RowStyles[row2].Height = h2; this.tableLayoutPanel.ColumnStyles[col2].Width = w2; } else { this.tableLayoutPanel.RowStyles[0].Height = h1; this.tableLayoutPanel.RowStyles[1].Height = h2; this.tableLayoutPanel.RowStyles[2].Height = h1; this.tableLayoutPanel.ColumnStyles[0].Width = w1; this.tableLayoutPanel.ColumnStyles[1].Width = w2; this.tableLayoutPanel.ColumnStyles[2].Width = w1; } } /// <summary> /// 指定された逆方向へ縮小処理を行います。 /// </summary> /// <remarks>拡大時のみ縮小される。元のコントロールのサイズより小さくはならない</remarks> public void ZoomOut() { this._ZoomTimer = new Timer(); this._ZoomTimer.Interval = _AnimationInterval; this._ZoomTimer.Tick += new EventHandler(this.ZoomOutTimer_Tick); this._ZoomTimer.Enabled = true; } /// <summary> /// 縮小時の処理を行います。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ZoomOutTimer_Tick(object sender, EventArgs e) { var control = this.tableLayoutPanel.Controls[0] as RoundCornerLabel; var h1 = 0.0F; var w1 = 0.0F; var h2 = 0.0F; var w2 = 0.0F; var col1 = 0; var row1 = 0; var col2 = 0; var row2 = 0; if (this._Direction == ZoomDirection.RightDown) { // 左上基準、右下方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[1].Height + this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[1].Width + this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[0].Height - this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[0].Width - this._PitchWidth; row1 = 1; col1 = 1; } else if (this._Direction == ZoomDirection.RightUp) { // 左下基準、右上方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[0].Height + this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[1].Width + this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[1].Height - this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[0].Width - this._PitchWidth; row2 = 1; col1 = 1; } else if (this._Direction == ZoomDirection.LeftDown) { // 右上基準、左下方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[1].Height + this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[0].Width + this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[0].Height - this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[1].Width - this._PitchWidth; row1 = 1; col2 = 1; } else if (this._Direction == ZoomDirection.LeftUp) { // 右下基準、左上方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[0].Height + this._PitchHeight; w1 = this.tableLayoutPanel.ColumnStyles[0].Width + this._PitchWidth; h2 = this.tableLayoutPanel.RowStyles[1].Height - this._PitchHeight; w2 = this.tableLayoutPanel.ColumnStyles[1].Width - this._PitchWidth; row2 = 1; col2 = 1; } else { // 中央基準点、全方向拡大の場合 h1 = this.tableLayoutPanel.RowStyles[0].Height + 0.5F; w1 = this.tableLayoutPanel.ColumnStyles[0].Width + 0.5F; h2 = this.tableLayoutPanel.RowStyles[1].Height - 0.5F; w2 = this.tableLayoutPanel.ColumnStyles[1].Width - 0.5F; } // コントロールの元のサイズ以下となった場合、Timerを停止し縮小を終える if (control.Width <= this._OriginalWidth || control.Height <= this._OriginalHeight) { this._ZoomTimer.Enabled = false; this._ZoomTimer.Tick -= this.ZoomInTimer_Tick; return; } if (this._Direction != ZoomDirection.AllSide) { this.tableLayoutPanel.RowStyles[row1].Height = h1; this.tableLayoutPanel.ColumnStyles[col1].Width = w1; this.tableLayoutPanel.RowStyles[row2].Height = h2; this.tableLayoutPanel.ColumnStyles[col2].Width = w2; } else { this.tableLayoutPanel.RowStyles[0].Height = h1; this.tableLayoutPanel.RowStyles[1].Height = h2; this.tableLayoutPanel.RowStyles[2].Height = h1; this.tableLayoutPanel.ColumnStyles[0].Width = w1; this.tableLayoutPanel.ColumnStyles[1].Width = w2; this.tableLayoutPanel.ColumnStyles[2].Width = w1; } } #endregion #region private /// <summary> /// 拡大縮小を行うためのテーブルレイアウトを構築します。 /// </summary> private void CreateTebleLayout() { this.tableLayoutPanel.SuspendLayout(); this.tableLayoutPanel.Controls.Clear(); this.tableLayoutPanel.RowStyles.Clear(); this.tableLayoutPanel.ColumnStyles.Clear(); var control = CreateRoundCornerLabel(); if (this._Direction == ZoomDirection.RightDown) { // 左上基準点、右下方向拡大の場合 this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.Controls.Add(control, 0, 0); } else if (this._Direction == ZoomDirection.RightUp) { // 左下基準点、右上方向拡大の場合 this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.Controls.Add(control, 0, 1); } else if (this._Direction == ZoomDirection.LeftDown) { // 右上基準点、左下方向拡大の場合 this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.Controls.Add(control, 1, 0); } else if (this._Direction == ZoomDirection.LeftUp) { // 右下基準点、左上方向拡大の場合 this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, this._OriginalWidth)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, this._OriginalHeight)); this.tableLayoutPanel.Controls.Add(control, 1, 1); } else { // 中央基準点、全方向拡大の場合 var width = 25F; var height = 25F; this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, width)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); this.tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, width)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, height)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F)); this.tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, height)); control.Dock = DockStyle.Fill; this.tableLayoutPanel.Controls.Add(control, 1, 1); } if (this._Direction != ZoomDirection.AllSide) { control.Dock = DockStyle.Fill; } this.tableLayoutPanel.ResumeLayout(); } /// <summary> /// 角丸ラベルユーザコントロールを生成します。 /// </summary> private RoundCornerLabel CreateRoundCornerLabel() { var control = new RoundCornerLabel(); control.DisplayText = this._DisplayText; control.CornerColor = this._CornerColor; control.CornerR = this._CornerR; control.ForeColor = this.ForeColor; control.Font = this.Font; control.BackColor = this.tableLayoutPanel.BackColor; control.InnerColor = this._InnerColor; control.PenWidth = this._PenWidth; control.TextAlign = this._TextAlign; control.Width = (int)this._OriginalWidth; control.Height = (int)this._OriginalHeight; control.Padding = new Padding(0); return control; } /// <summary> /// 角丸ラベルユーザコントロールのプロパティを変更します。 /// </summary> private void SetRoundCornerLabel() { if (this.tableLayoutPanel.Controls.Count == 0) { return; } var control = this.tableLayoutPanel.Controls[0] as RoundCornerLabel; if (control == null) { return; } control.DisplayText = this._DisplayText; control.CornerColor = this._CornerColor; control.CornerR = this._CornerR; control.ForeColor = this.ForeColor; control.Font = this.Font; control.BackColor = this.tableLayoutPanel.BackColor; control.InnerColor = this._InnerColor; control.PenWidth = this._PenWidth; control.TextAlign = this._TextAlign; control.Width = (int)this._OriginalWidth; control.Height = (int)this._OriginalHeight; } /// <summary> /// 拡大縮小時のピッチの計算を行います。 /// </summary> private void CalcPitch() { // 拡大縮小を行う単位を算出する var gcd = Gcd(this.Width, this.Height); var size = CalcAspect(this.Width, this.Height); this._PitchHeight = size.Height; this._PitchWidth = size.Width; } /// <summary> /// 引数のサイズからアスペクト比を算出します。 /// </summary> /// <param name="w">横の解像度</param> /// <param name="h">縦の解像度</param> /// <returns>アスペクト比</returns> private SizeF CalcAspect(int w, int h) { // 最大公約数を求める var gcd = Gcd(w, h); if (gcd == 1) { gcd = 100; } var result = new SizeF(); result.Width = (float)this.Width / (float)gcd; result.Height = (float)this.Height / (float)gcd; return result; } /// <summary> /// 最大公約数を求めます。 /// </summary> /// <param name="w">横の解像度</param> /// <param name="h">縦の解像度</param> /// <returns></returns> private int Gcd(int w, int h) { if (w < h) { return Gcd(h, w); } while (h != 0) { var remainder = w % h; w = h; h = remainder; } return w; } #endregion } }
Windowsフォーム アプリケーションでも工夫と頑張りでアニメーションっぽい処理もそれなりにできますが、やっぱりWPFの方が楽ですね…。
枯れてきたWindowsフォーム アプリケーションを使いたいって要件もまだそこそこありますので、参考になればと思います。