グリッドでもESCキーのイベントを透過させたい - umemura - 08-27-2014
表示されているViewに対して、ESCキーを押されたら閉じる、という処理を考えています。
ただ、RecordGrid のセルにフォーカスが入っている場合、
ESCキーを押しても、Viewが閉じません。
TextField などの場合は問題なく閉じるので、
グリッドにESCのキープレスイベントが握りつぶされているのではないかと思うのですが、
これを回避するにはどうすればよいでしょうか。
Code: {def grid =
{RecordGrid
record-source =
{RecordSet
{RecordFields
{RecordField "a", nullable? = true}
}
,
{RecordData a = ""}
},
{RecordGridColumn "a"}
}
}
||View の FocusManager に、ESC キーで閉じるイベントを設定する
{define-proc {add-esc v:View}:void
{if-non-null fm = {v.get-focus-manager} then
def ka =
{KeyAccel
key-accel-string = "Esc",
{on Action do
{v.close}
}
}
{fm.add-key-accel
ka
}
}
}
{CommandButton
label = "RecordGried の View",
{on Action do
def v = {View grid}
{add-esc v}
{v.show}
}
}
{CommandButton
label = "TextField の View",
{on Action do
def v = {View {TextField }}
{add-esc v}
{v.show}
}
}
RE: グリッドでもESCキーのイベントを透過させたい - dyoshida - 08-27-2014
オープンコントロールのRecordGridのコードをみると、
セルにフォーカスが入っている(編集中)状態でのESCキー
押下は入力中の文字の取消として使われているようです。
SkinnedSRGTextFieldFeelクラスのon-key-pressメソッド内に
該当する処理があり、ご推察の通りここでESCキーイベントを
consumeしているようです。
(controls/feels/record-grid-feels.scurl 163行目付近)
既に機能に割り当てられているキーはショートカットキー
として使用しない方がよいと思いますので、別のキーで
Viewを閉じるのはいかがでしょうか?
("Ctrl+Q" など)
RE: グリッドでもESCキーのイベントを透過させたい - umemura - 08-27-2014
dyoshidaさん、ありがとうございます。
ただ、SkinnedSRGTextFieldFeel の中でコンシュームするのをやめても、
View にまではESCのキーイベントは透過されないようです。
こうなると、RecordGrid が怪しくなってくるわけですが・・・。
Code: {define-class public open CustomSkinnedSRGTextFieldFeel
{inherits SkinnedSRGTextFieldFeel}
||-- {method public open {on-start-composition-event
||-- e:StartCompositionEvent
||-- }:void
||-- {if-non-null ui = self.ui-object asa #SkinnableTextFieldUI then
||-- {if not e.consumed? then
||-- {type-switch {get-grid-cell ui}
||-- case srgc:StandardRecordGridCell do
||-- {srgc.reveal-if-hidden}
||-- {if not srgc.edit-active? then
||-- {ui.control.become-active-from-traversal}
||-- set srgc.edit-active? = true
||-- }
||-- }
||-- }
||-- }
||-- || FIXME: why don't we call into super here?
||-- }
{method public open {on-key-press ev:KeyPress}:void
{if-non-null ui = self.ui-object asa #SkinnableTextFieldUI then
let constant cell:StandardRecordGridCell =
{non-null {get-grid-cell ui}}
{cell.reveal-if-hidden}
|| Toggle edit mode if necessary.
{if not cell.edit-active? and
(ev.insertable? or
ev.value == KeyPressValue.backspace or
ev.value == KeyPressValue.delete or
ev.value == KeyPressValue.enter or
ev.value == KeyPressValue.f2)
then
set cell.edit-active? = true
{ui.control.become-active-from-traversal}
}
let constant rng:StringDataModelWritableRange =
(ui.control asa TextField).selected-range
let constant ui-reserved?:bool =
{if-non-null grid = cell.grid then
{grid.ui.reserved-key? ev}
else
false
}
|| Squelch grid keys, except right/left/home/end
|| when not fully selected.
{if cell.edit-active? and
(not ui-reserved? or
((ev.value == KeyPressValue.right or
ev.value == KeyPressValue.left or
ev.value == KeyPressValue.home or
ev.value == KeyPressValue.end) and
rng.size != rng.data-model.size))
then
{switch ev.value
case KeyPressValue.esc do
|| Escape reverts the cell.
{cell.refresh-data}
||↓ コンシュームしないようにしてもView は閉じない
|| (RecordGrid に握りつぶされている?)
|| {ev.consume}
case KeyPressValue.f2 do
|| f2 used by windows to collapse selection for editing.
{if rng.size == rng.data-model.size then
set rng.point = rng.max-index
{rng.collapse-to-point}
{ev.consume}
}
}
|| Suppress editing keys when non-editable.
{if ev.insertable? or
ev.value == KeyPressValue.delete or
ev.value == KeyPressValue.backspace
then
{if {grid-cell-can-update? ui} then
{super.on-key-press ev}
}
else
{super.on-key-press ev}
}
}
{forward-to-grid-cell ui, ev}
set ev.test-recorded? = true
else
{super.on-key-press ev}
}
}
}
||--{define-class public open CustomSkinnedSRGTextFieldFeel
||-- {inherits SkinnedSRGTextFieldFeel}
||--
||-- {method public open {on-key-press ev:KeyPress}:void
||--
||-- {super.on-key-press ev}
||-- || ESC で View を閉じる・・・のはさすがに無理やりすぎて嫌だなぁ
||-- {if-non-null ui = self.ui-object asa #SkinnableTextFieldUI then
||-- {if-non-null cell = {get-grid-cell ui} then
||-- {switch ev.value
||-- case KeyPressValue.esc do
||--
||-- {if-non-null v = {cell.get-view} then
||-- {v.destroy}
||-- }
||-- }
||-- }
||-- }
||-- }
||--}
{define-class public CustomSRGTextFieldUI {inherits SRGSkinnableTextFieldUI}}
{do
{type-switch
the-default-look-and-feel.target-look-and-feel
case slaf:StyledLookAndFeel do
{slaf.register-control-feel
CustomSRGTextFieldUI,
CustomSkinnedSRGTextFieldFeel
}
}
}
{define-class public CustomCell {inherits StandardStringCell }
{constructor public {default}
{construct-super}
}
{method protected open {create-editor}:TextField
def tf = {super.create-editor}
set tf.ui-object = {CustomSRGTextFieldUI}
{return tf}
}
}
{def grid =
{RecordGrid
record-source =
{RecordSet
{RecordFields
{RecordField "a", nullable? = true}
}
,
{RecordData a = ""}
},
{RecordGridColumn "a" , cell-spec =CustomCell}
}
}
||View の FocusManager に、ESC キーで閉じるイベントを設定する
{define-proc {add-esc v:View}:void
{if-non-null fm = {v.get-focus-manager} then
def ka =
{KeyAccel
key-accel-string = "Esc",
{on Action do
{v.close}
}
}
{fm.add-key-accel
ka
}
}
}
{CommandButton
label = "RecordGried の View",
{on Action do
def v = {View grid}
{add-esc v}
{v.show}
}
}
{CommandButton
label = "TextField の View",
{on Action do
def v = {View {TextField }}
{add-esc v}
{v.show}
}
}
RE: グリッドでもESCキーのイベントを透過させたい - umemura - 08-27-2014
やっぱり、consume されないようにすれば、View を閉じれました。
イベントの中を正しく追えていなかった(super.on-key-press を見落としていた)です。失礼。
こんなことをしていいのかどうか、という問題はありますが・・・。
Code: {define-class public open CustomSkinnedSRGTextFieldFeel
{inherits SkinnedSRGTextFieldFeel}
{method public open {on-key-press ev:KeyPress}:void
{super.on-key-press ev}
{if-non-null ui = self.ui-object asa #SkinnableTextFieldUI then
{switch ev.value
case KeyPressValue.esc do
set ev.consumed? = false
}
}
}
}
あと、セルの振る舞い(キープレス)を変えるのは、このControlFeel を使うのが正しいのでしょうかね?
ルックアンドフィール(LookAndFeel)を取得して、レジストして・・・というのは、
アスペクト志向のようで、便利ではあるのですが、あとからコードを探しにくいという欠点もあるので、
クラスの継承のみで完結させたい気もあります。
このあたり詳しい人いたらコメント下さい。
|