Access (VBA) |
|
(Windows 11 Home : Access 2019)
テキストボックス内で改行する
投稿日時: 24/06/12 12:02:40
投稿者: mmiwa
|
---|---|
教えて下さい
|
投稿日時: 24/06/12 12:49:52
投稿者: Suzu
|
|
---|---|
SelStart は テキストボックス内のテキストの挿入位置 を示します。
引用: としています vbCrLf は Text の方に入れるべき値ではありませんか? |
投稿日時: 24/06/12 13:00:36
投稿者: abec
|
|
---|---|
selstartは文字の位置を数値で入れるので、そこでvbcrlfを入れてはいけません。
|
投稿日時: 24/06/12 13:41:00
投稿者: sk
|
|
---|---|
引用: その処理をどのコントロールのどのイベントで 実行しようとされているのでしょうか。 |
投稿日時: 24/06/12 22:54:19
投稿者: hatena
|
|
---|---|
mmiwa さんの引用: カーソルのある場所に文字列を挿入するなら、SelTextに代入すればいいでしょう。 文字列の最後へカーソルを移動した上で改行は、カーソルを最後に移動させた後、SelTextにvbCrLfを代入すればいいでしょう。 Me!テキスト1 .SelText = buf 'カーソル位置にBufを挿入 .SelStart = Len(.Text) 'カーソルを最終位置に移動 .SelText = vbCrLf 'カーソル位置に改行を代入 End With と、ここまで回答を書いて、サンプルを作成して動作確認したら、 .SelText = vbCrLf 'カーソル位置に改行を代入 がうまく動作しない。改行が挿入されずにカーソルが先頭に移動してしまう。 Accessのテキストボックスは改行コード(vbCrLf)の扱いが特殊なようです。 仕方がないので、SendKeys で改行してみました。 With Me!テキスト1 .SelText = buf 'カーソル位置にBufを挿入 .SelStart = Len(.Text) 'カーソルを最終位置に移動 SendKeys "^{ENTER}" End With ちなみに、.SelText や .SelStart はフォーカスがないと取得できないので、 コマンドボタンのクリック時なとではコマンドボタンにフォーカス移動してしまうので、実行することはできません。 サンプルではラベルのクリック時で実行しました。ラベルはフォーカス移動しないので、動作させることができます。 |
投稿日時: 24/06/17 09:03:15
投稿者: mmiwa
|
|
---|---|
Suzuさん、abecさん、skさん、hatenaさん
引用: 確かにそうですね .Text = Left(.Text, .SelStart) & buf & Mid(.Text, .SelStart + 1) & vbCrLf としてみましたが、結果は同じでした 引用: ありがとうございます SetFocus加えましたが、結果は同じでした 引用: リストボックスをダブルクリックすることで選択した項目をbufへ格納 bufをテキストボックスのカーソルの位置へ転記します 続いてカーソルをテキストボックス内の文字列の最後へ移動させ 改行を入れたいのです 引用: ありがとうございます これまでSendKeysに良い印象がなかったので 選択肢としていませんでした 残念ながら、試してみましたが、結果は同じでした |
投稿日時: 24/06/17 10:50:54
投稿者: sk
|
|
---|---|
引用: 次のどちらの操作を想定されているのかが不明瞭です。 ・リストボックスをダブルクリックしてから テキストボックスの任意の位置にフォーカスを移動させようとしている。 ・テキストボックスの任意の位置にフォーカスがある状態から リストボックスをダブルクリックしようとしている。 仮に前者である場合、テキストボックスへのフォーカスの移動は マウスクリックだけでなく Tab や Enter などのキークリックによって 行なわれる可能性があります。 その際にカーソルがどこに移動するかは、クライアントの設定における [フィールドの移動時の動作]オプションに左右され、場合によっては テキストボックスの値全体が範囲選択された状態となり得ますが、 もしそうなったら値全体を buf の値で上書きしてしまうのでしょうか。 また後者である場合、例えばそのフォームが開かれてから 一度もテキストボックスにフォーカスに移ったことがない状況で リストボックスがダブルクリックされることがあり得るのであれば、 その際の挙動はどのようになさるつもりなのでしょうか。 |
投稿日時: 24/06/17 22:50:35
投稿者: mmiwa
|
|
---|---|
skさん
引用: 後者です 引用: そのフォームが開かれたときに 一旦テキストボックスへフォーカスを移動しています |
投稿日時: 24/06/18 03:30:14
投稿者: hatena
|
|
---|---|
mmiwa さんの引用: 私の回答で既にふれてますが、SelStartはフォーカスがないテキストボックスではエラーになり使えません。 ラベルのクリック時で実行するように回答してますが、ラベルのクリック時で試してみてダメだったのですか。 リストボックスのダプルクリック時で実行したいのなら下記のような問題が発生します。 リストボックスをダブルクリックすると、フォーカスがリストボックスに移動します。 その時点でSelStartはリセットされます。 SetFocusでフォーカスをテキストボックスに戻してもSelStartは0(クライアントの設定によっては最後の位置)になります。 テキストボックスのフォーカス移動時にSelStartとSelLengthを格納しておいて、SetFocus後に移動前の状態に戻すという対処法が必要になります。 ということで、コード化してみました。 Option Compare Database Option Explicit Dim preSelStart As Long Dim preSelLength As Long Private Sub テキスト1_Change() With Me.テキスト1 Debug.Print "Change: ", .SelStart, .SelLength End With End Sub Private Sub テキスト1_Exit(Cancel As Integer) With Me.テキスト1 preSelStart = .SelStart preSelLength = .SelLength End With End Sub Private Sub リスト2_DblClick(Cancel As Integer) Dim buf As String buf = Me.リスト2.Value With Me.テキスト1 .SetFocus .SelStart = preSelStart .SelLength = preSelLength .SelText = buf .SelStart = Len(.Text) SendKeys "^{ENTER}" End With End Sub これでサンプルで実験してい見るとうまく行く時とうまく行かないときがあります。 Accessのコントロールは裏でいろいろやっているようで複雑です。 いろいろ試してみましたが、もう力尽きたので寝ます。 |
投稿日時: 24/06/18 11:58:47
投稿者: sk
|
|
---|---|
引用: 引用: (フォームモジュール) ------------------------------------------------------------- Option Compare Database Option Explicit Private varSelStart As Variant Private varSelLength As Variant Private Sub Form_Load() Dim strControlSource As String With Me![テキスト1] strControlSource = "=GetSelectConditions([" & .Name & "])" .OnKeyUp = strControlSource .OnMouseUp = strControlSource .OnUndo = strControlSource Me.OnUndo = strControlSource End With End Sub Private Sub Form_Current() Me![テキスト1].SetFocus GetSelectConditions Me![テキスト1] End Sub Private Sub リストボックス名_DblClick(Cancel As Integer) On Error GoTo Err_リストボックス名_DblClick Const conNoPreviousControl = 2483 If Nz(Me![リストボックス名].Value, "") = "" Then Exit Sub End If Dim varBuf As Variant varBuf = Me![リストボックス名].Value & vbCrLf Dim ctlPrevious As Access.Control Set ctlPrevious = Screen.PreviousControl Me.Painting = False With ctlPrevious If (.Name = "テキスト1") And (IsEmpty(varSelStart) = False) Then .Value = Left(.Value, varSelStart) & _ varBuf & _ Mid(.Value, varSelStart + varSelLength + 1) .SetFocus .SelStart = varSelStart + Len(varBuf) .SelLength = 0 GetSelectConditions ctlPrevious End If End With Exit_リストボックス名_DblClick: Set ctlPrevious = Nothing Me.Painting = True Exit Sub Err_リストボックス名_DblClick: Dim strErrTitle As String Dim strErrMsg As String Select Case Err.Number Case 0, conNoPreviousControl Case Else strErrTitle = "実行時エラー(" & Me.Name & ".リストボックス名_DblClick)" strErrMsg = Err.Number & ": " & Err.Description Debug.Print strErrTitle Debug.Print strErrMsg MsgBox strErrMsg, vbCritical, strErrTitle End Select Resume Exit_リストボックス名_DblClick End Sub Private Function GetSelectConditions(TextBox As Access.TextBox) With TextBox If Me.ActiveControl.Name = .Name Then varSelStart = .SelStart varSelLength = .SelLength Else varSelStart = Empty varSelLength = Empty End If End With End Function ------------------------------------------------------------- とりあえず、以上のようなコードを記述した上で 動作テストを行なってみて下さい。 |
投稿日時: 24/06/18 13:46:55
投稿者: hatena
|
|
---|---|
skさんのコードの動作確認してみました。
mmiwa さんの引用: うまく動作しているようですが、 文字列の最後へカーソルを移動した上で改行の部分を私は、「テキストボックスの文字列の最後に移動して改行」と解釈していましたが、 skさんの動作をみて、「挿入した文字列の最後に移動して改行」という意味とも解釈できますね。 skさんのコードは後者の解釈ですね。 mmiwaさん、ご希望はどちらなんでしょうか。 |
投稿日時: 24/06/18 16:10:42
投稿者: sk
|
|
---|---|
hatena さんの引用: hatena さんの引用: 本件に関して、改行文字の挿入位置の違いはさほど重要ではないため、 私自身はあまり問題視していません。 単にリストボックスのダブルクリックが繰り返し行なわれた際に 後者のような動きをした方が、「文字列の挿入/上書き」と 「カーソル位置の移動」が正しく実行されたかどうかを確認しやすいからです。 abec さんの引用: hatena さんの引用: abec さんと hatena さんが回答された通り、テキストボックスの SelStart プロパティおよび SelLength プロパティは、 そのテキストボックスがアクティブである状態でしか 参照することが出来ません。 リストボックスの DblClick イベントが発生した時点では 既に[テキスト1]からフォーカスが失われているため、 その後で参照しようとしても手遅れです。 したがって、[テキスト1]からフォーカスが失われるまでの間、 そのカーソル位置とテキスト選択範囲が変化する都度、 これらのプロパティの値を正確に捕捉、保持しておく必要があります。 それを具体的にどのイベントで、どのような方法によって実現するかが、 本件において最も重要な問題です。 hatena さんの引用: hatena さんの引用: hatena さんが挙げられたサンプルでは Exit イベント、 つまりフォーカスを喪失しようとしている時に SelStart プロパティと SelLength プロパティを 取得なさろうとされているわけですが、お気付きの通り そのイベントではこれらのプロパティの値を正確に 取得できないことがあります。 また、そのフォームが非連結フォームではなく連結フォームであり、 かつ[テキスト1]が連結テキストボックスであった場合、 フォームのカレントレコードが他のレコードに移動されれば [テキスト1]の値は移動後のレコードの連結フィールドの値に変わり、 テキストの選択状態はリセットされます。 フォームのアンドゥ、または[テキスト1]のアンドゥが 実行された場合も同様です。 以上の点を踏まえて、[テキスト1]がアクティブであり、かつ [テキスト1]のテキストの選択状態の変化を促す操作が 行なわれた時に発生し得るそれぞれのイベントにおいて SelStart プロパティと SelLength プロパティを取得するようにし、 かつリストボックスにフォーカスが移る直前にアクティブだった コントロールが[テキスト1]である場合のみ、これらのプロパティが 指し示すカーソル位置/選択範囲に対して「文字列の挿入/上書き」 および「カーソル位置の移動」を実行するようにしています。 直前にアクティブだったコントロールが[テキスト1]ではなければ、 この処理は実行されません。 もし対象となるのが([テキスト1]だけに限らず)「リストボックスに フォーカスが移る直前にアクティブだったテキストボックス」全てであり、 それらに対して同様の処理を実行しようとなさっているのであれば、 クラスモジュールを作成してより適切な形で処理を共通化させた方がよいでしょう。 |
投稿日時: 24/06/18 17:18:44
投稿者: sk
|
|
---|---|
sk さんの引用: 連結フォームのアンドゥが実行された場合については、 一旦[テキスト1]にフォーカスを移した状態で GetSelectConditions を呼び出した方が安定しそうなので、 次のように訂正します。 (フォームモジュール) ------------------------------------------------------------- Option Compare Database Option Explicit Private varSelStart As Variant Private varSelLength As Variant Private Sub Form_Load() Dim strControlSource As String With Me![テキスト1] strControlSource = "=GetSelectConditions([" & .Name & "])" .OnKeyUp = strControlSource .OnMouseUp = strControlSource .OnUndo = strControlSource 'Me.OnUndo = strControlSource End With End Sub Private Sub Form_Current() Me![テキスト1].SetFocus GetSelectConditions Me![テキスト1] End Sub Private Sub Form_Undo(Cancel As Integer) Me![テキスト1].SetFocus GetSelectConditions Me![テキスト1] End Sub Private Sub リストボックス名_DblClick(Cancel As Integer) On Error GoTo Err_リストボックス名_DblClick Const conNoPreviousControl = 2483 If Nz(Me![リストボックス名].Value, "") = "" Then Exit Sub End If Dim varBuf As Variant varBuf = Me![リストボックス名].Value & vbCrLf Dim ctlPrevious As Access.Control Set ctlPrevious = Screen.PreviousControl Me.Painting = False With ctlPrevious If (.Name = "テキスト1") And (IsEmpty(varSelStart) = False) Then .Value = Left(.Value, varSelStart) & _ varBuf & _ Mid(.Value, varSelStart + varSelLength + 1) .SetFocus .SelStart = varSelStart + Len(varBuf) .SelLength = 0 GetSelectConditions ctlPrevious End If End With Exit_リストボックス名_DblClick: Set ctlPrevious = Nothing Me.Painting = True Exit Sub Err_リストボックス名_DblClick: Dim strErrTitle As String Dim strErrMsg As String Select Case Err.Number Case 0, conNoPreviousControl Case Else strErrTitle = "実行時エラー(" & Me.Name & ".リストボックス名_DblClick)" strErrMsg = Err.Number & ": " & Err.Description Debug.Print strErrTitle Debug.Print strErrMsg MsgBox strErrMsg, vbCritical, strErrTitle End Select Resume Exit_リストボックス名_DblClick End Sub Private Function GetSelectConditions(TextBox As Access.TextBox) With TextBox If Me.ActiveControl.Name = .Name Then varSelStart = .SelStart varSelLength = .SelLength Else varSelStart = Empty varSelLength = Empty End If End With End Function ------------------------------------------------------------- |
投稿日時: 24/06/19 18:22:42
投稿者: mmiwa
|
|
---|---|
hatebaさん skさん
引用: 曖昧な記述で申し訳ありませんでした 僕の希望は前者でした skさんのコードだと「挿入した文字列の最後に移動して改行」になるので 僕の希望とは異なります 引用: なるほど 「発生しうるあらゆるイベントに対する対応」が必要とは認識していたつもりですが まだまだ勉強不足だなあと痛感しました 「テキストボックスの文字列の最後に移動して改行」については skさんのコードを下記のように変更して 希望通りの動きとなりました With ctlPrevious If (.Name = "テキスト0") And (IsEmpty(varSelStart) = False) Then Dim varBuf2 As Variant varBuf2 = Left(.Value, varSelStart) & _ varBuf & _ Mid(.Value, varSelStart + varSelLength + 1) If Right(varBuf2, 2) = vbCrLf Then varBuf2 = varBuf2 Else varBuf2 = varBuf2 & vbCrLf End If .Value = varBuf2 .SetFocus .SelStart = Len(.Value) GetSelectConditions ctlPrevious End If End With 結局 SendKeys "^{ENTER}" は避けてしまいました せっかくコードを上げていただいたのにhatenaさん申し訳ありません これを機会に SendKeys "^{ENTER}" も使ってみます アドバイスいただいた皆様 本当にありがとうございました 今後ともよろしくお願いいたします |