[BlueLeaf1336]> PROBLEMS> SprictEditor>

SprictEditor - What's this?

historyTOP

2004/07/17:作成。
2004/07/17:更新
2004/07/18:更新
2004/07/19:更新

overviewTOP

とうとう手を出すことにします。以前にも何度も撃沈してますが、エディターです。で、普通のエディター作ったところで絶対に、今使っているこのエディター(PeggyPad/アンカーシステムズ)より使い易くなるわけがないので、モチベーションが薄れる可能性も踏まえて、Microsoft Script Control を実行するようなそんな感じにしようかと思っています。

コレは、最近その存在を教えてもらったんですが少し楽しそうです。参考になりそうなリンクを覚え書いておきます。

早くここに辿り着きますように。あ、あとタイトルの「SprictEditor」のつづりは意図的なものです。どう考えても「ScriptEditor」を名乗れるようなものができるわけがないだろう、というとても現実的な羞恥心からあえてこうしています。

PaintBoxで文字列を編集するTOP

さて、早速、脈絡なく思いつくままにススメていきます。まずはエディタの基本的な処理、文字列の編集機能です。まあ、TMemo使えば一撃ですが、いつかは強調表示とかしたいなぁというわけで、自前でやることにします。

コレをやろうとするからすぐに力尽きるわけですが、是非やりたいんです。で、あいもかわらず参考書としては、C Magazine 2003年1月号のプログラムのレシピ 第5回 / C Magazine 2003年2月号のプログラムのレシピ 第6回 です。以降、参考書と呼びます。

まあ、とりあえずは強調表示なんていってられないので、普通に文字列を編集できますか?というところから入っていきます。簡単のために、1行だけで考えることにします。...しばらく沈みます。

2バイト文字を考慮しだして、滅茶苦茶邪魔臭いんですが、今のうちにやらんとだめでしょうねぇやっぱり。しかもその場しのぎでないようなやり方でやるべきな気がしてきました。本当にそこら中ででてくる。カーソル移動や文字の削除や。まぁそんな堅苦しいことはやめて、その場しのぎでいっておきます。こんなところで立ち止まっている場合ではないので。後でしんどいよりもここで飽きてしまう方が嫌なんで。

などと泣き言を言っているうちに、第1弾がこんなんになりました。20040717SprictEditor.zip(3,429bytes)

参考書どおりに、ちゃんとIME変換ウィンドウも表示できているし、HOME/END/Delete/BackSpaceにも何となく対応できているようです。1行だけしか入力できませんが。

ちょっと気になるのがIMEの変換ウィンドウで入力しているときと確定したときで、表示位置が少しだけずれることです。PeggyPad(アンカーシステムズ)だとずれないんですが、xyzzy(ごっつやる気のないぺぇじ)だとずれるんでまぁヨシとします。

横スクロールバーをつけるTOP

次は、横スクロールバーをつけてみます。横です。縦ではありません。ここは重要で、縦だとどう考えてもテキストの行数でつまみの高さを変えたくなりますが、横の場合折返しを実現しない(できそうにないし)なら、もう知らんというぐらい長くしておいてかまわないわけで、結局つまみの幅もデフォルトのままでよさそうと思えてきます。

だいたいからして、1行しか入力できないテストプログラムに縦スクロールバーをつけても仕方がないわけで。多分表示(PaintBox.OnPaint)だけだろうと思ってるんですが、甘いでしょうか?

やってみると、とてもややこしいことがわかりました。それはカーソルの位置です。

じゃないですね。書いていてわかってきましたが、第1弾の描画方法がまずかったようです。2バイト文字の1バイト目は描画せず、2バイト文字の2バイト目を描画する際についでに描画する(1バイトずつ律儀に描画するとへんてこなことになるので)という風にしていたのですが、この方法だと半分だけ見えているという状況でも、2バイト文字の2バイト目なので1バイト目とあわせて描画してしまいます(言葉でいっても何のことやらわかりませんが...)。

「あいS|えお」という文字列を描画する時に(|がカーソル位置とします)、1バイトだけスクロールすると、希望としては「(あの右半分)いS|えお」となってもらいたいわけですが、実際には「あい$えお」となるわけで。とすると最初に書いた「カーソルの位置」には問題がないんですね。頑張ります。

状況を簡単にするために、「MSゴシック 9pt」でやることにします。この組み合わせだといIME変換ウィンドウ入力中と確定後の描画位置にずれが生じません。本当の固定ピッチフォントというわけです。

意外と簡単に解決しました。問題はかっこつけて描画範囲の枝刈り(画面に表示されている位置から文字列描画を開始する)をしていたからでした。今思えば最終的に強調表示するに当たって、予約語などの場合、画面に半分しか表示されていようがいまいが色をつけなければならないわけだから、表示範囲に収まっているかどうかを盛り込むのは技術的に事故りそうな予感がします。で、あっさりとこんな感じになりました。200407172SprictEditor.zip(3,753bytes)

縦スクロールバーもついてますがなーんにも関係ありません。横だけです。ちゃんと半分に切れた2バイト文字の描画もできました。ただ、テキストの編集状況やカーソルの移動に伴って、表示範囲内に収まるように自動的にスクロールするような処理は、入れられてません。平気でカーソルが表示範囲外に飛び出します。これについては、またいつか考えることにします。

行番号と列番号を表示するTOP

こんな感じに。20040718SprictEditor.zip(4,003bytes)

滅茶苦茶です。何が、といって、もう描画処理全部。見た目はまあまあイメージとしてはありかと思いますが(現在カーソル位置は「*」、5列目は「+」、以外は「-」という横着ですが)、なんというか行き当たりばったりで書いてます。

どう書くのが普通なのか見えてきません。ここでは、

  1. 全体の塗りつぶし
  2. 左上の何もない場所の塗りつぶし
  3. 列番号のための塗りつぶしと要素の描画
  4. 本体の要素の描画
  5. カーソルの描画
  6. 行番号のための塗りつぶしと要素の描画

とやってますが、何度も同じ場所を塗りつぶしていて、尋常じゃないちらつきが発生しています。いや、それ以前の問題か。とにかく、選択範囲や強調表示などいやになるほど太ってくる描画処理が既にイってしまっているのは大問題です。

といっても、どうするんがよいのか見当がつかない状態です。リストボックスのDrawItemイベントのように、意味を考えずに1行分のRectだけ計算して単純に別関数に丸投げして、呼び出された関数内でそれなりにやるか、というかリストボックスでやるか?仮想リストボックスとかにして。これ、意外とありかも知れない。

とりあえず先に進む前に、ここまでのコードを整理する必要があるようです。

コードの整理TOP

処理をクラスにまとめたり、まとまらなかったり。でも、ちらつきがかなり収まりました。ついでに複数行に対応して縦スクロールもできるようになりました。あとは...そんなもんか。20040719SprictEditor.zip(6,123bytes)

なぜかIME変換ウィンドウの表示位置を決めるSetImeCompositionWindowがControlsに宣言されていて、usesにも追加しているのに、クラスを宣言しているユニットからは呼び出せませんでした。不思議。

ちらつきが収まった理由は、必要な場所だけ再描画する、という点に尽きるのですが、問題は「文字の削除と改行挿入」です。1行の先頭でBackSpaceすると当然前の行に合体すべきだし、1行の末尾でDeleteすると当然次の行が今の行に合体すべきですが、このとき1行減るわけです。あるいは行の途中などで改行を入れたら1行増えて欲しいわけです。で、何が問題かというと、その1行だけを再描画するだけではすまなくて、以降の全ての行を再描画しないと駄目という点です。

以降の全ての行が何行か?という点は、現在行から今存在している文字列リスト(TStringListでテキストを管理しています)の行数+100までを再描画するという恐ろしい方法で対処しています。コレを文字列リストの行数だけにしてしまうと、1行減った場合に最後の行が再描画されなくて妙なことになってしまうんです。というか、それよりも改行するたびあるいは削除するたびに再描画が結構な回数行われるので反応が鈍いんです。どうやってるんでしょうか。

それからもうひとつ。今まではPaintBox.OnPaintで、ステータスバーに現在位置やスクロール量を表示していたんですが、必要な箇所だけを描画するという方針に変更してから、この情報の更新タイミングがわからなくなってしまったんです。とりあえずSetImeCompositionWindowと同じくKeyDownでやっているんですが...

もう駄目かも...

とにかくクリップボード経由の入力や範囲選択なんかが一切合財ほったらかしで入力しにくいことこの上なしです。が!! そんなものは後回しにして、次回から強調表示に入ることにしましょう。その方が楽しそうなので。このページも長くなったので次回は別のページで。

EOFTOP