スポンサーサイト 


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

--/--/--

Category: スポンサー広告

TB: --  /  CM: --

top △

帳票フォームで固定行スクロール 


以下の様な質問がありました。

フォームを帳票形式にて作成して10件づつ表示をさせようとすると一部のデータが表示されません。
方法としては、帳票形式で10件のみ表示出来る様にサイズを調整して「前へ」と「次へ」のボタンをつけて10件づつ表示させています。

<ここでコードの提示があり>

例えば38件データが有った場合10件の表示を3回行い、8件を最後に表示すれば良いのですが
最後は一番最後のレコードのみ表示されます。

そこで、チョイ前に確認した 帳票サブフォーム間の同期 を流用、変更したものを提示してみました。

実際に、提示したものは(2000/2003/2007 でも)そこそこ動きますが、チョッと条件を変えると1行目が表示されなくなったりします。
それも考慮した、最終形について記述していきたいと思います。


※ 1行目が表示されない現象は以下と関連あるのかどうか・・・・わかりませんけど

[ACC2002] スクロールすると先頭レコードが表示されない
http://support.microsoft.com/default.aspx?scid=kb;ja;418706&Product=accJPN
 
上記は関係ないと思います。(大きな確率で)


一応回答したのは以下の通りです。

私に騙されてみる気はありますか。

以下の方法は、私がいろいろやってみて、何か動きそう・・・
というレベルのもので、Microsoft の資料等裏付けが取れていないものになります。


確認用フォームは、添付図の様になります。
(フォームウィザードから表形式として作ったものになります)
kEnt144_1

「an」「日付」「Src」を連結した帳票で、
ボタン、前に「btnPrev」、次に「btnNext」がヘッダに配置されたものになります。

VBAで、以下を記述します。
Const CSCRLNUM As Long = 10

Private Sub Form_Load()
  Me.InsideHeight = Me.Section(acHeader).Height _
          + Me.Section(acDetail).Height * CSCRLNUM _
          + Me.Section(acFooter).Height
End Sub

Private Sub ScrollByMyself(iNum As Long)
  Dim i As Long, j As Long

  If (Me.Dirty Or Me.NewRecord) Then Exit Sub

  j = Abs(iNum)
  With Me.RecordsetClone
    .MoveLast
    .Bookmark = Me.Bookmark
    i = .AbsolutePosition + iNum
    If (i < 0) Then
      i = 0
    ElseIf (i >= .RecordCount) Then
      i = ((.RecordCount - 1) \ j) * j
    ElseIf ((i Mod j) <> 0) Then
      i = (i \ j) * j
    End If
    .AbsolutePosition = i
    Me.an.SetFocus  ' ★詳細にあるコントロール「an」にフォーカス移動
    Me.Bookmark = .Bookmark
    i = (Me.CurrentSectionTop - Me.Section(acHeader).Height) _
      + Me.Section(acDetail).Height
    i = i \ Me.Section(acDetail).Height
    If (i > 0) Then
      DoCmd.GoToPage 1, , Me.Section(acDetail).Height * i
    End If
  End With
End Sub


Private Sub btnPrev_Click() ' 前へ
  Call ScrollByMyself(-CSCRLNUM)
End Sub

Private Sub btnNext_Click() ' 次へ
  Call ScrollByMyself(CSCRLNUM)
End Sub

※ ★ の、詳細にあるコントロールにフォーカスを移動しないと、まともに動きません。
上記では「an」にしましたが、「日付」でも「Src」でも・・・・
フォーカスが詳細にあることが重要です。

上記の細かい説明は、ここではしません。

※ 本質問とは別の用途ですが、ブログに記事として載せてます。
アドレスは書けない、導くキーワードの提示も規約で禁止されているので書けません。
興味あったら探してみてください。

探して・・・・・っていっても結構きつい所があると思うので記事として載せておきます。
(結構クローラーさんが訪問されているので、そのうち ScrollByMyself で検索できるかも)
(関数名は適当に付けてます。知っている単語をそれっぽく繋げて・・・文法・・・知りません)

別の用途っていうのは、帳票サブフォーム間の同期 になります。
また、詳しくはそちらを見てください。

今回用意したフォームは、メニュー以外に2種類
kEnt144
・フォームヘッダにいろいろ操作するものを置いたもの
・フォームヘッダは使わずにフッタ側で操作するもの(ヘッダの高さ = 0)


回答した時のフォーム「F_TJ」を作っていきます。

テーブル「TJ」を「an」「日付」「Src」で作成
「an」は、オートナンバ: 「日付」は、日付/時刻型: 「Src」は、テキスト型
データが入っていないうちに「TJ_BASE」名でコピーしておきます。

サンプルデータは、標準モジュールにある以下を実行すると38件出来上がります。
Public Sub MkTj()
  Dim i As Integer
  Dim rs As New ADODB.Recordset

  On Error Resume Next
  DoCmd.DeleteObject acTable, "TJ"
  DoCmd.CopyObject , "TJ", acTable, "TJ_BASE"

  rs.Open "TJ", CurrentProject.Connection, adOpenForwardOnly, adLockOptimistic
  For i = 0 To 37
    rs.AddNew
    rs("日付") = DateAdd("d", i, "2012/1")
    rs.Update
  Next
  rs.Close
End Sub

 
今回の確認では必要無いと思いますが、毎回オートナンバを1~にしたい時使えるかな・・・
※ DateAdd や CDate では、年月だけを与えると 1日 に解釈してくれるようです。

このテーブルを元に、フォームウィザードで表形式として「F_TJ」を作成、編集していきます。
・表示する行数を固定する為に、「ポップアップ」を「はい」に
・「前に」「次に」ボタンでスクロールさせるので、「スクロールバー」は「いいえ」に
・ボタン、前に「btnPrev」、次に「btnNext」をヘッダに配置
デザイン上は、これ位です。

VBA を記述していきます。
(回答時から変更したのは、画面のチラツキを抑えた位・・・黄色部分)
Const CSCRLNUM As Long = 10

Private Sub Form_Load()
  Me.InsideHeight = Me.Section(acHeader).Height _
          + Me.Section(acDetail).Height * CSCRLNUM _
          + Me.Section(acFooter).Height
End Sub

Private Sub ScrollByMyself(iNum As Long)
  Dim i As Long, j As Long

  If (Me.Dirty Or Me.NewRecord) Then Exit Sub

  Me.Painting = False
  j = Abs(iNum)
  With Me.RecordsetClone
    .MoveLast
    .Bookmark = Me.Bookmark
    i = .AbsolutePosition + iNum
    If (i < 0) Then
      i = 0
    ElseIf (i >= .RecordCount) Then
      i = ((.RecordCount - 1) \ j) * j
    ElseIf ((i Mod j) <> 0) Then
      i = (i \ j) * j
    End If
    .AbsolutePosition = i
    Me.an.SetFocus
    Me.Bookmark = .Bookmark
    i = (Me.CurrentSectionTop - Me.Section(acHeader).Height) _
      + Me.Section(acDetail).Height
    i = i \ Me.Section(acDetail).Height
    If (i > 0) Then
      DoCmd.GoToPage 1, , Me.Section(acDetail).Height * i
    End If
  End With
  Me.Painting = True
End Sub


Private Sub btnPrev_Click()
  Call ScrollByMyself(-CSCRLNUM)
End Sub

Private Sub btnNext_Click()
  Call ScrollByMyself(CSCRLNUM)
End Sub

 
何をしているかですが、
読み込み時(Form_Load)に、フォームの高さを固定したい行数を元に設定しています。
で、「前に」「次に」で移動した際に表示する1行目を、指定した行数で割った区切りのいいところ・・・
行数を 10 としていたら、1、11、21、31 レコード目が表示の先頭行になるように・・・・
これを AbsolutePosition を操作してレコードを指定することに・・・
AbsolutePosition は 0 スタートなので、行数を足して・・・行数で Mod とって・・・・先頭求めて・・・
後は、帳票サブフォーム間の同期 での計算式を使って表示を移動させてます。

  If (Me.Dirty Or Me.NewRecord) Then Exit Sub
としていたのは、チョッと後々面倒だったから・・・・
編集中に
    Me.Bookmark = .Bookmark
とした時点で、確定処理が動くと思います(未検証)が、エラーになったら・・・
とか
新規行だったら
    .Bookmark = Me.Bookmark
でエラーになるのかな(未検証)・・・・


今は、フォーカスを移動できるものが詳細にあったから良かったものの、無かった時にはどうするの・・・
が、次のフォーム「F_TJ1」

フォーム「F_TJ」を「F_TJ1」としてコピー
フォーム「F_TJ1」をデザインで変更していきます。
・詳細にある「an」「日付」「Src」を選択し、「使用可能」を「いいえ」、「編集ロック」を「はい」に。
・また、新規行には入力できなくなったので、フォームの「追加の許可」を「いいえ」に。

どうにかして詳細にフォーカスをあてないと、Me.CurrentSectionTop をまともに得られないので、
・詳細部分に透明のコマンドボタン「btn1」を配置します。

デザインでは上記の修正で完了です。VBA では、以下の部分を変更するだけです。
    Me.an.SetFocus → Me.btn1.SetFocus



今までは、ヘッダ部にコントロールを配置して操作してきましたが、操作する部分をフッタ側に移動し確認してみます。
このフォームが「F_TJ2」になります。

フォーム「F_TJ」を「F_TJ2」名でコピーします。
フォーム「F_TJ2」のデザインで、「前に」「次に」のコマンドボタンをフッタ側に移動します。
ヘッダに残ったものは全て削除し、ヘッダの高さを 0 とするように、ヘッダと詳細をくっつけ保存します。
VBA の変更は無いので、動きを確認してみます。

「次に」の後「前に」とすると、1行目が選択されているにもかかわらず、表示は2行目から・・・
kEnt144_2
何故か・・・っていうのはわかってまして・・・・
    i = (Me.CurrentSectionTop - Me.Section(acHeader).Height) _
      + Me.Section(acDetail).Height
ここの部分が問題なんです。
ヘッダ部で操作していた時、
 Me.CurrentSectionTop - Me.Section(acHeader).Height
この部分 < 0 (負値)になったんですね
今回のフッタ側での結果は、= 0 になってしまいました。
これにより、先頭に表示されているにもかかわらず、1行の移動を行う事に・・・・


どうしようかという事で、フォーム「F_TJ3」
フォーム「F_TJ2」を「F_TJ3」名でコピーします。
VBA で以下の部分を追加します。
Private Sub Form_Load()
  Me.Section(acHeader).Height = 1
  Me.InsideHeight = Me.Section(acHeader).Height _
          + Me.Section(acDetail).Height * CSCRLNUM _
          + Me.Section(acFooter).Height
End Sub

 
さて、ここで
 Me.CurrentSectionTop - Me.Section(acHeader).Height
部分がどうなったかというと、0 - 1 となり、負値になってくれました。
動作は意図した通りになってくれました。
前の記事同様に、Me.CurrentSectionTop の値について疑問が残りますが・・・・

という事で、最終形に持っていきたいと思います。


フッタ側を使ったフォーム「F_TJ4」
フォーム「F_TJ3」を「F_TJ4」名でコピーし、VBA を以下に変更します。
(固定行数を 8 にしてみました)
Const CSCRLNUM As Long = 8

Private Sub Form_Load()
  Me.Section(acHeader).Height = Me.Section(acHeader).Height + 1
  Me.InsideHeight = Me.Section(acHeader).Height _
          + Me.Section(acDetail).Height * CSCRLNUM _
          + Me.Section(acFooter).Height
End Sub

Private Sub ScrollByMyself(iNum As Long)
  Dim i As Long, j As Long

  If (Me.Dirty) Then Exit Sub

  j = Abs(iNum)
  With Me.RecordsetClone
    If (.RecordCount <= 0) Then Exit Sub
    Me.Painting = False
    .MoveLast
    If (Not Me.NewRecord) Then .Bookmark = Me.Bookmark
    i = .AbsolutePosition + iNum
    If (i < 0) Then
      i = 0
    ElseIf (i >= .RecordCount) Then
      i = ((.RecordCount - 1) \ j) * j
    ElseIf ((i Mod j) <> 0) Then
      i = (i \ j) * j
    End If
    .AbsolutePosition = i
    Me.an.SetFocus
    Me.Bookmark = .Bookmark
  End With
  i = (Me.CurrentSectionTop - Me.Section(acHeader).Height) _
    + Me.Section(acDetail).Height
  i = i \ Me.Section(acDetail).Height
  If (i > 0) Then
    DoCmd.GoToPage 1, , Me.Section(acDetail).Height * i
  End If
  Me.Painting = True
End Sub


Private Sub btnPrev_Click()
  Call ScrollByMyself(-CSCRLNUM)
End Sub

Private Sub btnNext_Click()
  Call ScrollByMyself(CSCRLNUM)
End Sub

 


ヘッダを使ったフォーム「F_TJ5」
フォーム「F_TJ」を「F_TJ5」名でコピーし、「F_TJ4」のVBA を転記します。
(固定行数を 12 にしてみました)

Const CSCRLNUM As Long = 12
固定行数は上記の値を変更するだけです。


サンプルは以下
 バージョン 20002003 (2002)2007
 ファイル kEnt144_2000.zipkEnt144_2003.zipkEnt144_2007.zip
 サイズ 38,12639,01341,478
※ ファイルは zip 形式
※ 2007 以外は、2007 保存時に変換 & 各バージョンで動作確認 & 最適化

関連記事

2012/10/21

Category: サンプルかな

TB: --  /  CM: 0

top △

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

top △

コメントの投稿

Secret

top △


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