• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C# 画面の描画制御に関して)

C# 画面の描画制御に関して

このQ&Aのポイント
  • C#の画面描画制御について、ボタンの表示/非表示や描画順位に関する問題が発生しています。
  • ボタンA群を一括で表示/非表示させることはできましたが、描画順位の制御ができません。
  • BeginUpdate()やEndUpdate()のような制御が望ましいですが、親フォームでは使用できません。

質問者が選んだベストアンサー

  • ベストアンサー
  • zzz_sheep
  • ベストアンサー率21% (36/166)
回答No.3

挙げて戴いたボタンを201個に増やした環境で試してみました。 仰られる通り、Visibleをtrueにした場合のみダダダっと順に表示されますね。 ただ、個人的な意見を言わせて頂けるなら、 これほどボタンが多いFormを作るのであれば カスタムコントロールを自作した方が良いと思います。 ◆理由◆ .Net Reflector http://www.atmarkit.co.jp/fdotnet/tools/dotfuscator/dotfuscator_02.html などの逆アセンブリツールで中身を見ると、 Buttonコントロールは以外と大きいコントロールです。 大きい=リソースを食うということなので、 たくさん載せる=メモリの余裕がなくなってしまいます。 出来合いのコントロールであるButtonクラスは確かに使いやすいですが、実際に我々が使用しないであろうイベントなどが実装されている為、無駄にメモリを食ってしまうのです。 ◆Sample ///using, Designer 部は省略 namespace test { public class MyButton { string _text; Point _location; Size _size; bool _visible; public MyButton() { _location = new Point(); _size = new Size(); } public string Text { get { return _text; } set { _text = value; } } public Point Location { get { return _location; } set { _location = value; } } public Size MySize { get { return _size; } set { _size = value; } } public bool Visible { get { return _visible; } set { _visible = value; } } public int Left { get { return _location.X; } } public int Top { get { return _location.Y; } } public int Right { get { return _location.X + _size.Width; } } public int Bottom{ get { return _location.Y + _size.Height; } } } public class MyButtonControl : Control { MyButton[] btnAr = new MyButton[201]; public MyButtonControl() { Dock = DockStyle.Fill; SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); UpdateStyles(); for(int i = 0; i < btnAr.Length; i++) { btnAr[i] = new MyButton(); btnAr[i].Location = new Point((int)(i / 30) * 100, 20 * (i % 30) + 2); btnAr[i].MySize = new System.Drawing.Size(100, 20); btnAr[i].Text = i == btnAr.Length - 1 ? "表示切替" : "ボタン" + i.ToString(); btnAr[i].Visible = true; } } public MyButton[] BtnArray { get { return btnAr; } set { btnAr = value; } } private void VisibleCtrl( object sender, EventArgs e ) { Rectangle clip = new Rectangle(btnAr[0].Location, btnAr[0].MySize); for(int i = 0; i < btnAr.Length - 1; i++) { btnAr[i].Visible = !btnAr[i].Visible; if(btnAr[i].Left < clip.Left) clip.X = btnAr[i].Left; if(btnAr[i].Top < clip.Top) clip.Y = btnAr[i].Top; if(clip.Right < btnAr[i].Right) clip.Width += btnAr[i].MySize.Width; if(clip.Bottom < btnAr[i].Bottom) clip.Height += btnAr[i].MySize.Height; } Invalidate(clip); } void DrawButton( Graphics g, MyButton btn, Brush back, Brush fore, Pen pen, StringFormat sf ) { Rectangle rect = Rectangle.FromLTRB(btn.Left + 1, btn.Top + 1, btn.Right - 1, btn.Bottom - 1); if(btn.Visible) { g.DrawRectangle(pen, rect); g.FillRectangle(back, new Rectangle(rect.Left + 1, rect.Top + 1, rect.Width - 1, rect.Height - 1)); g.DrawString(btn.Text, Font, fore, rect, sf); } } protected override void OnPaint( PaintEventArgs e ) { Rectangle clip = e.ClipRectangle; Graphics g = e.Graphics; SuspendLayout(); using(Pen pen = new Pen(ForeColor)) { StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; Brush fore = new SolidBrush(SystemColors.WindowText); Brush back = new SolidBrush(SystemColors.Window); for (int i = 0; i < btnAr.Length; i++) { MyButton btn = btnAr[i]; // 一部が描画領域に含まれるもの if((btn.Left < clip.Left && clip.Left < btn.Right) || (btn.Top < clip.Top && clip.Top < btn.Bottom) || (btn.Left < clip.Right && btn.Right < clip.Right) || (btn.Top < clip.Bottom && btn.Bottom < clip.Bottom)) { DrawButton(g, btn, back, fore, pen, sf); } // 全部が描画領域に含まれるもの else if(clip.Left <= btn.Left && btn.Right <= clip.Right && clip.Top <= btn.Top && btn.Bottom <= clip.Bottom) { DrawButton(g, btn, back, fore, pen, sf); } } } ResumeLayout(false); } protected override void OnMouseClick( MouseEventArgs e ) { base.OnMouseClick(e); Point pos = e.Location; MyButton btn = btnAr[btnAr.Length - 1]; if( (btn.Left <= pos.X && pos.X <= btn.Right) && (btn.Top <= pos.Y && pos.Y <= btn.Bottom)) VisibleCtrl(null, EventArgs.Empty); } } public partial class Form1 : Form { MyButtonControl con; public Form1() { InitializeComponent(); con = new MyButtonControl(); this.Controls.Add(con); } } }

suzuki-_-
質問者

お礼

サンプルまで載せて頂きありがとうございます これだと一瞬で消えますね! まさに望んでいた描画精度です >これほどボタンが多いFormを作るのであれば >カスタムコントロールを自作した方が良いと思います。 色々試している過程で壁にあたった問題だったので、 実際このような膨大な数になることはないと思いますが、 通常のボタンコントロールだと色々と無理があると言うこともわかったので、 今後の為にリソース対応も含め、カスタムコントロールについても 頂いたサンプルとともに学んでいきたいと思います どうもありがとうございました!

その他の回答 (2)

  • zzz_sheep
  • ベストアンサー率21% (36/166)
回答No.2

補足で戴いたコードを試してみました。 >この方法だと、各ボタンの描画順位に基づいて、 >優先的に、順番に表示されていくのが視覚的にわかります とのことですが、 こちらの環境では視覚的にわかりません。 そう言われればそんな気がしないでもないけど・・・、というぐらいの気にならないレベルです。 私がSetStyleメソッドの使用で描画が変わった!と感じたことは 巨大なListViewを載せたFormでしか経験がないのですが、 戴いたコードで使用するなら以下のような感じになると思います。 public Form1() { InitializeComponent(); EnableDoubleBuffering(); } public void EnableDoubleBuffering() { this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); this.UpdateStyles(); } private void VisibleCtrl(object sender, EventArgs e) { SuspendLayout(); for (int i = 0; i < 10; i++) { btnAr[i].Visible = !btnAr[i].Visible; } ResumeLayout(false); } ちなみにこちらの環境では、 やる前とやった後の違いがわかりませんでした(ノ∀`;)アチャー

suzuki-_-
質問者

お礼

試してみましたが解消されませんでした。。。 >こちらの環境では視覚的にわかりません。 >そう言われればそんな気がしないでもないけど・・・、というぐらいの気にならないレベルです。 グラフィックボードやメモリの関係でしょうか 非表示の時はパッと消えるんですが、表示の際は0からダダダダっと、 個別に描画しているのがわかるという状態です ボタンを増やすとzzz_sheepさんの環境でも実感できるかもしれません //InitializeComponent()内フォームのサイズを変更 this.ClientSize = new System.Drawing.Size(700, 600); //ボタン関係 private Button[] btnAr = new Button[201]; private void Form1_Load(object sender, EventArgs e) { for (int i = 0; i < btnAr.Length; i++) { btnAr[i] = new Button(); btnAr[i].Location = new Point((int)(i / 30) * 100, 20 * (i % 30) + 2); btnAr[i].Name = "Button" + i.ToString(); btnAr[i].Size = new System.Drawing.Size(100, 20); btnAr[i].TabIndex = i + 1; btnAr[i].Text = i == btnAr.Length-1 ? "表示切替" : "ボタン" + i.ToString(); if (i == btnAr.Length - 1) btnAr[i].Click += VisibleCtrl; this.Controls.Add(btnAr[i]); } } //表示-非表示の切替関数 private void VisibleCtrl(object sender, EventArgs e) { SuspendLayout(); for (int i = 0; i < btnAr.Length-1; i++) { btnAr[i].Visible = !btnAr[i].Visible; } ResumeLayout(false); } // 引き続き色々と試してみたいと思います わざわざテストして頂きありがとうです!

  • zzz_sheep
  • ベストアンサー率21% (36/166)
回答No.1

this.SuspendLayout(); for (int i = 0; i < 10; i++) { btnAr[i].Visible = !btnArray[i].Visible; } this.ResumeLayout(false); ではできないでしょうか? 上記で無理だったら、 FormのSetStyleメソッドを使えばなんとかなるのかなぁ?^^;

suzuki-_-
質問者

お礼

アドバイスありがとうございます 質問後色々調べてたところSuspendLayout()とResumeLayout(false)に辿りついたのですが、 やはり順に表示されていくのがわかってしまう状態でした zzz_sheepさんのSetStyleという言葉を聞き色々調べているのですが、 知識不足から理解に至たらず、まだ解決していません。。。 補足のほうへ簡潔にまとめた内容を記述させて頂きましたので、 よろしければ再度アドバイスいただければ幸いです 補足の内容は新規プロジェクト作成からWindowsアプリケーションで、 Form1.cs以外(Program.cs Form1.Designer.cs)を削除し、 From1.csのみに記述して実行させています

suzuki-_-
質問者

補足

using System; using System.Drawing; using System.ComponentModel; using System.Windows.Forms; namespace Test { public class Form1 : Form { private Container components = null; public Form1() { InitializeComponent(); } protected override void Dispose(bool disposing) { if (disposing) if (components != null) components.Dispose(); base.Dispose(disposing); } #region Windows フォーム デザイナで生成されたコード private void InitializeComponent() { this.AutoScaleBaseSize = new System.Drawing.Size(5, 12); this.ClientSize = new System.Drawing.Size(292, 266); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); } #endregion [STAThread] static void Main() { Application.Run(new Form1()); } private Button[] btnAr = new Button[11]; private void Form1_Load(object sender, EventArgs e) { for (int i = 0; i < 11; i++) { btnAr[i] = new Button(); btnAr[i].Location = new Point((int)(i / 10) * 100, 20 * (i % 10) + 2); btnAr[i].Name = "Button" + i.ToString(); btnAr[i].Size = new System.Drawing.Size(100, 20); btnAr[i].TabIndex = i + 1; btnAr[i].Text = i == 10 ? "表示切替" : "ボタン" + i.ToString(); if (i == 10) btnAr[i].Click += VisibleCtrl; this.Controls.Add(btnAr[i]); } } private void VisibleCtrl(object sender, EventArgs e) { for (int i = 0; i < 10; i++) { btnAr[i].Visible = !btnAr[i].Visible; } } } }

関連するQ&A