FC2ブログ

スポンサーサイト 


上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--/--/--

Category: スポンサー広告

TB: --  /  CM: --

top △

区切り単位での編集 


テーブル「T1」
フィールド型 等々
 an オートナンバ (主キー)
 F1 テキスト

というテーブルがあった時、
「F1」の内容は、"/" を区切り文字とした文字列
(区切り文字の個数は最大7個で、区切りとしては8つ)

これをフォームに表示します。
この時、大元の「F1」と、区切られた文字列部分1~8個を別々に表示して
それぞれを編集した時に、他部分にも反映しつつ登録操作をしたい。

kEnt131_F1  kEnt131_F2
画面のイメージは、こんなものでしょうか。

過去記事にも似たようなものがありました。
ハイパーリンクって、、、セキュリティは になりますが、"#" が区切り文字になってますね。
ま、以前の場合は、元々の文字列は表示せずに、分割したものだけを表示/変更するものだったので、
似てはいますが、新記事として・・・・

単票フォームでは実現は簡単ですが、帳票フォームでのサンプルも・・・・
(過去記事に幾度と登場していますが、「コントロールを重ねる」ものになります)
 

単票フォーム


フォーム「F1」として、フォームデザインから作っていきます。
レコードソースは、テーブル「T1」そのままを指定し、
詳細に、
テキストボックス「txt0」、コントロールソースを「F1」
テキストボックス「txt1」~「txt8」で非連結
連結、非連結がわかりやすいように背景色を分けて設定しておきます。
これらテキストボックスに対応する標題部分を、ヘッダにラベルとして作成します。
非連結テキストボックスに対応するラベルを「lab1」~「lab8」と名付けます。
動作確認用フォームなので、区切り文字を指定できるようにヘッダにテキストボックス「tx0」を配置。

画面上は、これで終わりです。
kEnt131_F1

VBAを記述していくわけですが、まず、区切りで抜き出す・・・・これを標準モジュールに作成しておきます。
Public Function MySplit(vSrc As Variant, iNum As Long _
            , Optional DLM As String = "/") As String
  On Error Resume Next
  MySplit = ""
  MySplit = Split(vSrc, DLM)(iNum)
End Function

 
対象の文字列、区切り文字を指定して、区切りの何個目を頂戴・・・・っていうものです。

フォーム「F1」の処理概要としては、
・非連結テキストボックスで変更されたら、文字列を作り直す
・ラベル部分をクリックされたら、対応するテキストボックスへフォーカス移動
・レコード移動時、連結文字列から各非連結テキストボックスへ区切った文字設定
ってな具合です。

記述したのは以下
Private Function TxtChange()
  Dim sAry(7) As String
  Dim i As Long

  For i = 0 To 7
    sAry(i) = Nz(Me("txt" & i + 1))
  Next
  Me.txt0 = Join(sAry, Me.tx0)
End Function

Private Function LabClick(iNum As Long)
  Me("txt" & iNum).SetFocus
End Function

Private Sub Form_Load()
  Dim i As Long

  Me.tx0 = "/"
  Me.tx0.ValidationRule = "Is Not Null"
  Me.tx0.ValidationText = "何か入力して"
  For i = 1 To 8
    Me("lab" & i).OnClick = "=LabClick(" & i & ")"
    Me("txt" & i).AfterUpdate = "=TxtChange()"
  Next
End Sub

Private Sub Form_Current()
  Dim i As Long

  For i = 0 To 7
    Me("txt" & i + 1) = MySplit(Me.txt0, i, Me.tx0)
  Next
End Sub

Private Sub Form_Undo(Cancel As Integer)
  Dim i As Long

  If (IsNull(Me.txt0.OldValue)) Then Exit Sub
  For i = 0 To 7
    Me("txt" & i + 1) = MySplit(Me.txt0.OldValue, i, Me.tx0)
  Next
End Sub

Private Sub tx0_AfterUpdate()
  Call Form_Current
  Me.txt0.SetFocus
End Sub

Private Sub txt0_BeforeUpdate(Cancel As Integer)
  If (IsNull(Me.txt0)) Then Exit Sub
  If ((Len(Me.txt0) - Len(Replace(Me.txt0, Me.tx0, ""))) \ Len(Me.tx0) > 7) Then
    MsgBox "区切りの個数は7個まで", vbCritical
    Cancel = True
  End If
End Sub

Private Sub txt0_AfterUpdate()
  Call Form_Current
End Sub

 
動きとしては良さそうです。
ただ、非連結側を変更した際に、有効な部分だけで文字列作りましょうか・・・
(上記では、必ず区切り文字を7個使った文字列が生成されてました)
上記記述の先頭部分を以下に変更します。(サンプルは上記のままです)
Private Function TxtChange()
  Dim sAry() As String
  Dim i As Long

  ReDim sAry(7)
  For i = 0 To 7
    sAry(i) = Nz(Me("txt" & i + 1))
  Next
  For i = 7 To 0 Step -1
    If (Len(sAry(i)) > 0) Then Exit For
  Next
  If (i < 0) Then
    Me.txt0 = Null
  Else
    ReDim Preserve sAry(i)
    Me.txt0 = Join(sAry, Me.tx0)
  End If
End Function

 

帳票フォーム


では、単票として出来上がったフォーム「F1」を元に、帳票フォームにしていきましょう・・・
単に帳票フォームにしただけでは、非連結テキストボックスの表示は、レコードに依存したものにはならず、
全レコード共通になってしまいます。

まずは、レコードに依存した表示するだけ・・・のフォームを作っていきます。


フォーム「F2」(表示するだけ)

フォーム「F1」を「F2」名でコピーし、既定のビューを帳票フォームに変更します。
デザイン上での大きな変更はこれで終わりです。(詳細部分を狭めるとかはありますが・・・)
kEnt131_F2

非連結の各テキストボックスのコントロールソースに、単票時レコード移動時に行っていたもの
区切り文字での抽出を行うようにします。
例えば、「txt1」では、 =MySplit([txt0],0,[tx0])
[txt0] を [tx0] で区切った時の 0 番目を表示しますよ・・・
これ、VBAで設定するようにします。(「txt1」~「txt8」を手で設定していくより楽かな・・・)

VBA記述は以下。
Private Function LabClick(iNum As Long)
  Me("txt" & iNum).SetFocus
End Function

Private Sub Form_Load()
  Dim i As Long

  Me.tx0 = "/"
  Me.tx0.ValidationRule = "Is Not Null"
  Me.tx0.ValidationText = "何か入力して"
  For i = 1 To 8
    Me("lab" & i).OnClick = "=LabClick(" & i & ")"
    Me("txt" & i).ControlSource = "=MySplit([txt0]," & i - 1 & ",[tx0])"
  Next
End Sub

Private Sub tx0_AfterUpdate()
  Me.Recalc
  Me.txt0.SetFocus
End Sub

Private Sub txt0_BeforeUpdate(Cancel As Integer)
  If (IsNull(Me.txt0)) Then Exit Sub
  If ((Len(Me.txt0) - Len(Replace(Me.txt0, Me.tx0, ""))) \ Len(Me.tx0) > 7) Then
    MsgBox "区切りの個数は7個まで", vbCritical
    Cancel = True
  End If
End Sub

これで、表示することは出来ましたが、「txt1」~「txt8」での入力/変更はできません。
変更できるのは、フィールド「F1」と連結している「txt0」だけになります。

さて、入力できるようにしていきますか・・・・って、コントロールを重ねることをするんですけどね。


フォーム「F3」(入力/編集可)

フォーム「F2」を「F3」名でコピーします。
詳細部分にテキストボックス「txtmv」を配置します。
不可視にしておいて、「タブストップ」を「いいえ」にして、最背面に位置移動しておきます。

イメージ的には、
「txt1」~「txt8」にフォーカスが移動してきたら、「txtmv」を位置/大きさをそのものに合わせて移動し、
フォーカスを「txtmv」に移します。
フォーカスを得た「txtmv」は背面にあるにもかかわらず、そのレコードの「txtmv」のみ前面に出てきます。
他のレコードでは「txtmv」は背面のままなので、該当レコード上のみが変化している
って具合になります。
「txtmv」を使う時、「Tag」部分に情報をチョッと・・・
  元テキストボックスの番号;元テキストボックスのタブ移動順;「txtmv」のタブ移動順
「txtmv」にフォーカスを移動する前に、タブ移動順を入れ替えます。
「txtmv」がフォーカスを失う時に、タブ移動順を戻します。
その情報の置き場所として「Tag」を利用するってだけですけど・・・・
(タブ移動順は入れ替えなくてもよいのかも・・・・)

VBA で記述したのは以下
Private Function TxtEnter(iNum As Long)
  Dim i As Integer

  With Me("txt" & iNum)
    Me.txtmv.Top = .Top
    Me.txtmv.Left = .Left
    Me.txtmv.Height = .Height
    Me.txtmv.Width = .Width
    Me.txtmv.Value = .Value
    i = Me.txtmv.TabIndex
    Me.txtmv.Tag = iNum & ";" & .TabIndex & ";" & i
    Me.txtmv.TabIndex = .TabIndex
    .TabIndex = i
  End With
  Me.txtmv.Visible = True
  Me.txtmv.SetFocus
End Function

Private Function LabClick(iNum As Long)
  On Error Resume Next
  Me("txt" & iNum).SetFocus
End Function

Private Sub Form_Load()
  Dim i As Long

  Me.tx0 = "/"
  Me.tx0.ValidationRule = "Is Not Null"
  Me.tx0.ValidationText = "何か入力して"
  For i = 1 To 8
    Me("lab" & i).OnClick = "=LabClick(" & i & ")"
    With Me("txt" & i)
      .ControlSource = "=MySplit([txt0]," & i - 1 & ",[tx0])"
      .OnEnter = "=TxtEnter(" & i & ")"
    End With
  Next
End Sub

Private Sub Form_Current()
  Me.Recalc
End Sub

Private Sub tx0_AfterUpdate()
  Me.Recalc
  Me.txt0.SetFocus
End Sub

Private Sub txt0_BeforeUpdate(Cancel As Integer)
  If (IsNull(Me.txt0)) Then Exit Sub
  If ((Len(Me.txt0) - Len(Replace(Me.txt0, Me.tx0, ""))) \ Len(Me.tx0) > 7) Then
    MsgBox "区切りの個数は7個まで", vbCritical
    Cancel = True
  End If
End Sub

Private Sub txtmv_AfterUpdate()
  Dim sAry(7) As String
  Dim i As Long

  For i = 0 To 7
    sAry(i) = Nz(Me("txt" & i + 1))
  Next
  i = Split(Me.txtmv.Tag, ";")(0)
  sAry(i - 1) = Nz(Me.txtmv)
  Me.txt0 = Join(sAry, Me.tx0)
'  Me.Recalc
End Sub

Private Sub txtmv_LostFocus()
  Dim sAry() As String

  sAry = Split(Me.txtmv.Tag, ";")
  Me("txt" & sAry(0)).TabIndex = sAry(1)
  Me.txtmv.TabIndex = sAry(2)
End Sub

 
これで、見た目入力もできるようになりました。
でも、入力後「Enter」すると次のテキストボックスに移動しますが、その入力していた所の表示が・・・
ジンワ~~~と表示されていきます。

入力したらすぐに表示変更したいな・・・・って事で、上記
Private Sub txtmv_AfterUpdate()
  Dim sAry(7) As String
  Dim i As Long

  For i = 0 To 7
    sAry(i) = Nz(Me("txt" & i + 1))
  Next
  i = Split(Me.txtmv.Tag, ";")(0)
  sAry(i - 1) = Nz(Me.txtmv)
  Me.txt0 = Join(sAry, Me.tx0)
  Me.Recalc ' コメントを外して有効に
End Sub
部分を変更したのが、フォーム「F31」
表示はすぐに反映されるようになりましたが、動きに変化が・・・・

フォーム「F3」では、編集状態のままだったんですが、
フォーム「F31」では、変更した内容で確定されてしまいました。

キャンセル操作が出来なくなりました。
表示をすぐに反映したいし、確定されてはなぁ~~ということで、考えてみることに・・・


フォーム「F41」(入力/編集可:元に戻したい)

考えてみて・・・・

確定されても、元に戻せる状態にしておけばいいんじゃない・・・
レコード移動時に、元の値を「txt0」の「Tag」に格納しておきましょう。
(「Tag」は String なので、Null / 空文字列 の区別はできなくなるけど・・・いいや)

元に戻すのは、コマンドボタンを配置してそれをクリックしてもらいましょう・・・
コマンドボタンを配置するのは良いけど、対象のレコード以外のところのボタン表示は隠しましょう。
過去記事にもあるように、隠す時にはテキストボックスで透かして見せる/見せないを・・・
でも、テキストボックスの上にカーソルが行くと、カーソル形状が変わっちゃうね・・・
カーソル形状が変化しない「使用可能」を「いいえ」にすると、イベントが取れないね・・・
また、追加して「編集ロック」を「はい」にしないと、グレー表示になっちゃう・・・
じゃぁ、その上に透明なコマンドボタンを置きましょうか・・・
この透明なコマンドボタンの上にマウスカーソルが来たら、最下層のボタンにフォーカスを移しましょう。
これにより、ボタン上にマウスカーソルが来た時のボタン表示がそのままできるね・・・
普通はフォーカスは移動しないんだけど・・・・ ま、いいか・・・

という事で、フォーム「F31」を「F41」名でコピー後、
kEnt131_F41  kEnt131_F41D
ヘッダ部に、レコードを特定する値を格納するテキストボックス「tx00」を非表示で、
詳細部分に、戻すボタン「btn1」を、
その上に、透けて見せるためのテキストボックス「txt00」、
その上に、透明なボタン「btn2」を配置します。

「txt00」では、
コントロールソースを  =IIf([an]=[tx00],"","gg")
背景スタイルを、透明
境界線スタイルを、実線  (本来は、透明で・・・境界線色を背景色と同じにしていたのでセーフ)
境界線色を、#FFFFFF
フォントを、Webdings
フォントサイズを、24
使用可能を、いいえ
編集ロックを、はい
タブストップを、いいえ

各ボタンの「タブストップ」も「いいえ」としておきます。

VBA で記述したのは以下
Private Function TxtEnter(iNum As Long)
  Dim i As Integer

  With Me("txt" & iNum)
    Me.txtmv.Top = .Top
    Me.txtmv.Left = .Left
    Me.txtmv.Height = .Height
    Me.txtmv.Width = .Width
    Me.txtmv.Value = .Value
    i = Me.txtmv.TabIndex
    Me.txtmv.Tag = iNum & ";" & .TabIndex & ";" & i
    Me.txtmv.TabIndex = .TabIndex
    .TabIndex = i
  End With
  Me.txtmv.Visible = True
  Me.txtmv.SetFocus
End Function

Private Function LabClick(iNum As Long)
  On Error Resume Next
  Me("txt" & iNum).SetFocus
End Function

Private Sub Form_Load()
  Dim i As Long

  Me.tx0 = "/"
  Me.tx0.ValidationRule = "Is Not Null"
  Me.tx0.ValidationText = "何か入力して"
  For i = 1 To 8
    Me("lab" & i).OnClick = "=LabClick(" & i & ")"
    With Me("txt" & i)
      .ControlSource = "=MySplit([txt0]," & i - 1 & ",[tx0])"
      .OnEnter = "=TxtEnter(" & i & ")"
    End With
  Next
End Sub

Private Sub Form_Current()
  Me.tx00 = Me.an
  Me.txt0.Tag = Nz(Me.txt0)
  Me.Recalc
End Sub

Private Sub tx0_AfterUpdate()
  Me.Recalc
  Me.txt0.SetFocus
End Sub

Private Sub txt0_BeforeUpdate(Cancel As Integer)
  If (IsNull(Me.txt0)) Then Exit Sub
  If ((Len(Me.txt0) - Len(Replace(Me.txt0, Me.tx0, ""))) \ Len(Me.tx0) > 7) Then
    MsgBox "区切りの個数は7個まで", vbCritical
    Cancel = True
  End If
End Sub

Private Sub btn1_Click()
  If (Me.NewRecord) Then Exit Sub
  Me.Painting = False
  If (Len(Me.txt0.Tag) = 0) Then
    Me.txt0 = Null
  Else
    Me.txt0 = Me.txt0.Tag
  End If
  Call tx0_AfterUpdate
  Me.Painting = True
End Sub

Private Sub btn2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
  If (Len(Me.txt00) = 0) Then Me.btn1.SetFocus
End Sub

Private Sub txtmv_AfterUpdate()
  Dim sAry(7) As String
  Dim i As Long

  For i = 0 To 7
    sAry(i) = Nz(Me("txt" & i + 1))
  Next
  i = Split(Me.txtmv.Tag, ";")(0)
  sAry(i - 1) = Nz(Me.txtmv)
  Me.txt0 = Join(sAry, Me.tx0)
  Me.Recalc
End Sub

Private Sub txtmv_LostFocus()
  Dim sAry() As String

  sAry = Split(Me.txtmv.Tag, ";")
  Me("txt" & sAry(0)).TabIndex = sAry(1)
  Me.txtmv.TabIndex = sAry(2)
End Sub

 

こんな感じでしょうか・・・

でも、上記記述でどうしようもなかったものがあるんですけど・・・・
戻すボタン「btn1」がクリックされた時、「txt0」を元に戻して、「txt0」にフォーカス移動・・・
これ、その通りに書いていたのですが、
「btn1」から「txt0」にフォーカスが移って、フォーカスを失った「btn1」は背面に隠れ・・・
までは良かったのですが、
透明ボタン「btn2」が前面に来て・・・だけどマウスカーソルが動いて「btn1」にフォーカス移動・・・
結局、戻すボタンからフォーカスが移動していない様に見える・・・・

そういうものだ・・・・で、行くことにします。
これ用に、フラグ(変数)を設けて・・・って、頑張るところでもないような気が・・・

そうそう、今回入力用に1つのテキストボックスを重ねて・・・
言い方によっては使い回しするようにしましたが、「txt1」~「txt8」それぞれに重ねるものを用意して・・・
の方が楽なのかも・・・・・・・


サンプルは以下
 バージョン 20002003 (2002)2007
 ファイル kEnt131_2000.zipkEnt131_2003.zipkEnt131_2007.zip
 サイズ 39,53340,48543,581
※ ファイルは zip 形式
※ 2007 以外は、2007 保存時に変換 & 各バージョンで動作確認 & 最適化



予告)次の記事は「遊んでみますか の2」になります。
内容的には、Line コントロールをいじってみましょう的なものになります。
kEnt132_F3  kEnt132_21  kEnt132_16  kEnt132_17_2
関連記事

2012/05/28

Category: サンプルかな

TB: --  /  CM: 0

top △

この記事に対するコメント

top △

コメントの投稿

Secret

top △


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。