- PR -

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

投稿者投稿内容
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-23 18:53
どうも、お世話になります。

複数ページに渡る文字の選択を実現するのは
結構頭使わないといけないような気もしますね。

mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2003-08-24 01:43
引用:

CHNさんの書き込み (2003-08-22 09:58) より:

エディターで文字を選択するが可能ですよね。文字選択すると
バックの色が変わって選択していることがわるようになります。
これってどういう仕組みでしょうか?お願いします。



何も考えずに実装してみました。
キーボードでシフト押しながらカーソルキーのみ対応です。
参考になるかどうかは怪しいですが・・・

コード:
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class Form1 : Form {
	private Container components = null;
	MyCaret caret;
	string[] lines;
	Point cur;
	Point org;
	bool bSel;

	public Form1() {
		InitializeComponent();

		caret = new MyCaret(this);
		lines = new string[] {
								 "public class MyApp {",
								 "    System.Console.WriteLine(\"Hello,World\");",
								 "}"};
		cur = Point.Empty;
		org = Point.Empty;
		bSel = false;
	}

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

	protected override void OnPaint(PaintEventArgs e) {
		base.OnPaint (e);
		StringFormat fmt = StringFormat.GenericTypographic;
		fmt.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
		for (int i = 0; i < lines.Length; ++i)
			e.Graphics.DrawString(lines[i], Font, new SolidBrush(this.ForeColor), 
				0, Font.Height * i, StringFormat.GenericTypographic);
		if (bSel) {
			DrawSelected(e.Graphics);
		}
	}

	protected override void OnKeyDown(KeyEventArgs e) {
		if (e.Shift) {
			if (!bSel) {
				org = cur;
				bSel = true;
			}
		}
		else {
			org = cur;
			bSel = false;
		}

		switch (e.KeyCode) {
			case Keys.Left:
				if (cur.X > 0) 
					--cur.X;
				else if (cur.Y > 0) {
					--cur.Y;
					cur.X = lines[cur.Y].Length;
				}
				break;
			case Keys.Right:
				if (cur.X < lines[cur.Y].Length)
					++cur.X;
				else if (cur.Y < lines.Length - 1) {
					++cur.Y;
					cur.X = 0;
				}
				break;
			case Keys.Up:
				if (cur.Y > 0) {
					--cur.Y;
					if (cur.X > lines[cur.Y].Length)
						cur.X = lines[cur.Y].Length;
				}
				break;
			case Keys.Down:
				if (cur.Y < lines.Length - 1) {
					++cur.Y;
					if (cur.X > lines[cur.Y].Length)
						cur.X = lines[cur.Y].Length;
				}
				break;
		}
		MoveCaret();
		Invalidate();
	}

	void DrawSelected(Graphics g) {
		Point bgn;
		Point end;

		if (org.Y < cur.Y || org.Y == cur.Y && org.X < cur.X) {
			bgn = org;
			end = cur;
		}
		else {
			bgn = cur;
			end = org;
		}

		int p;
		int q;
		PointF lt = PointF.Empty;
		PointF rb = PointF.Empty;
		for (int i = bgn.Y; i <= end.Y; ++i) {
			lt.Y = i * Font.Height;
			rb.Y = (i + 1) * Font.Height;

			if (i == bgn.Y) { 
				lt.X = CalcWidth(g, lines[i].Substring(0, bgn.X));
				p = bgn.X;
			}
			else { 
				lt.X = 0; 
				p = 0;
			}
			if (i == end.Y) {
				rb.X = CalcWidth(g, lines[i].Substring(0, end.X));
				q = end.X;
			}
			else {
				rb.X = CalcWidth(g, lines[i]);
				q = lines[i].Length;
			}
			g.FillRectangle(Brushes.DarkBlue, lt.X, lt.Y, rb.X - lt.X, rb.Y - lt.Y);
			g.DrawString(lines[i].Substring(p, q - p), Font, new SolidBrush(Color.White), 
				lt.X, lt.Y, StringFormat.GenericTypographic);
		}
	}

	float CalcWidth(Graphics g, string s) {
		StringFormat fmt = StringFormat.GenericTypographic;
		fmt.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
		SizeF size = g.MeasureString(s, Font, Point.Empty, fmt);
		return size.Width;
	}

	void MoveCaret() {
		using (Graphics g = Graphics.FromHwnd(Handle)) {
			float w = CalcWidth(g, lines[cur.Y].Substring(0, cur.X));
			caret.Position = new Point((int)w, Font.Height * cur.Y);
		}
	}

	private void InitializeComponent() {
		this.AutoScaleBaseSize = new System.Drawing.Size(6, 12);
		this.ClientSize = new System.Drawing.Size(292, 266);
		this.Font = new System.Drawing.Font("MS ゴシック", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
		this.Name = "Form1";
		this.Text = "Form1";

	}

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

public class MyCaret {
	[DllImport("user32.dll")]
	public static extern int CreateCaret(IntPtr hwnd, IntPtr hbm, int cx, int cy);
	[DllImport("user32.dll")]
	public static extern int DestroyCaret();
	[DllImport("user32.dll")]
	public static extern int SetCaretPos(int x, int y);
	[DllImport("user32.dll")]
	public static extern int ShowCaret(IntPtr hwnd);
	[DllImport("user32.dll")]
	public static extern int HideCaret(IntPtr hwnd);

	Control ctrl;
	Size	size;
	Point	pos;
	bool	bVisible;

	public MyCaret(Control ctrl) {
		this.ctrl = ctrl;
		Position = Point.Empty;
		Size = new Size(1, ctrl.Font.Height);
		Control.GotFocus += new EventHandler(OnGotFocus);
		Control.LostFocus += new EventHandler(OnLostFocus);

		if (ctrl.Focused)
			OnGotFocus(ctrl, new EventArgs());
	}

	public Control Control {
		get { return ctrl; }
	}

	public Size Size {
		get { return size; }
		set { size = value; }
	}

	public Point Position {
		get { 
			return pos; 
		}
		set { 
			pos = value; 
			SetCaretPos(pos.X, pos.Y);
		}
	}

	public bool Visible {
		get {
			return bVisible;
		}
		set {
			bVisible = value;
			if (bVisible)
				ShowCaret(Control.Handle);
			else
				HideCaret(Control.Handle);
		}
	}

	public void Dispose() {
		if (ctrl.Focused)
			OnLostFocus(ctrl, new EventArgs());
		Control.GotFocus -= new EventHandler(OnGotFocus);
		Control.LostFocus -= new EventHandler(OnLostFocus);
	}

	private void OnGotFocus(object sender, EventArgs e) {
		CreateCaret(Control.Handle, IntPtr.Zero, Size.Width, Size.Height);
		SetCaretPos(Position.X, Position.Y);
		Visible = true;
	}

	private void OnLostFocus(object sender, EventArgs e) {
		Visible = false;
		DestroyCaret();
	}
}



ちょっと長過ぎかな・・・(汗)
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-24 20:17
meiさん、どうもありがとうございます。

私もまさにこんな感じで想像していました、想像だけですが。
折角やっていただきましたのでそそまま使わせて頂きます。

あとはちらつくのをなんとかしたいところですね。
これは何とか自分で調べてやりたいと思います。
これ以上聞くとご迷惑になりますので。

度々、本当にありがとうございました。
wppqqoo
会議室デビュー日: 2003/08/27
投稿数: 3
投稿日時: 2003-08-27 17:43
http://mywebpages.comcast.net/bmenees/index.html
のMeneesDiffUtils をみてみるといい感じかもしれません。
Caret,文字の選択などが実装してあります。
文字の入力ができませんが・・・・

ちらつきですが
コンストラクタに
SetStyle(ControlStyles.DoubleBuffer|
ControlStyles.AllPaintingInWmPaint, true);

を書き加えるとうまくいくと思います。(意味違ってたらゴメンサイ)

エディタならやはり#Developをみるのがイイかと。
しかし#Developは選択領域の反転などしていませんね。(Caretの重なった位置の反転も)

GraphicのClip プロパティーを設定してあげると実装できるとおもわれ。。。。

#この文章呼んでくれるかな・・・
wppqqoo
会議室デビュー日: 2003/08/27
投稿数: 3
投稿日時: 2003-08-27 17:53
RichTextBoxを改造するならこれ
http://www.c-sharpcorner.com/Code/2003/June/ColorSyntaxEditor.asp

よくできてますよw
通常文字を選択するとちらっと 選択したな というのが見えるんですが
WndProcをオーバーライドしてWM_PAINTメッセージが送られてきたときの処理を
ちょっと改造しています。
なかなかおもしろい。。
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-27 19:10
wppqqooさん、こんにちは。

ご親切にありがとうございます。
参考にさせて頂きます。

> RichTextBoxを改造するならこれ

改造は結局どこかで無理をします。つまり不自然になることがあります。
ですのでやはり自作します。コンピュータに慣れればなれるほどテキストが
重要だと思うようになる気がします。勉強も兼ねて作ってみたいと思います。

また何か気付かれたことがありましたらよろしくお願いします。
wppqqoo
会議室デビュー日: 2003/08/27
投稿数: 3
投稿日時: 2003-08-27 20:28
実は私もC#でテキストエディタを作っています。
完成にはほど遠いですが・・・・・・
もしよろしければ一緒に作りませんか?
よろしければメールください。

//C#経験者であればだれでもかまいません

[ メッセージ編集済み 編集者: wppqqoo 編集日時 2003-08-27 20:34 ]
CHN
ぬし
会議室デビュー日: 2002/03/07
投稿数: 382
投稿日時: 2003-08-27 22:05
すごくありがたいことですね。

ご一緒にやらせて頂くとなりますと、多少でも
責任が伴いますよね。私の方は仕事が忙しくなりますと
適当にやるつもりはないですがほったらかしにするつもりです。
ご迷惑をかけることになります。
しかもまだコードを一行も書いてません、というのはやり直しを
嫌がるタイプなので、徹底的に調査してから取り掛かるつもりです。
あと、私が作りたいのはコントロールです。普通のエディタよりも
多くのことを実装しなければなりません。使用者も開発者を想定します。
これはテキストエディタだけを作成される方には関係のないことです。
ご一緒にさせて頂くことは難しいとかもしれません。

ただ、意見交換などは積極的にさせて頂きたいと思います。
今後ともご指導のほどよろしくお願いします。

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