DOBON.NETプログラミング道掲示板

■34738 / 親記事)  テキストボックスでの制御
  
□投稿者/ 炎の妖精さん 一般人(3回)-(2021/05/26(Wed) 09:18:40)
  • アイコン環境/言語:[Win10 VB.NET] 
    分類:[.NET] 

    2021/05/26(Wed) 09:55:32 編集(投稿者)

    DOBON.NET様のサイトには大変お世話になっております。

    テキストボックスにて
    以下の制御を実装したいと考えているのですが可能しょうか?
    もし制御が複雑になりそうな場合、別の方法を検討します。


    @キャレット位置によってインクリメントの値を変えたい(|←キャレット)
    ex1) 1|23.45 ⇒ 2|23.45
    ex2) 123|.45 ⇒ 124|.45
    ex3) 123.45| ⇒ 123.46|

    Aキャレット先頭位置に移動不可
     先頭は1文字2文字目の間にキャレットがあるようにしたい(Homeキー押下や先頭位置でマウスクリックしても常に先頭に移動しないようにしたい)
    ex1) 123.4|5 ⇒ 1|23.45
マルチポストを報告
違反を報告
引用返信 削除キー/
■34740 / ResNo.1)  Re[1]: テキストボックスでの制御
□投稿者/ 魔界の仮面弁士 大御所(1337回)-(2021/05/26(Wed) 11:36:14)
  • アイコンNo34738に返信(炎の妖精さんさんの記事)
    > もし制御が複雑になりそうな場合、別の方法を検討します。

    NumericUpDown だと、キーボードの上下キーやスピンボタンを操作して
    増減させたときに、キャレット位置がリセットされてしまう仕様ですよね。
    @を追加実装するのは面倒そうです。

    制御すべき機能が多くなりそうなので、いっそのこと
    UpDownBase なり MaskedTextBox なりを継承して自作した方が
    まだ融通が利くように思えました。


    ひとまずAの実装案だけ載せておきます。


    Partial Public NotInheritable Class NumericUpDownEx
      Inherits NumericUpDown

      Private Sub CaretPosChanged(sender As Object, e As EventArgs)

      End Sub

      Private WithEvents upDownEdit As TextBoxBase
      Private caretPos As Integer = -1
      Public Sub New()
        MyBase.New()
        upDownEdit = Controls.OfType(Of TextBoxBase)().Single()
        AddHandler Application.Idle, AddressOf Application_Idle
      End Sub
      Private Sub Application_Idle(sender As Object, e As EventArgs)
        If upDownEdit.SelectionStart <> caretPos OrElse upDownEdit.SelectionStart = 0 Then
          caretPos = upDownEdit.SelectionStart
          Try
            If caretPos = 0 AndAlso upDownEdit.TextLength > 0 Then
              upDownEdit.Select(upDownEdit.SelectionStart + 1, Math.Max(0, upDownEdit.SelectionLength - 1))
              caretPos = upDownEdit.SelectionStart
            End If
          Catch
          Finally
            CaretPosChanged(Me, EventArgs.Empty)
          End Try
        End If
      End Sub
    End Class



    > @キャレット位置によってインクリメントの値を変えたい(|←キャレット)

    Maximum が 999.99d だったとして、
     1|02.34の場合は Increment を 100.00d
     10|2.34の場合は Increment を 10.00d
     1|2.34 の場合は Increment を 10.00d
     12|.34 の場合は Increment を 1.00d
     12.3|4 の場合は Increment を 0.10d
     12.34| の場合は Increment を 0.01d
    にしたいという事だと読み取りました。

    ということは、下記のように数字の直後以外では、Increment = Decimal.Zero でしょうか。
     |-12,345.67
     -|12,345.67
     -12,|345.67
     -12,345.|67

    この場合、各桁の上限/下限はどのように扱うのでしょうか。
    たとえば Up 操作において、
     19|.00 → 19|.00 (9 以上にはならない)
     19|.00 → 10|.00 (ルーレットのように 0 に戻る)
     20|.00 → 10|.00 (次の桁に繰り上げ)
    のいずれになるのか、ということです。


    > Aキャレット先頭位置に移動不可
    その実装は使いにくいと思いますよ。

    先頭部への移動を禁止してしまうと、ReadOnly = False の場合に
     「テキストを全選択して "100" と入力する」
    のような操作ができなくなりますし、そもそも
    負数の場合、Hexdecimal、ThosandsSeparator の取り扱いも
    検討せねばならないため、先頭だけ処理すれば良いという物でも無いでしょう。


    それに、上下キーやスピンボタンを操作する以外にも、
    全選択して削除して "..." と入力することもできますし、
    クリップボードから任意のテキストを貼ることもできるわけなので、
    こうした「入力中」への動作が中途半端にならないようにせねばなりません。

    やるなら、ParseEditText / UpdateEditText メソッドが呼ばれた後の
    テキスト整形後に限った処理にした方が良いかもしれません。
    Overridable になっていないのが難点。

違反を報告
引用返信 削除キー/
■34741 / ResNo.2)  Re[2]: NumericUpDownコントロールでの制御
□投稿者/ 炎の妖精さん 一般人(4回)-(2021/05/26(Wed) 11:53:23)
  • アイコン魔界の仮面弁士さん
    ご確認ありがとうございます。

    VB6のNumericUpDownコントロールの制御が
    VB.NETと同じように出来ないかなと思い、質問させて頂いた次第です。
    VB6では以下のように制御が出来ていましたが
    VB.NETではインクリメントの値しか変動していないようでしたので気になりました。

    >>@キャレット位置によってインクリメントの値を変えたい(|←キャレット)
    >
    > Maximum が 999.99d だったとして、
    >  1|02.34の場合は Increment を 100.00d
    >  10|2.34の場合は Increment を 10.00d
    >  1|2.34 の場合は Increment を 10.00d
    >  12|.34 の場合は Increment を 1.00d
    >  12.3|4 の場合は Increment を 0.10d
    >  12.34| の場合は Increment を 0.01d
    > にしたいという事でしょうか。
    > それ以外の場所では、Increment = Decimal.Zero ですか?
    その通りです。
    最大値:999.99 最小値:0.00  ※負の値は無し



    > 各桁の上限/下限はどのように扱うのでしょうか。
    > たとえば Up 操作において、
    >  19|.00 → 19|.00 (9 以上にはならない)
    >  19|.00 → 10|.00 (ルーレットのように 0 に戻る)
    >  20|.00 → 10|.00 (次の桁に繰り上げ)
    > のいずれになるのか、ということです。
    次の桁に繰り上げ、繰り下げをしたいです。
    ex1) 19|.00 → 20|.00(UP操作)
    ex2) 99|.00 → 100|.00(UP操作)
    ex3) 0.9|0 → 1.0|0(UP操作)
    ex4) 10|.00 → 9|.00(DOWN操作)
    ex5) 1.0|0 → 0.9|0(DOWN操作)
    ex6) 1.00| → 0.99|(DOWN操作)
違反を報告
引用返信 削除キー/
■34742 / ResNo.3)  Re[3]: NumericUpDownコントロールでの制御
□投稿者/ 魔界の仮面弁士 大御所(1338回)-(2021/05/26(Wed) 15:49:05)
  • アイコンNo34741に返信(炎の妖精さんさんの記事)
    >> NumericUpDown だと、キーボードの上下キーやスピンボタンを操作して
    >> 増減させたときに、キャレット位置がリセットされてしまう仕様ですよね。

    この問題は、リセット後に再復帰させることでクリアできるかも。

    Inherits NumericUpDown
    Protected Overrides Sub UpdateEditText()
     Dim upDownEdit = Controls.OfType(Of TextBoxBase)().Single()
     Dim pos = upDownEdit.SelectionStart
     MyBase.UpdateEditText()
     upDownEdit.SelectionStart = pos
    End Sub


    > VB6のNumericUpDownコントロールの制御が

    VB6 に NumericUpDown コントロールは付属していなかったような…?
    そのコントロールのファイル名や、
    デザイン時のプロパティ設定を教えていただけますか?

    形状が似たものとして、UpDown Control (mscomct2.ocx) や
    Outrider SpinButton Control (spin32.ocx) はありますが、
    これらは TextBox ではありませんし。


    > その通りです。
    > 最大値:999.99 最小値:0.00  ※負の値は無し

    テキスト入力中のキャレット位置については、どう扱う予定なのでしょうか?

    Backspace で文字列が消されたり、
    複数の文字を選択した状態でキー入力で上書きされることもありますよね。


    > 次の桁に繰り上げ、繰り下げをしたいです。
    Incrment させたい値を算出するために、キャレット位置と
    現在のテキスト内容が必要ですね。

    System.Windows.Forms.UpDownBase+UpDownEdit クラスを取得し、
    TextBoxBase.SelectionStart プロパティが変化した時に
    Text プロパティに対して何文字目の位置にいるかを
    特定するコードを用意する必要がありそうです。

    ただし RichTextBox とは異なり、SelectionChanged イベントに
    相当するものが無いのが最大のネックかも。
    (先のコードでは Idle イベントで代用)
違反を報告
引用返信 削除キー/
■34743 / ResNo.4)  Re[4]: NumericUpDownコントロールでの制御
□投稿者/ 魔界の仮面弁士 大御所(1339回)-(2021/05/26(Wed) 16:26:38)
  • アイコンNo34742に追記(魔界の仮面弁士の記事)
    > VB6 に NumericUpDown コントロールは付属していなかったような…?
    > そのコントロールのファイル名や、
    > デザイン時のプロパティ設定を教えていただけますか?

    ここは気になる所なので、確認よろしくお願いします。


    > Text プロパティに対して何文字目の位置にいるかを
    > 特定するコードを用意する必要がありそうです。

    手抜きサンプル。

    ProposeIncrementValue の実装がイマイチですが、
    ある程度はそれっぽく動くかも。

    Option Strict On
    Imports System.Text.RegularExpressions
    Partial Public NotInheritable Class NumericUpDownEx
     Inherits NumericUpDown
     Protected Overrides Sub UpdateEditText()
      Dim upDownEdit = Controls.OfType(Of TextBoxBase)().Single()
      Dim pos = upDownEdit.SelectionStart
      MyBase.UpdateEditText()
      upDownEdit.SelectionStart = pos
      Increment = ProposeIncrementValue(pos)
     End Sub

     Protected Overrides Sub OnTextBoxKeyDown(source As Object, e As KeyEventArgs)
      Dim c = DirectCast(source, TextBoxBase)
      Increment = ProposeIncrementValue(c.SelectionStart)
      MyBase.OnTextBoxKeyDown(source, e)
      Increment = ProposeIncrementValue(c.SelectionStart)
     End Sub

     Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
      Dim c = Controls.OfType(Of TextBoxBase)().Single()
      Increment = ProposeIncrementValue(c.SelectionStart)
      MyBase.OnMouseClick(e)
      Increment = ProposeIncrementValue(c.SelectionStart)
     End Sub

     Private Function ProposeIncrementValue(pos As Integer) As Decimal
      '0.00〜999.99 の範囲を前提とした手抜き実装
      Dim m = Regex.Match(Text, "(?<Left>\d+)\.(?<Right>\d+)")
      If Not m.Success Then
       Return 0D
      Else
       Dim L = m.Groups("Left").Value
       'Dim R = m.Groups("Right").Value
       If L.Length + 3 = pos Then
        Return 0.01D
       ElseIf L.Length < pos Then
        Return 0.1D
       ElseIf L.Length = 3 Then
        If pos <= 1 Then
         Return 100D
        ElseIf pos = 2 Then
         Return 10D
        Else
         Return 1D
        End If
       ElseIf L.Length = 2 Then
        If pos <= 1 Then
         Return 10D
        Else
         Return 1D
        End If
       ElseIf L.Length <= 1 Then
        Return 1D
       Else
        Return 0D
       End If
      End If
     End Function
    End Class
違反を報告
引用返信 削除キー/
■34744 / ResNo.5)  Re[4]: NumericUpDownコントロールでの制御
□投稿者/ 炎の妖精さん 一般人(5回)-(2021/05/26(Wed) 17:31:43)
  • アイコン> >> NumericUpDown だと、キーボードの上下キーやスピンボタンを操作して
    > >> 増減させたときに、キャレット位置がリセットされてしまう仕様ですよね。
    >
    > この問題は、リセット後に再復帰させることでクリアできるかも。
    ソースの提示、ありがとうございます。参考になります。


    >>VB6のNumericUpDownコントロールの制御が
    >
    > VB6 に NumericUpDown コントロールは付属していなかったような…?
    > そのコントロールのファイル名や、
    > デザイン時のプロパティ設定を教えていただけますか?
    >
    > 形状が似たものとして、UpDown Control (mscomct2.ocx) や
    > Outrider SpinButton Control (spin32.ocx) はありますが、
    > これらは TextBox ではありませんし。
    VB6の開発環境が構築出来ていない為、ソース上での確認になりますが、
    XNUM.OCXのライブラリが適用されていました。(リネームされた場合は申し訳ありませんが元のライブラリは不明です)


    > テキスト入力中のキャレット位置については、どう扱う予定なのでしょうか?
    >
    > Backspace で文字列が消されたり、
    > 複数の文字を選択した状態でキー入力で上書きされることもありますよね。
    複数文字の選択は出来ないのが望ましいですが、制御が複雑になりそうなので複数選択しないように注釈を載せておきます。
    Backspaceキーでの制御ですが
    ex1) 100|.00 ⇒ 10|.00
    ex1) 1|.00 ⇒ 0|.00
    ex1) 100.23| ⇒ 100.20|
    ex1) 100.2|3 ⇒ 100.3|0
    という制御になります。

違反を報告
引用返信 削除キー/
■34745 / ResNo.6)  Re[5]: NumericUpDownコントロールでの制御
□投稿者/ 魔界の仮面弁士 大御所(1340回)-(2021/05/26(Wed) 19:19:47)
  • アイコンNo34744に返信(炎の妖精さんさんの記事)
    > XNUM.OCXのライブラリが適用されていました。

    Visual Studio 6.0 / Visual Basic 6.0 標準のものではないですよね。
    自作のライブラリですか?

    サードパーティ製品だとしたら、製品名まで分からないと
    第三者には何のことか分からないです。(^_^;)


    > Backspaceキーでの制御ですが
    > ex1) 100|.00 ⇒ 10|.00
    普通に操作すれば、
     "100|.00" → "10|.00" ⇒補正後⇒ "|10.00"
    になってしまいますが、 No34742 の応用で補正前後の SelectionStart を維持すれば、
     "100|.00" → "10|.00" ⇒補正後⇒ "10|.00"
    とできますね。


    > ex1) 1|.00 ⇒ 0|.00
    通常の操作では、
     "1|.00" → "|.00" ⇒補正後⇒ "|0.00"
    になる流れですが、「SelectionStart が 0 の時は 1 に修正する」という処理を組み込めば
     "1|.00" → "|.00" ⇒補正後⇒ "0|.00"
    にできるでしょう。

    ここで言う補正処理とは、UpdateEditText() メソッドの呼び出しを指しています。
    UpdateEditText() メソッドは通常、「LostFocus 時」または
    「ユーザー編集後の最初の Value プロパティ参照時」に呼ばれるようになっています。


    NumericUpDown には、補正処理に関連するメソッドとして、下記のものが用意されています。

     Protected Overridable Sub UpdateEditText()
      … オーバーライド可能。
        値が編集されていた場合に、Text プロパティを補正するためのもの。

     Protected Sub ParseEditText()
      … オーバーライドできない。
        Value プロパティを更新し、UserEdit プロパティを False にするもの。

     Protected Overridable Sub ValidateEditText()
      … オーバーライド可能。
        既定では ParseEditText() と UpdateEditText() を呼ぶだけ。


    > ex1) 100.23| ⇒ 100.20|
    バックスペースを 2 回押した場合は
     "100.23|" → "100.2|" → "100.|" ⇒補正後⇒ "100.00|"
    で、1 回だけなら
     "100.23|" → "100.2|" ⇒補正後⇒ "100.20|"
    という流れと読み取りましたが、如何でしょうか。
    キャレットの後ろに文字列が無ければ、補正後は末尾になる、という想定です。

    この想定は、そちらの認識と相違ありますか?



    > ex1) 100.2|3 ⇒ 100.3|0
    > という制御になります。
    @ "100.2|3" → "100.|3" ⇒補正後⇒ "100.|30"
    A "100.2|3" → "100.|3" ⇒補正後⇒ "100.3|0"
    B "100.2|3" → "100.|3" ⇒補正後⇒ "100.30|"
    のパターンのうち、Aになるわけですね。(自分は@を予想していました)
    この場合、キャレット位置はどのようなルールで算出される想定でしょうか。

    私の予想はこんな感じでした。

    @案:キャレットがピリオド直後にあったので、補正後もピリオドの直後となる
    A案:小数部に居た場合、末尾から数えて 1 桁目なので、補正後も小数部の末尾から 1 桁目
    B案:小数部が補正されて桁数が変化した場合、補正後は小数部の末尾となる



    ついでに、小数点が削除された場合の算出案

    C "1.|23" → "1|23" ⇒補正後⇒ "1|23.00"  整数部の先頭 1 文字目を維持する想定
    D "100.|23" → "100|23" ⇒補正後⇒ "999.99|"  範囲外の値だった場合は末尾固定案
    E "100.|23" → "100|23" ⇒補正後⇒ "999|.99"  整数部の左から3文字目に居たので、補正後も整数部の左から3文字目
    F "100.|23" → "100|23" ⇒補正後⇒ "9|99.99"  整数部の百の位の位置に居たので、補正後も整数部の百の位


    小数部にフォーカスが行かないようにできれば良いのですが、ドラッグ操作での範囲選択もあるため、
    小数部にカーソルが完全に行かないように制限するのは難しいでしょうね。
違反を報告
引用返信 削除キー/
■34746 / ResNo.7)  Re[5]: NumericUpDownコントロールでの制御
□投稿者/ 炎の妖精さん 一般人(6回)-(2021/05/26(Wed) 21:52:17)
  • アイコン魔界の仮面弁士さん

    ありがとうございます。
    大変参考になります。

    提示頂いたコードを参考に反映させていきます。
    ありがとうございました。
解決み!
違反を報告
引用返信 削除キー/



スレッド内ページ移動 / << 0 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -