![view](/schemes/projectsu/viewie.png)
![edit](/schemes/projectsu/edit.png)
![attach](/schemes/projectsu/upload.png)
![history](/schemes/projectsu/history.png)
![top](/schemes/projectsu/top.png)
![changes](/schemes/projectsu/recent.png)
![search](/schemes/projectsu/search.png)
![help](/schemes/projectsu/help.png)
Genie その3(メニューコマンド、キーボードショートカットを実行する)
その2の応用で、独自機能をインプリメントしてみましょう。例えば、選択文字列がなければ検索文字列入力用の FillInTheBlank を開いて入力された文字列を検索、選択文字列があるときは、その文字列を検索…という機能を付けたいと思います。--sumim - 2003-01-24, 17:05:50
了解です.FillInTheBlankを出してC文字列を受け取るのですね.ちょっとドキドキ.--人狼 - 2003-01-24, 17:28:57
いや、FillInTheBlank 周りは ParagraphEditor >> #find を流用しちゃおうかなぁ…と(^_^;)。ご期待にそえずすみません。もっとも FillInTheBlank はそんなやっかいなものではないですよ。FillInTheBlank request: 'What''s Your Name?' initialAnswer: 'Jinro'
とかで簡単に使えちゃいますから。--sumim - 2003-01-24, 18:32:23
どちらかというと、エディタと相談して選択範囲があるかどうか情報をやりとりするのがミソかと。--sumim - 2003-01-24, 18:33:45
簡単のため、a TextMorph および a TextMorphForEditView の場合に限ってこの作業(選択範囲があれば setSearchString; findAgain 、なければ find )をコード化してみます。両者はいずれも editor というインスタンス変数に自らのエディタ(コントローラ)を束縛していて、TextMorph >> #editor でゲットできます。エディタの TextMorphEditor は ParagraphEditor のサブクラスです。startBlock および stopBlock という選択範囲関係のインスタンス変数は見つかりますが、もうちょっと簡単に選択範囲があるかないか、あればどんな文字列が選択されているかを簡単に調べることができるメソッドがないか browse protocol で探してみましょう。--sumim - 2003-01-24, 19:02:11
>FillInTheBlank 周りは ParagraphEditor >> #find を流用
はい,了解しました.主題はエディタの会話ですね.ご呈示頂いたサンプルは試してみました.--人狼 - 2003-01-27, 09:55:32
>簡単に選択範囲があるかないか、あればどんな文字列が選択されているか
ParagraphEditor>>#selection:は如何でしょうか?--人狼 - 2003-01-27, 10:00:46
>ParagraphEditor>>#selection:
ParagraphEditor >> #selection ですね。よいと思います。前々からちょっと気にはなっているのですが、selection: と selection は別物です。大文字小文字の区別も明確でないときが見受けられますので徐々に注意していってください。今回は ParagraphEditor >> #selection: というものがないので特に問題があるわけではありませんが。--sumim - 2003-01-27, 10:35:06
では、ターゲットのエディタに選択範囲をたずねてそれが空(から)なら true を返すメッセージ式を書いてみましょう。(そのままやん>われ(^_^;))--sumim - 2003-01-27, 10:40:52
>selection:とselectionは別物
了解です.済みません.大文字小文字の件も注意します.--人狼 - 2003-01-27, 10:42:00
target editor selection isEmpty ですね。これが true なら、エディタに find を送ります。false、つまり何か文字列が選択されているときはエディタに setSearchString して選択文字列を検索文字列に指定、続けて findAgain することで次候補を選択する…という処理にしたいと思います。--sumim - 2003-01-27, 11:10:51
>空(から)なら true を返すメッセージ式
#findSelection#
((target editor selection) size) = 0 ifTrue:[True]
ではいかがでしょうか?--人狼 - 2003-01-27, 11:25:46
ありゃ,isEmptyですか.しまった.--人狼 - 2003-01-27, 11:26:14
>ifTrue:[True]
つい先ほどの今でこれはひじょ〜にまずいですね(^_^;)。True は true のクラスで true は True の唯一のインスタンスです。なので、((target editor selection) size) = 0 ifTrue:[true] とすべきです。また、((target editor selection) size) = 0 はこのメッセージ式単独で true もしくは false を返しますので ifTrue: の引数には直接処理(すでに述べたエディタに対する find 送信)を記述するのがよいでしょう。あと、余計なことかも知れませんが、((target editor selection) size) = 0 は括弧を省略して target editor selection size = 0 としても同じだというところ(二項メッセージと単項メッセージの優先順位に関するご理解)は大丈夫でしょうか? --sumim - 2003-01-27, 11:35:36
>TrueはtrueのクラスでtrueはTrueの唯一のインスタンス
うぅ,大失態です.すみません.
>ifTrue: の引数には直接処理
そうですね,そうなります.
>括弧を省略して target editor selection size = 0 としても同じ
はい,それは大丈夫です.ただネストを意識しやすいように(自分がですが)括弧をつけています.--人狼 - 2003-01-27, 11:41:38
>ただネストを意識しやすいように(自分がですが)括弧をつけています
そういうことでしたら問題ありまケん。杞憂でした。--sumim - 2003-01-27, 11:46:42
では処理の完結のほうをチャレンジしてみてください。--sumim - 2003-01-27, 11:48:00
>…という処理にしたいと思います
まだ,findAgainの方がうまく動きませんが,こんな感じで試行錯誤しています.#findSelection#
|edt slct|
edt _ target editor.
slct _ edt selection.
slct isEmpty ifTrue:[edt find] ifFalse:[edt setSearchString ; findAgain]
--人狼 - 2003-01-27, 11:51:33
>findAgainの方がうまく動きません
#findSelection#
|edt slct|
edt _ target editor.
slct _ edt selection.
target handleEdit: [slct isEmpty ifTrue:[edt find] ifFalse:[edt setSearchString ; findAgain]]
としてみてはいかがでしょうか?--sumim - 2003-01-27, 11:58:11
一時変数を使うのがいいのか、使わないのがいいのかよく知らないのですが、私はこんなふうにしてみました。#findSelection#
target handleEdit: [
target editor selection isEmpty
ifTrue: [target editor find]
ifFalse: [target editor setSearchString; findAgain]]
--sumim - 2003-01-27, 12:04:25
問題は target が a PluggableTextMorph の場合ですね。a PluggableTextMorph は、editor というメッセージを受け付けません。ただ、submorphs の深層および、textMorph というインスタンス変数に a TextMrophForEditView を束縛しているのでこれをひっぱりだして改めて target の代わりをさせればこのコードをそのまま使えると思います。textMorph をゲットできれば問題ないのですが、残念ながらこのインスタンス変数のゲッタは定義されていません。submorphs をたどってゆくのも面倒なので禁じ手を使ってしまいましょう(^_^;)。instVarNamed: は指定した名前のインスタンス変数に束縛されているオブジェクトを返します。結果、こうなります。#findSelection#
| textMorph |
target handleEdit: [
((textMorph _ (target isKindOf: PluggableTextMorph)
ifTrue: [target instVarNamed: 'textMorph']
ifFalse: [target]) editor selection) isEmpty
ifTrue: [textMorph editor find]
ifFalse: [textMorph editor setSearchString; findAgain]]
解釈にチャレンジしてみてください。--sumim - 2003-01-27, 12:18:02
>としてみてはいかがでしょうか?
動きましたです.う〜んと…handleEdit:が今一つよく判ってないみたいです.
そうそう,別件ですが3/1の件でメールを差し上げました.--人狼 - 2003-01-27, 12:22:55
>一時変数を使うのがいいのか、使わないのがいいのか
う〜ん,どちらとも言えないです.私には,一時変数を使った方が可読性が高いので一時変数を使いたい人なのです.先の括弧もそうですが,深い意味はなく,その方が見やすいからです.--人狼 - 2003-01-27, 12:28:56
>解釈にチャレンジしてみてください。
targetがPluggableTextMorphであった場合,'textMorph'と言う名前のインスタンス変数に束縛されているオブジェクトを一時変数textMorphに束縛.
targetがそれ以外の場合は,一時変数textMorphにtargetを束縛
textMorphに選択文字列が無ければ,findを,あれば選択文字列を検索文字列に設定してfindAgainを実行.
と言う風に読みました.--人狼 - 2003-01-27, 12:33:17
>う〜んと…handleEdit:が今一つよく判ってない
あれ。handleEdit: 説明してませんでしたっけ?<反語 別件は了解です。デモがないとなるとどうもうまみが(^_^;)。ちょっと考えさせてください。--sumim - 2003-01-27, 12:34:13
解釈は問題なさそうですね。これで a PluggableTextMorph 、つまりワークスペースなどの余白部分でのジェスチャーでもきちんと動作するはずです。いかがでしょう。--sumim - 2003-01-27, 12:36:06
>handleEdit: 説明してませんでしたっけ?
え〜っと(汗)反語のところはおいといて(大汗)この前の回で,描画が云々の時にちらと出てきましたが,何者かまでは話しが及んでおりませんでした.今ソースを眺めとるところです.別件,申し訳ありません.我がUGだけではないので,まだ具体的には決まらないのです.すみません.--人狼 - 2003-01-27, 12:38:43
>いかがでしょう。
動いております.大丈夫です.--人狼 - 2003-01-27, 12:39:50
>今ソースを眺めとるところです
ソースを読んでみましたが,なんか奥が深いです(汗)selectionChangedを潜ってみたのですが,なかなか謎に満ちています.ただそもそもコメントに"Ensure that changed areas get suitably redrawn"とありますので,変更があったところをきっちり再描画しまっせ,と言う事だろうと思うのです.この場合の変更と言うのは,テキストの変更のみならず,選択状態の変更も含んでいるので,再描画を要する場合はhandeEdit:経由にするべき,と言う事なのでしょうか?--人狼 - 2003-01-27, 13:38:54
>再描画を要する場合はhandeEdit:経由にするべき,と言う事
いまのところはそういう理解でいます。前も「これで理屈ではどこでジェスチャーしても printIt されるはず…なのですが、どうも描画がおかしいようです」「これをかましてやれば画面描画は大丈夫そうなので試してみましょう」てな具合だったかと。--sumim - 2003-01-27, 14:50:14
>いまのところはそういう理解でいます
了解致しました.以前handleEdit:が出てきた時も,確かに描画関連でした.てっきり,私の理解が進んでいないので簡単に御説明頂いただけで,実はもっと深い意味がるのかと思っていました.--人狼 - 2003-01-27, 15:01:16
>てっきり,私の理解が進んでいないので
いえ。私も正直、わかっていません(^_^;)。経験則ですみません(笑)。<ぉぃ! --sumim - 2003-01-27, 15:08:06
>経験則で
実はこれが一番頼もしいのです(笑)--人狼 - 2003-01-27, 15:15:06
では、次のある目的のために、任意のキーを押したときのイベントを発生する Genie コードを組んでみましょう。任意のアルファベットを入力するための Genie キーストークは標準で装備されていますが、これを改めて Genie コードで実現してみようという試みです。--sumim - 2003-01-28, 10:50:16
>任意のアルファベットを入力するための Genie キーストークは標準で装備
これは,この前Exported nameをTextとした辞書に登録したアルファベットとは別物ですか?--人狼 - 2003-01-28, 11:19:15
>辞書に登録したアルファベット
このときは、Genie の標準の機能(キーストローク)を使ったわけですが、それを Genie コードで実現してみようという試みです。--sumim - 2003-01-28, 11:24:57
コードタイトルとして記入された一文字をタイプしたのと同じ効果が得られるようなコードを書いてみようと。いや、単純にキーボードイベントを発生させるだけなのですが(^_^;)。--sumim - 2003-01-28, 11:26:30
>それをGenieコードで実現してみよう
判りました,そう言うお話だったのですね(^^;--人狼 - 2003-01-28, 11:34:26
>コードタイトルとして記入された一文字をタイプしたのと同じ効果が得られるようなコード
了解しました.キーボードイベントを発生させるのですね.--人狼 - 2003-01-28, 11:35:29
敵を欺くにはまず味方から…<違! ちうことで、Genie のキーストロークがどのようにイベントを発生しているか解析してみましょう。まず、Genie コードに self halt としてジェスチャーがハンドリングされたところで止めます。スタックを遡って、コードとして処理される他にかならずキーストロークと判断して処理する場所があるはずなので、これを探してみましょう。--sumim - 2003-01-28, 12:34:13
>コードとして処理される他にかならずキーストロークと判断して処理する場所
Morph>>#handleGesture:(レシーバは a TextMorphEditView)でしょうか?ここで,コードなのかマウスイベントなのか,ストロークなのか,コマンドなのか判断しているかと思います.--人狼 - 2003-01-28, 13:07:33
よいと思います。そこから implementers で gestureStrokes: 方面に潜っていってイベント発生手続きを探してみてください。深く潜りますがほぼ一本道です。--sumim - 2003-01-28, 14:17:52
>イベント発生手続き
CRGesture>>#correspondingKeystrokeEventsAt:でしょうか?--人狼 - 2003-01-28, 15:16:40
惜しい。理想を言えば、入力したい文字を与えるだけでイベントを生み出してくれるメソッドを利用したいと思います。これだとメッセージ名にもあるように events なので。もうちょっと潜ってみてください。ただ、このひとつ上流(RGesture >> #correspondingKeystrokeEvents Morph >> #gestureKeystrokes:)でやっているイベント列の処理はあとで出てきますのでよく見ておいてください。--sumim - 2003-01-28, 16:45:47
>もうちょっと潜ってみてください
CRGesture>>#keystrokeEventFor:でしょうか?ここで,KeyboardEvent newしていました.
>イベント列の処理はあとで出てきます
う〜ん,この1行で「イベント列」なんですか.ちょっと悩んでみます.--人狼 - 2003-01-28, 17:08:28
>う〜ん,この1行で「イベント列」なんですか.
すみません、コピペしくじりました。Morph >> #gestureKeystrokes: です。--sumim - 2003-01-28, 18:13:10
>Morph >> #gestureKeystrokes:
了解しました.いや,私も気付くべきでした.済みません.--人狼 - 2003-01-29, 10:27:10
>CRGesture>>#keystrokeEventFor:
ビンゴです。これに、例のコードタイトルの文字、たとえば #a# とでもしましょうか、から # を除く例の処理をして a Character にしたものを引数としてかましてやればイベントオブジェクトを作ることができます。あとは、これをハンドリングしてやればよいわけですが、そのために Morph >> #gestureKeystrokes: での処理で使用しているメソッドを流用したいと思います。それっぽいのは見つかりましたか?--sumim - 2003-01-29, 10:41:07
>それっぽいのは見つかりましたか?
HandMorph>>#handleEventWithGenieEscaped:でしょうか?--人狼 - 2003-01-29, 12:27:45
いいと思います。これで、#a# とすると a を入力する Genie コードが組めますね。#a#
ActiveHand handleEventWithGenieEscaped:
((self keystrokeEventFor:
(lookupResult first char printString copyWithout: $#) asCharacter))
--sumim - 2003-01-29, 12:35:22
>Genie コードが組めます
えぇ〜っと(汗)copyWithout: を調べてきます.今日は15時から外出します.申し訳ありません.--人狼 - 2003-01-29, 13:01:26
>copyWithout: を調べてきます
lookupResult first char printString copyWithout: $#で,Genieコードの名前から#を取り除いた物を抽出していますよね.ここでは文字入力の為に名前は1文字だけで,それをキャラクターオブジェクトとして,keyStrokeEventFor:のパラメータとしてCRGesture自身に送信して,そのイベントをパラメータとしてhandleEventWithGenieEscaped:をActivHand(と言うグローバル変数に束縛されているHandMorph)に送信.と言ったところでしょうか?--人狼 - 2003-02-03, 10:29:55
オッケーです。Genie キーストローク機能があるのに、なんでこんなややこしいものを Genie コードとして書いたかというと、キーボードショートカットにあるけれど黄ボタンメニューにはない機能を比較的簡単な実装で使いたかったからです。たとえば私の大好きな連続選択範囲の交換(cmd-e)や、ペン入力では結構重要なシンボル(クラス名やメッセージセレクタ)の補完(cmd-q)、そうして補完したメッセージセレクタの引数の場所にキャレットを移動する機能(cmd-A)など。最後のはペン入力では不要かしらん(^_^;)。--sumim - 2003-02-03, 16:45:50
で、全然関係ないんですが、ふってわいたような“北ウグ懇”関係でお忙しいこととは存じますが、今週末のドッグファイト企画は大丈夫そうですか?--sumim - 2003-02-03, 16:50:37
>キーボードショートカットにあるけれど黄ボタンメニューにはない機能を比較的簡単な実装で使いたかった
なるほど,やっと意図を了解致しました.確かにショートカットに関してはこの手が良さそうです.--人狼 - 2003-02-03, 22:33:40
>今週末の ドッグファイト企画 は大丈夫そうですか?
もちろんです!その為に,一時エアダンを中止してAC04の慣熟飛行をしとります(笑)それでも,撃墜はされまくりでしょうが(汗)北ウグ懇関連は確かに忙しいのですが,まぁ好きでやってる事ですから忙しくても楽しいです.是非多くの方に参加して頂きたいなぁ…と.--人狼 - 2003-02-03, 22:35:37
トップでは告知されていますが、こちらでも。Apple User Groups 北海道地区懇親会 が来る3月1日に開催されます。是非、皆さんいらしてください。スクイークユーザーのかたは二次会ででもこっそり隅のほうでスクイークネタで盛り上がりましょう(^_^;)。--sumim - 2003-02-04, 10:51:08
さて、本題ですが。キーストロークイベントにはモディファイアキーの上げ下げの状態を後から指定することができます。そこで、コマンドキーを押し下げた状態としてやれば、キーボードショートカットのイベントにすることができそうですね。KeyboardEvent の browse protocol などを使って、a KeyboardEvent にその手の状態変化を促すのに送ったらよいメッセージはないか探してみてください。--sumim - 2003-02-04, 11:02:07
告知,有り難うございます.二次会では隅等とおっしゃらずに,堂々と中央でお願いします>スクイーク.--人狼 - 2003-02-04, 14:18:22
>状態変化を促すのに送ったらよいメッセージ
え〜っと.
toggleCommandKey,toggleControlKey,toggleMacOptionKey,toggleShift当たりが使えそうです.commandKeyPressed等の押されているか判断する系のメソッドもトグルの前に使って確認すれば更に良いのかな?--人狼 - 2003-02-04, 14:20:36
>堂々と中央で
そんなこというと、クロッケーゲリラデモとかやっちゃいますよ(笑)--sumim - 2003-02-04, 15:22:48
では、そんなメッセージを駆使しつつ、ちょこっと cmd-a をする Genie コードにしたててみていただけますか?> #a# --sumim - 2003-02-04, 15:24:51
>クロッケーゲリラデモ
いや,その(汗)時間の都合がつかないので(大汗)許してください〜.--人狼 - 2003-02-04, 17:10:48
>cmd-a をする Genie コードにしたててみて
了解です.今は出先なので(をい)戻ってから考えてみます.--人狼 - 2003-02-04, 17:11:28
>戻ってから考えてみます
何やらバタバタとしていて,中々進まずに済みません.とりあえず,cmd-aは出来るようにはしたてたのですが,検査系のメッセージ式の評価が組み込めていません.取り急ぎ中間報告と言う事で.
#a#
ActiveHand handleEventWithGenieEscaped:
((self keystrokeEventFor:
(lookupResult first char printString copyWithout: $#) asCharacter)
toggleCommandKey)
--人狼 - 2003-02-07, 10:11:41
検査を入れるとしたら#a#
| event |
event _ self keystrokeEventFor:
(lookupResult first char printString copyWithout: $#) asCharacter.
self commandKeyPressed ifFalse: [event toggleCommandKey].
ActiveHand handleEventWithGenieEscaped: event
みたいなことになると思うのですが、いろいろ試してみると、そもそも cmd キーを押した状態でジェスチャーできない(モーフの選択になってしまう)ので、検査系はいらないかなぁ…とも(^_^;)。心配でしたら、#a#
ActiveHand handleEventWithGenieEscaped:
((self keystrokeEventFor:
(lookupResult first char printString copyWithout: $#) asCharacter)
addButtons: 64)
とする手もあります。--sumim - 2003-02-07, 11:47:32
>そもそも cmd キーを押した状態でジェスチャーできない
えぇ,まんまとその罠に引っ掛かりました(笑)ご教示頂いたコードでは,前者の方が意味が明示的で好みです…が,そもそも検査はいらなそうですね.--人狼 - 2003-02-07, 14:48:06
仕事の関係でZOPEを調べ始めました.もう頭の中がゴチャゴチャです(苦笑) --人狼 - 2003-02-07, 14:48:44
徐々に復活です.とりあえずcmd-aは気持ち良く動いています.--人狼 - 2003-03-03, 19:13:07
すいません。出遅れました。お疲れさまでした。まだひともめありそうですが…(^_^;)。
メモカは例会にお持ちします。--sumim - 2003-03-04, 15:43:07
このページを編集 (23312 bytes)
![Congratulations!](/schemes/projectsu/happy.gif) |
以下の 1 ページから参照されています。 |
This page has been visited 3240 times.