- PR -

画面に大量にテキストを描画すると遅くなることは防げますか?

投稿者投稿内容
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-19 11:13
皆さん、こんにちは。
また困ってしまいましたので質問させてください。

C#に限った話ではないですが
例えば、WindowsFormに一行100文字 X 10000行文もの
文字をDrawStringするとかなりおそくなります。
分かりにくいので具体的にこんなイメージです。
フォームのPaintイベントで(あくまでイメージです)
----
private void xxxxPaint(object sender, PaintEventArgs e){
Graphics g = e.Graphics;
for(int i=1; i<=10000; i++){
g.DrawString(.....);
}
g.Dispose();
}
----
Paintイベントなので頻繁に実行されます、画面がちらついきますし
かくかくとした動きになります。ダブルバッファという方法をどこかで
よんだことがありますが、やったとしてもこの場合は変わらない気がします。

何かいい方法がありませんでしょうか?
皆さん、お力をお貸しください
よろしくお願いします。


ちなみになぜこんなことをするかですが
テキストエディターコントロールを作りたいです。
Windowsの既存のものを拡張するのではなくゼロに近い状態から
作りたいです。
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-19 11:53
どなたか、テキストエディターの動作の仕組みをご存知の方
居られませんか?

実際画面に表示しきれないほどの量の文字の場合、
スクロールできるって見せかけているだけで
実際の表示は画面に見える範囲だけなのでしょうか?
スクロールしたときだけ必要な部分を取り出してやはり見える分
だけ表示ですかね?
それなら、大きいサイズのファイルでも一瞬の間表示できてしまっても
納得できますね。

どうなんでしょうか?

mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2003-08-19 23:20
こんばんは、meiです。

引用:

CHNさんの書き込み (2003-08-19 11:13) より:
かくかくとした動きになります。ダブルバッファという方法をどこかで
よんだことがありますが、やったとしてもこの場合は変わらない気がします。



取りあえず、ダブルバッファの例です。
コード:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

	/// <summary>
	/// Form1 の概要の説明です。
	/// </summary>
public class Form1 : System.Windows.Forms.Form {
	/// <summary>
	/// 必要なデザイナ変数です。
	/// </summary>
	private System.ComponentModel.Container components = null;

	private bool mode = false;
	private Bitmap bmp;

	public Form1() {
		InitializeComponent();
		Rectangle r = System.Windows.Forms.Screen.PrimaryScreen.Bounds;
		bmp = new Bitmap(r.Width, r.Height);
	}

	protected override void Dispose( bool disposing ) {
		if( disposing ) {
			if (components != null) {
				components.Dispose();
			}
		}
		base.Dispose( disposing );
	}

	protected override void OnPaint(PaintEventArgs e) {
		Cursor = Cursors.WaitCursor;
		Graphics g = e.Graphics;
		if (mode) {
			// ダブルバッファモードの場合はビットマップを描画するだけ
			g.DrawImage(bmp, 0, 0);
		}
		else {
			// 通常は毎回描画する
			DrawTest(g, Brushes.Blue);
		}		
		Cursor = Cursors.Arrow;
		base.OnPaint (e);
	}

	// 描画関数
	private void DrawTest(Graphics g, Brush b) {
		string s = "あいうえお";
		float w = g.MeasureString(s, Font).Width;
		for (int i = 0; i < 1000; ++i) 
			for (int j = 0; j < 20; ++j)
				g.DrawString(s, Font, b, w * j, i * Font.Height);
	}

	// バッファへの描画を行う
	private void SetupBitmap() {
		Graphics g = Graphics.FromImage(bmp);
		DrawTest(g, Brushes.Red);
		g.Dispose();
	}

	// ダブルクリックでモード変更
	private void Form1_DoubleClick(object sender, System.EventArgs e) {
		mode = !mode;
		if (mode) {
			Cursor = Cursors.WaitCursor;
			SetupBitmap();
			Cursor = Cursors.Arrow;
		}
		this.Invalidate();
	}

	#region Windows フォーム デザイナで生成されたコード 
	/// <summary>
	/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
	/// コード エディタで変更しないでください。
	/// </summary>
	private void InitializeComponent() {
		// 
		// Form1
		// 
		this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
		this.ClientSize = new System.Drawing.Size(292, 266);
		this.Name = "Form1";
		this.Text = "Form1";
		this.DoubleClick += new System.EventHandler(this.Form1_DoubleClick);

	}
	#endregion

	[STAThread]
	static void Main() {
		Application.Run(new Form1());
	}
}



↑ダブルクリックするとモードが切り替わります。
青は通常モード、赤はダブルバッファモードです。
モードを切り替えて、ウィンドウサイズを変更させて再描画を起こすと、
ダブルバッファの効果が見えると思います。

引用:

実際画面に表示しきれないほどの量の文字の場合、
スクロールできるって見せかけているだけで
実際の表示は画面に見える範囲だけなのでしょうか?
スクロールしたときだけ必要な部分を取り出してやはり見える分
だけ表示ですかね?


そうだと思います。

ただ、本当にメモリ上に一画面分しか持っていないと、
メモリへの読み込みが頻繁になりパフォーマンスが悪くなるので、
何ページ分かは読み込んでいるとは思います。
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-20 00:15
こんばんは、meiさん
ご返事いただき誠にありがとうございます。
ご丁寧にサンプルまで付けてくださって、いや〜サンクスです。

サンプルをためさせて頂きました。さすがにダブルバッファにすると
かなりパフォーマンスが改善されるようですね。使う価値ありますね。

エディターコントロールの作成はやはり工夫が必要なようですね、
ファイルの内容すべてを無効領域が発生するたびに
描画し直すのは無理がありますね。(ダブルバッファを使っても)
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-08-20 09:51
ども、ほむらです。
-------------------
今の常識はちとわかりませんが昔の方法を説明すると
全てメモリ上での作業、全書き込みが基本です。

ただし。
スクロールなどの書き込み作業時、描画矩形を指定してい
不必要な部分は描画しない形になっているはずです。
(不定形ウィンドウの作り方や更新領域の指定について調べてみるとでてくるかと)

むかし。MFCでエディタを作ろうと思ったときの
ソースがみつかればよいのですが。。。

# エディタを作るのならリッチエディットコントロールを改造したほうがいいような。。。
# カレットの制御がかなり厳しいです><

# 以下 追記
# 全書き込みというのは嘘でした><
# クライアント座標の原点から1ページ分しかかいてなかったっす
# 原点はGetClipBox()とか言う関数で調べていました。
# C#だとgetClip()???

[ メッセージ編集済み 編集者: ほむら 編集日時 2003-08-20 12:35 ]
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-21 08:58
ほむらさん、こんにちは。
そして、お返事ありがとうございます。

本当に便利でなんでもできるやつをやろうと思ったら
リッチエディットを改造ではなくてすべて自作した方が
いいと思います。勉強にもなりますから。

アドバイスありがとうございます。
大変参考になります
またよろしくお願いします。
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-22 09:58
すいません、もうひとつご教授願いたいことがありまして

エディターで文字を選択するが可能ですよね。文字選択すると
バックの色が変わって選択していることがわるようになります。
これってどういう仕組みでしょうか?長方形を書いてからその上に
文字を書いて選択したって見せてるんでしょうか?
くだらないことですが、以外と考えてみるとあれ?どういう風に
やっているんだろう...って思いました。

よろしくお願いします。
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-08-23 03:20
ども、ほむらです。
作ったことはありませんが普通に背景の色を指定して
文字を書いているだけでは?

強調表現の関係で文字単位で書き込みをしているかと思いますし。。

スキルアップ/キャリアアップ(JOB@IT)