C# プログラムの反応の改善

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
derok
記事: 51
登録日時: 12年前

C# プログラムの反応の改善

#1

投稿記事 by derok » 10年前

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;

namespace TestForm {
    static class Program {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form2());
        }
    }
    public class Form2 : Form {
        PictureBox Edit;
        TextBox WidthNum;
        int BackXNum = 1;
        public Form2() {
            Edit = new PictureBox();
            Edit.BackColor = Color.Black;
            WidthNum = new TextBox();
            WidthNum.TextChanged += Num_TextChanged;
            WidthNum.Location = new Point(100, 100);
            this.Controls.Add(Edit);
            this.Controls.Add(WidthNum);
            this.Paint += Main_OnPaint;
        }
        private int GetText(TextBox textbox) {
            try {
                int Num = int.Parse(textbox.Text);
                if (Num < 1) {
                    return 1;
                } else {
                    return Num;
                }
            } catch (System.FormatException) {
                return 1;
            }

        }
        private void Num_TextChanged(object sender, EventArgs e) {
            Edit.Invalidate();
        }
        private void Main_OnPaint(object sender, PaintEventArgs e) {
            PictureBox Main = this.Edit;
            if (GetText(WidthNum) != BackXNum) {
                Edit.Image = Edit.Image;
                BackXNum = GetText(WidthNum);
            }
            Pen pen = new Pen(Color.White, 2);
            Graphics graphics = this.Edit.CreateGraphics();
            for (int i = 0; i < GetText(WidthNum) + 1; i++) {
                int X = (int)(Main.Width * i/ GetText(WidthNum));
                graphics.DrawLine(pen, (int)X, 0, (int)X, Main.Height);
            }
            pen.Dispose();
        }
    }
}
テキストボックスの書かれた数字の数だけ、picutureBoxを線で分割するプログラムなんですが、
入力した後マウスを動かさなければpictureBoxに反映されません。
どうやらPaintイベントが発生してないようなのですが、一体どうやったら発生させることができるのでしょうか?
Main_OnPaint関数や、Num_TextChanged関数で再描画させると今度は線が表示されなくなります。
TImerを使って無理矢理再描画させれば問題はなくなるのですが、こんな方法しかないのでしょうか?
追記:
開発環境はVisual Studio Express 2013 for Windows Desktopです。

YuO
記事: 947
登録日時: 14年前
住所: 東京都世田谷区

Re: C# プログラムの反応の改善

#2

投稿記事 by YuO » 10年前

Control.Invalidateは領域を無効化するだけです。
実際に再描画が必要になるまで,描画はなされません。

すぐに描画をしたいのであれば,MSDNにあるようにInvalidate後にUpdateするか,
Invalidate + UpdateのかわりにRefreshメソッドを呼び出します。

sleep

Re: C# プログラムの反応の改善

#3

投稿記事 by sleep » 10年前

FormのPaint処理内でコントロールのGraphicsオブジェクトを生成して描画される方が本当に多いですね。
意図通り表示されるのであれば私はそれでも良いと思うんですけど、なかなか難しいですよね。

32行目を this.Paint から Edit.Paint へ変更
57行目を this.Edit.CreateGraphics() から e.Graphics へ変更

sleep

Re: C# プログラムの反応の改善

#4

投稿記事 by sleep » 10年前

あと、YuOさんのくださってる助言に補足です。

現状、EditのInvalidate()を 呼び出されていますが、
derokさんのプログラムの場合、thisの方で呼び出す必要があります。
(FormのPaint処理しか用意していないため)

なので、48行目で Refresh を呼ぶ場合は、this.Refresh() を呼び出す必要があります。
(その場合、私の書いた修正は必要ありません)

derok
記事: 51
登録日時: 12年前

Re: C# プログラムの反応の改善

#5

投稿記事 by derok » 10年前

>>YuOさん
返答ありがとうございます。
勘違いしてました。
>>sleepさん
助言ありがとうございます。
色々いじってる間に変な感じになってしまって
一応コードです。

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;

namespace TestForm {
    static class Program {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form2());
        }
    }
    public class Form2 : Form {
        PictureBox Edit;
        TextBox WidthNum;
        int BackXNum = 1;
        public Form2() {
            Edit = new PictureBox();
            Edit.BackColor = Color.Black;
            WidthNum = new TextBox();
            WidthNum.TextChanged += Num_TextChanged;
            WidthNum.Location = new Point(100, 100);
            this.Controls.Add(Edit);
            this.Controls.Add(WidthNum);
            this.Paint += Main_OnPaint;
        }
        private int GetText(TextBox textbox) {
            try {
                int Num = int.Parse(textbox.Text);
                if (Num < 1) {
                    return 1;
                } else {
                    return Num;
                }
            } catch (System.FormatException) {
                return 1;
            }

        }
        private void Num_TextChanged(object sender, EventArgs e) {
            this.Refresh();
        }
        private void Main_OnPaint(object sender, PaintEventArgs e) {
            PictureBox Main = this.Edit;
            if (GetText(WidthNum) != BackXNum) {
                Edit.Image = Edit.Image;
                BackXNum = GetText(WidthNum);
            }
            Pen pen = new Pen(Color.White, 2);
            Graphics graphics = this.Edit.CreateGraphics();
            for (int i = 0; i < GetText(WidthNum) + 1; i++) {
                int X = (int)(Main.Width * i / GetText(WidthNum));
                graphics.DrawLine(pen, (int)X, 0, (int)X, Main.Height);
            }
            pen.Dispose();
        }
    }
}

sleep

Re: C# プログラムの反応の改善

#6

投稿記事 by sleep » 10年前

私の補足が誤解を生んでしまった様ですね。申し訳ないです。

私が補足したのは、derokさんのプログラム(Formに設定したPaint処理を呼び出すため)の場合の話なので
コントロールへの描画はコントロールのPaintイベントで行ってください。(その場合はコントロールのRefreshを呼び出してください)

今表示できているかもしれませんが、それは偶然です。
理解して欲しいのは、Formのイベント内でコントロールのCreateGraphicsから返されたGraphicsオブジェクトで描画するということは上書きされてしまう可能性があるということです。
FormのBeginPaintは既に呼び出されていますが、同じクライアント領域の座標にあるコントロールのBeginPaintが上記のGraphicsオブジェクトによる描画より先に呼ばれている保証はありません。運です。
コントロールのBeginPaintが後で呼び出されてしまうと、その段階で上記のGraphicsオブジェクトによる描画はコントロールのWNDCLASSに設定されているhbrBackgroundで上書きされてしまいます。
(今回を例にすると、EditのBackColorのことですが、仮にBackColorに色を設定しなくてもコントロールにはデフォルトでFormのダイアログ背景色(ARGB=(255, 240, 240, 240))が設定されている)

今回偶々コントロールのBeginPaintが先に呼ばれている様ですが
コントロールのBeginPaintが先に呼ばれるか後に呼ばれるかは同期が取れておらず、コードの負荷などによる運なので
コントロールへの描画は、例外なく、確実にコントロールのBeginPaintより後となるコントロールのPaintイベント内で行う必要があります。

修正したプログラムを張っておきます。(コード内にコメントアウトで① ② ③と書いている 3箇所を修正しています)

コード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;

namespace TestForm
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form2());
        }
    }
    public class Form2 : Form
    {
        PictureBox Edit;
        TextBox WidthNum;
        int BackXNum = 1;
        public Form2()
        {
            Edit = new PictureBox();
            Edit.BackColor = Color.Black;
            WidthNum = new TextBox();
            WidthNum.TextChanged += Num_TextChanged;
            WidthNum.Location = new Point(100, 100);
            this.Controls.Add(Edit);
            this.Controls.Add(WidthNum);
            //this.Paint += Main_OnPaint;  //①
            Edit.Paint += Main_OnPaint;
        }
        private int GetText(TextBox textbox)
        {
            try
            {
                int Num = int.Parse(textbox.Text);
                if (Num < 1)
                {
                    return 1;
                }
                else
                {
                    return Num;
                }
            }
            catch (System.FormatException)
            {
                return 1;
            }

        }
        private void Num_TextChanged(object sender, EventArgs e)
        {
            //this.Refresh();  //②
            Edit.Refresh();
        }
        private void Main_OnPaint(object sender, PaintEventArgs e)
        {
            PictureBox Main = this.Edit;
            if (GetText(WidthNum) != BackXNum)
            {
                Edit.Image = Edit.Image;
                BackXNum = GetText(WidthNum);
            }
            Pen pen = new Pen(Color.White, 2);
            //Graphics graphics = this.Edit.CreateGraphics();  //③
            Graphics graphics = e.Graphics;
            for (int i = 0; i < GetText(WidthNum) + 1; i++)
            {
                int X = (int)(Main.Width * i / GetText(WidthNum));
                graphics.DrawLine(pen, (int)X, 0, (int)X, Main.Height);
            }
            pen.Dispose();
        }
    }
}

derok
記事: 51
登録日時: 12年前

Re: C# プログラムの反応の改善

#7

投稿記事 by derok » 10年前

>>sleepさん
いえ、こちらこぞ誤解して申し訳ございません。
丁寧な解説及び訂正してコードありがとうございます。
偶然うまく動いていただけだったのですね。

閉鎖

“C言語何でも質問掲示板” へ戻る