文字入力の抑止について

17 件の投稿

TextFieldの{NumericValidator・・}で数値の検証を行い
数値以外の場合はエラーメッセージを表示するようにできるのですが、
そもそも数値以外の入力をさせたくない場合はどのような記述をすればいいでしょうか?
KeyPressイベントで数値以外を入力したらundoするような機能ってあるのでしょうか?
また、abcdeを入力してtabキーを押すとエラーは出るのですが、再度tabキーを押すと
検証されずに次の項目に遷移されてしまうのですが、毎回検証することはできないのでしょうか?

Code:
{let tf:TextField =
    {TextField
        width = 40pt,
        max-chars = 5,
        {validate-with
            {NumericValidator
                locale = "en",
                max-allowable = 99999,
                signed? = true,
                allow-grouping? = false,
                allow-decimal-point? = false,
                allow-exponent? = false
            },
            required? = false,
            dialog-on-finished? = true,
            message="入力は半角数字5文字までです。",
            refocus? = true
        }
    }
}
{let tf2:TextField =
    {TextField
        width = 40pt
    }
}
{HBox tf,tf2}


若干乱暴ですがTextFieldを継承したクラスで
UIのKeyPressイベントを止めつつ、
set-value-with-eventsを抑止すれば
ほぼ入力できなくなると思います。
Code:
{define-class public NumericTextField {inherits TextField}

  {constructor public {default ...}

    {construct-super {splice ...}}
    {self.ui-object.add-event-handler
{on e:KeyPress do
{switch e.value
case '1','2','3','4','5','6','7','8','9','0','-',',' do
else                {e.consume}
}
}
}

    set self.halign = "right"
}

  {method public {set-value-with-events val:String}:void
{for c:char in val do
{switch c
case '1','2','3','4','5','6','7','8','9','0','-',',' do
else            {return}
}

    }

    {super.set-value-with-events val}  }

}

{NumericTextField value = "150"}
ありがとうございます。
このままだとBackSpace等も効かなくなるので、それなりに工夫が必要ですね。
>TextFieldの{NumericValidator・・}で数値の検証を行い
>数値以外の場合はエラーメッセージを表示するようにできるのですが、
>そもそも数値以外の入力をさせたくない場合はどのような記述をすればいいでしょうか?
>KeyPressイベントで数値以外を入力したらundoするような機能ってあるのでしょうか?

こんな感じではどうでしょうRolleyes
KeyPressイベントではなく、ValueChangeイベントにてundo処理を行っています。
ペーストされた場合でも値が入らない様になります。

Code:
{curl 8.0 applet}
{curl-file-attributes character-encoding = "utf8"}

{import * from CURL.LANGUAGE.REGEXP}

{def tf = {TextField
              {on ValueChanged at tf:TextField do
                  {if {regexp-match? |"\D"|, tf.value} then
                      {tf.undo}
                  }
              }
          }
}
{value
    {HBox
        tf
    }
}
ありがとうございます。
123a
と入力した場合undoだから全部消えてしまいますね。
aだけ消えるのはValueChangedでは難しいのでしょうか?
単純な数値入力でよければ以下はいかがでしょうか?

Code:
{import * from CURL.LANGUAGE.REGEXP}

{define-class public NumberTextField {inherits TextField}

  {constructor public {default ...}
    {construct-super {splice ...}}
  }
  
  {method public open {replace-selection-with-string
                          text-to-insert:StringInterface
                      }:void
    {output text-to-insert}
    {if {regexp-match? |"^\D*$"|, text-to-insert} then
        set text-to-insert = ""
    }
    {super.replace-selection-with-string text-to-insert}
  }
}

{NumberTextField}

マイナスを受け入れたり、小数点以下を許す場合には
もっと工夫が必要かと思います。
Yuhkiさんに出遅れましたが、
前述のNumericTextFieldを改変したサンプルを作ってみました。

でもコピー&ペーストを許容するならYuhkiさんのつくりの方がよさそうですね。
ご参考まで。


.curl   NumericTextField.curl (Size: 1.63 KB / Downloads: 1,357)
>123aと入力した場合undoだから全部消えてしまいますね。
>aだけ消えるのはValueChangedでは難しいのでしょうか?

申し訳ありません。確認不足でした。。。Sad

Code:
{curl 8.0 applet}
{curl-file-attributes character-encoding = "utf8"}

{import * from CURL.LANGUAGE.REGEXP}

{def tf = {TextField
              {on e:KeyPress do
                  {tf.record-typing-for-undo e.value}
              },
              {on ValueChanged at tf:TextField do
                  {if {regexp-match? |"\D"|, tf.value} then
                      {tf.undo}
                   else
                      {tf.clear-undo-stack}
                  }
              }
          }
}
{value
      tf
}
>nmyzkさん
{set-of char}に許容する文字やキーを羅列しておけばよいということですね。
>森口さん
123aや12a3をコピーしてTextFieldにペーストしたら123だけ入るのってさすがに厳しいですかね?
まぁ、そこまで要求することはないとは思いますが・・Smile

これまでのコメントを元に、max-charsになったら自動的にtabキーを押して次の項目に遷移するような
TextFieldを作成してみました。初回起動して12345を入力しても遷移しないのですが、もう一度
12345を入力しなおすと自動遷移します。この現象ってどこに原因があるのでしょうか?
初回と2回目は同じ動きをしているっぽいのですが謎です。
また、tf2をmax-charsの変更だけで同じ挙動をさせたいのですがこの場合はNumericTextFieldのような
拡張クラスを作らなければならないのでしょうか?

Code:
{import * from CURL.LANGUAGE.REGEXP}
{let max-chars:int = 5}
{let tf1:TextField =
    {TextField
        width = 40pt,
        max-chars = max-chars,
        {on e:KeyPress  do
            {tf1.record-typing-for-undo e.value}
        },
        {on e:ValueChanged at tf:TextField do
            {if {tf.get-text}.size >= max-chars then
                let kp:KeyPress = {KeyPress}
                set kp.value = KeyPressValue.tab
                {tf1.ui-object.enqueue-event
                    kp
                }
                {e.consume}
            }
            {if {regexp-match? |"\D"|, tf.value} then
                {tf.undo}
             else
                {tf.clear-undo-stack}
            }
        },
        {on AttachEvent do
            {tf1.become-active}
        }
    }
}
{let tf2:TextField =
    {TextField
        width = 40pt,
        max-chars = 4
    }
}
{HBox tf1,tf2}
>123aや12a3をコピーしてTextFieldにペーストしたら123だけ入るのってさすがに厳しいですかね?
>まぁ、そこまで要求することはないとは思いますが・・[Image: smile.gif]


う~ん、undoを使用する場合だと、その様な仕様は難しいかもしれませんねSad
Yuhkiさんが投稿されている様に、文字を空文字に置き換える様にすれば実現はできると思いますSmile

Quote:また、tf2をmax-charsの変更だけで同じ挙動をさせたいのですがこの場合はNumericTextFieldのような
拡張クラスを作らなければならないのでしょうか?

クラスを作らずに、同じ定義を部品化したいのであれば
Arguments と splice を使用すればこんな感じでできます。

Code:
{import * from CURL.LANGUAGE.REGEXP}
{let max-chars:int = 5}
{let arg:Arguments = {Arguments
                         {on e:KeyPress  do
                             {tf1.record-typing-for-undo e.value}
                         },
                         {on e:ValueChanged at tf:TextField do
                             {if {regexp-match? |"\D"|, tf.value} then
                                 {tf.undo}
                              else
                                 {tf.clear-undo-stack}
                             }
                             {if {tf.get-text}.size >= tf.max-chars then
                                 let kp:KeyPress = {KeyPress}
                                 set kp.value = KeyPressValue.tab
                                 {tf1.ui-object.enqueue-event
                                     kp
                                 }
                                 {e.consume}
                             }
                         },
                         {on AttachEvent do
                             {tf1.become-active}
                         }}}
{let tf1:TextField =
    {TextField
        width = 40pt,
        max-chars = max-chars,
        {splice  arg}
    }
}
{let tf2:TextField =
    {TextField
        width = 40pt,
        max-chars = 5,
        {splice  arg}
    }
}
{let tf3:TextField =
    {TextField
        width = 40pt,
        max-chars = 4,
        {splice  arg}
    }
}
{let tf4:TextField =
    {TextField
        width = 25pt,
        max-chars = 3,
        {splice  arg}
    }
}
{let tf5:TextField =
    {TextField
        width = 60pt,
        max-chars = 10,
        {splice  arg}
    }
}
{HBox tf1,tf2,tf3,tf4,tf5}
(09-24-2011, 03:20 PM)森口 慶紀 Wrote: >う~ん、undoを使用する場合だと、その様な仕様は難しいかもしれませんねSad
>Yuhkiさんが投稿されている様に、文字を空文字に置き換える様にすれば実現はできると思いますSmile


そのような入力の方法は通常しないと思うので、ペースト時に入力不可能な文字が入っていたらペースト自体ができないのが本来の動きでよいのかとも思ってますSmile
(09-26-2011, 12:55 PM)onyo Wrote: クラスを作らずに、同じ定義を部品化したいのであれば
Arguments と splice を使用すればこんな感じでできます。


まさに期待していた部品です。どうもありがとうございますSmile
やはり初回起動時には自動遷移しないのが気になりますSad
いろんな提案があるみたいですが、TextFieldで文字制限する場合の王道はYuhkiさんのreplace-selection-with-stringをオーバーライドする方法でしょうね。コピペやキャレット位置に依存せずにやろうと思うと。

(09-26-2011, 05:42 PM)usami Wrote:
(09-24-2011, 03:20 PM)森口 慶紀 Wrote: >う~ん、undoを使用する場合だと、その様な仕様は難しいかもしれませんねSad
>Yuhkiさんが投稿されている様に、文字を空文字に置き換える様にすれば実現はできると思いますSmile


そのような入力の方法は通常しないと思うので、ペースト時に入力不可能な文字が入っていたらペースト自体ができないのが本来の動きでよいのかとも思ってますSmile


Yuhkiさんの例で数字にマッチしたときに空文字にしてしまっているところを、数字だけ削除するように変えれば一応できます。
(09-26-2011, 05:50 PM)usami Wrote: やはり初回起動時には自動遷移しないのが気になりますSad
AttachEventのところを以下のようにしてみてください。

Code:
{on AttachEvent do
    {after 0s do {tf1.become-active}}
}

ただ私のCurl8.0の環境だとこれをやらなくても初回起動からうまく動きましたよ。でも6.0だと動きませんでした。usamiさんも同じですかね。


どうもありがとうございます。 きちんと動きました。

>Yuhkiさんの例で数字にマッチしたときに空文字にしてしまっているところを、数字だけ削除するように変えれば一応できます。

Java等他システムで確認しましたが数字だけペーストできるものはなかったので、ペーストできない仕様でよいと思ってます。

>ただ私のCurl8.0の環境だとこれをやらなくても初回起動からうまく動きましたよ。でも6.0だと動きませんでした。usamiさんも同じですかね。

当方の環境は7.0でしたが、8.0の環境で試すと確かに変更なしで動きました。
また、tf1に全桁数字を入れた後、tf1にカーソルを戻して全桁表示状態で
数字以外のキーを押すとカーソルがtf3まで飛んでしまいますが、
tf1の状態にとどまることって可能なのでしょうかSad