VBA全くの素人で、医薬品集の索引作成に悪戦苦闘中です。見様見真似で『目次(索引)ページを自動作成』を参考に、レポートフッターにテキストボックス「txt目次」を作成し、レポート詳細の薬品名とページをはきだしていますが、薬品名を五十音順に並び替えるにはどのようにしたらよいでしょうか? 宜しくお願い致します。
Option Compare Database
Option Explicit
Const RowCount = 30
Dim Cnt As Integer
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
If Me.Pages = 0 Then
If Cnt \ RowCount <= 3 Then
Me("txt目次" & Cnt \ RowCount) = Me("txt目次" & Cnt \ RowCount) & Left(Me.薬品名 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End If
Cnt = Cnt + 1
End If
End Sub
Private Sub レポートヘッダー_Format(Cancel As Integer, FormatCount As Integer)
Me.Page = 0
Cnt = 0
End Sub
Me.Page = 0
関係はヘッダーに出力したいとき用のテクニックなので消してしまいましょうフッターに出力するタイミングで並び替えの処理が必要ですね。また、段組みにするのは並び替えの後の必要があるので、
詳細_Format
のタイミングではデータを拾うだけでよさそうです並び替えの方法はいろいろあります。楽そうな方法を公開しているサイトがあったのでそちらから借りてきました。VBAの配列を.NETのArrayListのSortで並べ替え(Excel作業をVBAで効率化さん)
動作確認していないので問題があったら教えてください。
それと、「薬品名」はすべて五十音ですか?「葛根湯」とかあると、漢字はすべてカナの後とかなったりします
hiroton さん、有難うございます。感激です! レポートフッターにテキストボックスを作成し、このままコードをコピペしたところコンパイルエラー(型が一致しません)と出た為、Private Sub ページフッターセクション → Private Sub レポートヘッダーセクション とし、プレビューしたところエラーは出ませんが、何もはきだしていない状態です。どこをどうすれば良いのか分からず、とりあえずご報告いたしました。
コンパイルくらい試すべきでした。すみません
まずは並び替え用の関数の修正
それと、「レポートフッター」でしたね
レポートフッターですよね?
レポート フッターのフォーマット時に[イベント プロシージャ]を設定してください
hiroton さん、有難うございます。
感激です!! 以下のように修正しました。
薬品名が並び変わっています!!
ただ、ある範囲までの薬剤が繰り返しはきだされていて、300ページ程になっています。
自分で何とかしようと思ったのですが、どこに問題があるのかもわかりません。
レポートフッターにテキストをtxt目次0~3まで作成しています。他に必要な情報はありますでしょうか?
宜しくお願い致します。
Option Compare Database
Option Explicit
Dim data As String
Private Sub 詳細_Format(Cancel As Integer, FormatCount As Integer)
data = data & Left(Me!薬品名 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End Sub
Private Sub レポートフッター_Format(Cancel As Integer, FormatCount As Integer)
Dim arr
Dim s
Const RowCount = 30
Dim CNT As Long
'並び替えのために配列にする
arr = Split(data, vbCrLf)
'配列を並び替え
Call ArrayListSort(arr)
'段組みに振り分ける
CNT = 0
For Each s In arr
Me("txt目次" & CNT \ RowCount) = Me("txt目次" & CNT \ RowCount) & s & vbCrLf
CNT = CNT + 1
If CNT >= 120 Then Exit For 'RowCount * 4
Next
End Sub
Sub ArrayListSort(ary As Variant)
Dim aryList As Object
Dim s
'// .NET FrameworkのArrayListクラスを利用する
Set aryList = CreateObject("System.Collections.ArrayList")
For Each s In ary
Call aryList.Add(s)
Next
Call aryList.Sort
ary = aryList.ToArray
End Sub
ページフッターやtxt目次など、配置した後デフォルトから変更しているプロパティがありますよね?それを提示してください
提示したコードは複数ページにまたがることを想定していないので次のページが出力されるとすると
レポートフッター_Format
が全く同じように動いて全く同じ内容が出力されますコード自体にページを増やす処理はないのでレポート上の設定に問題があると思われます。
txt目次
に印刷時拡張「はい」とか設定されていませんか?上記のとおり、レポートフッターが出力されるたび全く同じページが出力されるので、そのページが次のページを出力するような内容の場合無限ループしてしまいます
hiroton さん、何度も有難うございます。
また、複数ページにまたがる事をお伝えしていませんでした。
薬剤数450-500、3段組みの設定を考えており数ページに及びます。
変更点をご指導頂けますでしょうか?
「txt目次0~3」なら「0,1,2,3」の4段じゃないですか?
印刷時拡張を使って複数ページになるなら目次データの生成処理を初回の1回だけ処理するようにすればいいですね
それと、印刷時拡張かつ段組みとすると、30行ずつ3段目まで振り分けたらまた1段目に戻す必要がありますね
レポートフッター_Format
を次のように変更しますそれと、詳細セクションも複数ページにまたがることがあったりしますか?
ページ跨ぎが発生すると
詳細_Format
もその都度発生するので、data
に薬品名が重複して登録されます。こちらもページ跨ぎの場合はdata
にデータを追加しない様、制御処理を追加しておいたほうがいいかもしれませんhirotonさん、感動です! やりたかったことが出来てます!! 改めて、いくら自分で本を読んだりネットで調べてもダメだったと痛感しました。教えて頂いたコードを読み解いて勉強してみます。解決できない時はまたご指導ください。取り急ぎご報告まで。
hirotonさん、早くも質問です。小出し小出しで申し訳ない内容です。
索引を印刷したところ、本文の薬品ページと索引で示すページが異なっている一部薬品があります。ページが変わるタイミングの薬品で、レポートで薬品を剤型→薬効分類とグループ化しているのですが、薬効分類がページが切り替わる時、例えば、1ページ目に薬効分類が入っていると薬品が2ページ目なのに索引には1ページと表記される といった状態です。2点目は、以前
ご指摘の通り、薬品にはカタカナ、漢字、数字が混在しています。印刷をしてみると、やはり五十音順にならんでいた方が見やすいかなと思い、ご指導を頂けないでしょうか?
今更ですが、レポートと薬品集テーブルのスクリーンショットを添付しました。宜しくお願い致します。
適当なデータを作って試してみたら確かにうまくいかないですね
レポートのイベントの発生メカニズムの研究(hatena chipsさん)
ページ跨ぎが発生した場合に目次データが重複しないよう
と制御を入れたんですが、
FormatCount = 1
だけだとうまく目的のデータにならないようです。画像を見てわかる通り、目次データの取得は「実際の描画があったら目次データを作成する(ページ番号を取得する)」とする必要がありそうです。hirotonはうまい方法を知りません目次データを取得している詳細_Formatイベントは描画前の処理なので、このタイミングで「描画があったかどうか?」は知りようがありません。やるとすれば、印刷しようとしている余白に印刷できる高さがあるかどうかを計算するという方法になると思います。現在の印刷位置情報や、印刷領域の残り高さが必要になるのでかなり大変です
条件を限定すれば、いくらか簡単な方法でチェックすることもできそうです
・同一ページ印刷プロパティ「はい」
・単独で1ページを超えるような出力がない(上図の例なら詳細は最大でも9行(1ページで収まる)場合)
であれば、「
FormatCount = 2
があれば、それが描画ページ」とすることができます。ただ、FormatCount = 1
のときはFormatCount = 2
があるかどうかわからないので、「仮データを置いて、次の明細に移動したら仮データの確定処理をする」様にします五十音での並び替えについて
とりあえず無理やり的な方法で(修正箇所だけ)
例えば
のようなデータがあった場合、
のようにひとかたまりの文字列のデータにして並び替えた後、分割用の文字から後ろを抜き出せば「かな順」で並び替えができるというものです
「<split>」は誤動作しないよう「かな」に含まれない文字列なら何でも構いません
内容が複雑化してきて、簡素化した記述が足かせになって余計な苦労をしてるような気がしてきました。データのボリュームが増えてきているのでコード内でもしっかりデータを管理できるような仕組みを導入したほうがよさそうです
というわけで、ちゃんと使いやすいデータにして対応する例
Dictionary オブジェクトを使って目次データを整理するようにします
Dictionary オブジェクトを使うには事前準備が必要なのでレポートの開く時イベントに処理を追加しています。
Dictionary オブジェクトの仕様上「薬品名のフリガナ」に重複データがあると最後の「薬品名」のみ目次に反映されます
hirotonさん、本当に有難うござます。自分がやろうとしていたことが、素人には絶対無理だったと痛感しました。ご指導頂いた資料で今後じっくり勉強することにして・・・ とりあえず、このままコピペしてみました。添付しましたファイルの様なコメントが出ました。完全なコピペはダメだったでしょうか?
エラーメッセージの通りだと思います
新しく追加したプロシージャは
Report_Open
なので開く時プロパティに[イベント プロシージャ]
を設定してくださいArrayListSort関数も省略しているので適当な場所に入れておいてください(汎用的に使える関数なので標準モジュールに入れてしまってもいいと思います)
[イベント プロシージャ]
は各イベントのプロパティのプルダウンから常に選べるようになっているプロパティですが、これを指定すると、それぞれで専用のプロシージャを呼び出しなさいという指定になります(レポートの開く時ならReport_Open
とか)[イベント プロシージャ]
を選んで[...]をクリックすると、対応するプロシージャが自動で生成されますが、コードをコピペしても[イベント プロシージャ]
は自動で設定はされないので、この部分は自分でやる必要があります。適当にエラーが出るプロパティを設定してみたら同じエラーメッセージ出ませんでした。多分原因は
こっちのほうですね。
で必要な関数を消してしまったんでしょう。開く時(Report_Open)では
ArrayListSort()
使ってないのでエラーメッセージが残念な感じですがよくあることなので・・・先週金曜日から何とかご指摘を克服しようと努力はしましたが、今の知識では難しくお知恵を頂こうと思っていました。
13の完コピに、1のSub ArrayListSort以下を合体させたところ”薬品名のフリガナフィールドが見つかりません”とのメッセージに変わりました(前進ですか?)。レポートに「薬品名のフリガナ」がないのは気になっていたのですが、この点は如何でしょうか?
Sub ArrayListSort(ary As Variant)
Dim aryList As Object
Dim s
'// .NET FrameworkのArrayListクラスを利用する
Set aryList = CreateObject("System.Collections.ArrayList")
For Each s In ary
Call aryList.Add(s)
Next
Call aryList.Sort
ary = aryList.ToArray
End Sub
レポート上にテキストボックスを配置し、名前を「薬品名のフリガナ」、コントロールソースも「薬品名のフリガナ」とします。
印刷するデータではないので可視プロパティは「いいえ」にします。
五十音で並び替えたいということなので五十音のデータが必要です。薬品名から自動で五十音を作るのは現実的ではないので並び替え用に五十音のデータを用意します。>> 10の画像から使えそうなフィールド「薬品名のフリガナ」を用いていますが、見る限り五十音だけでないようなので必要であれば専用のフィールドを追加で用意してください
印刷しないデータなのでレコードセットから直接取れればいいんですが、レポートだとレコードセットを直接参照することができないのでレポート上にデータを読み込んであげる必要があります。そのため、テキストボックスを配置しコントロールを参照します
コントロールの名前プロパティとコントロールソースプロパティ(フィールド名)が同じ場合は意識する必要はないですが、別々にしている場合は注意してください
hirotonさん、有難うございます。上記の様に設定したところ、漢字、カナ、数字の区別なく五十音順に並び替えることが出来ました。ただ、ページ跨ぎになっている薬剤のページはやはりずれていますが、私としては大満足です。大変な知識不足でお手数をお掛けして申し訳ありませんでした。こういったコードを沢山見ることが向上に繋がるでしょうか?
実践あるのみですね。目的を立てて「できた!」までこぎつけてほんのちょっとレベルアップしたかもって思う感じです。
読み物としていろいろ見ておくと「自分のやろうとしてることくらいすでに誰かやっているんじゃないか?」とか「これめんどくさいな。もっと簡単な方法があるんじゃないか?」とかそういう考え方はできるようになるかもしれませんが、これが実力が付いたと言えるかというと微妙なところです。現にhirotonの回答は次々と問題が出てきて穴だらけですし
限定条件はあるもののその条件下なら今の回答でうまくいくと思っているんですが、うまくいかない部分があるということですか?それともこの条件だと目的のレポートにならないということですか?
今後継続して使用していく目的としてはとても便利で、思っていた以上のレポートです。
現にhirotonの回答は次々と問題が出てきて穴だらけですし
→ 私が条件を全て表示していなかったからです。感謝しかないです。
このスレッドの流れを細かく読んではいませんので、外しているかも知れませんが、
ちょっと思ったことを書いてみます。
レポートの最後に索引を追加したいということですよね。
ということだと、かなり難易度が高いと思います。
一つのレポートで索引も出力するというのはあきらめて、
まずは、索引なしの医薬品集レポートを出力する。
その後、索引を出力する。
というようにレポートを2つに分けたらどうでしょう。
索引用のテーブルを作成しておいて、それから索引レポートを作成しておきます。
医薬品集レポートを出力するときに、フォーマット時イベントで索引用テーブルに索引用データを出力していく。
こうすれば、並べ替えも、段組みもレポートの機能で簡単にできます。
処理の流れは下記のようなイメージです。
フォームにコマンドボタンを2つ配置。
「医薬品集レポート印刷」
「医薬品集索引印刷」
「医薬品集レポート印刷」ボタンのクリック
索引テーブル の全データを削除 → 医薬品集レポートの印刷
医薬品集レポートの詳細(またはグループヘッダー)のフォーマット時イベントで索引データを索引テーブルに追加。
上記印刷後、「医薬品集索引印刷」をクリックで索引レポートを印刷。
今の問題点は「
詳細_Format
で正確なページ数が取得できない」なので「取得後の目次データの取り扱いをどうするか」は問題の解決にならないです一応いろいろ眺めていたら解決案は出てきました(公開する段階にないですが)
これ自体は>> 7で出来てます。いろいろ議論の余地もあるかと思いますが、現時点で索引表示のためにワークテーブルを使う必要性は感じないです
エラーが出なくなったようなので続きですが、
今後の方針について
単独で1ページを超えるような出力に対応する
データに依存する仕組みじゃ使いにくいですね。対策します
同一ページ印刷プロパティ「いいえ」に対応する
一応、対策案はあります。今の想定ではそれなりにコードが複雑になるので同一ページ印刷が「はい」なら対策コードは入れなくていいかなと思っています
詳細セクションの印刷時拡張の設定
今回の手法(『目次(索引)ページを自動作成』)では
詳細_format
からページ数を取得するのことがかなり難しいことがわかりました。で、本当に今更な確認ですが、詳細セクションで印刷時拡張の設定が無ければ出力ページ数自体が元データから作れるのでは?と、ふと思ってしまいました。(謎の先入観で印刷時拡張「はい」があるものと思っていたようです)今の手法も形になりそうなのでhirotonが別手法を挙げることはないですが、一応ここで確認事項としてあげておきます
•詳細セクションの同一ページ印刷プロパティは「はい/いいえ」どちらですか?→ はい
•詳細セクションに印刷時拡張の設定はありますか? → はい
となっています。
hiroton さん、索引に印字されているページが本文のページと一致しているかもです。ページに跨ぎになっている薬剤を全て確認し、また報告をさせて頂きます。
条件を付けている通りで特別なデータ(用法・容量がすごく長くてその薬品一つだけで1ページを超えるようなデータ)があるとうまくページを取得できません
そんなデータあるわけない!なら多分うまくページが取れてると思います。適当に用法・容量が1ページを超えるようなデータを作って試してみてください。ダメな例がわかると思います
「データ」は今は良くても、今後、誰がどのように登録するかわからないなので
という方針を示しています。今後についても「そんなデータあるわけない!」なら今のコードで完成でもいいかなぁとは思います
追加の対策を考える場合、ちょっとテストしていたらグループヘッダーのセクション繰り返しの設定で動作を変えないといけないようでした。このプロパティの設定も教えてください。
hiroton さん、確認しましたが、やはり索引に印字されているページが本文のページと一致していました。完璧です。
『用法・容量がすごく長くてその薬品一つだけで1ページを超えるようなデータ』はない為、ダメな例を勉強してみます。
グループヘッダーのセクション繰り返しの設定 → 画像を添付しました。
索引の印刷プレビュー画面も添付しました。3段組、30行、文字数も制限しいている為、見栄えがよくありません。現在の薬品集が薬品名(文字数は制限なし)・・・ページ数となっている為、そのようにしてみようと思っています。自分で変えてみようと思いますが、無理だったらまた質問をさせて頂きます。
索引にページ数が入るのは仕方がないことですか?
今のコードも突っ込みどころはいろいろあるんですが、いったん完成ということにしてしまいますか。ダメな場合があるということだけは覚えておいてください。
元々見栄え自体はあまり気にしなくてもいい方法のようですから。見栄えを気にするならhatenaさん指摘のように、索引専用のレポートを作ることも検討してみましょう
ちなみに「薬品名(文字数は制限なし)」とすると発生する問題があります。どんな問題が出るのか確かめて、どうしたいか考えてみてください
ページフッターのページ数表示ですよね?索引のページ(レポートフッター)だったら非表示にすればいいと思ったんですが意外とめんどうでした
※ページ数表示は実際のコントロール名に合わせてください
hiroton さん、↑の通りやってみたところ、索引にページがのらなくなりましたが、本文のページ数に索引ページ分をカウントしているようです。
全体のページは必要ないので、 =[Page] & " ページ" としてみました。
ちなみに本文最後のページだけページ数が入らないのは何故でしょうか?
レポートフッターの改ページプロパティを「カレント セクションの前」にしてください
今の表示は同一ページ印刷「はい」の設定で、「本文の最後のページに収まらないから次のページから開始」という処理になってると思います。この場合だと本文最後のページで
レポートフッター_Format
が呼び出されます同一ページ印刷プロパティで制御
表示内容がないだけで、本文最後のページと索引最初のページ(レポートフッター)が同じページになっている
→本文の最後のページからページ数表示が非表示
改ページプロパティで制御
本文のページと索引のページは明確に分かれる
→索引だけページ数表示が非表示
もしくは改ページプロパティは弄らずに
If FormatCount = 2 Then Me!ページ数表示.Visible = False
にするとか
hirotonさん、どちらの方法も本文最後にページが入りました。
完璧です!!
2年程前、医薬品集の索引作成で大変お世話になりました。今回、この医薬品集に大分類(薬効87分類)、中分類(拡張薬効分類)を設けてレポートも作成し直した為、分類ごと(薬効87分類)の索引も欲しいと思い、hateneさんが提示されていた『目次(索引)ページを自動作成』を元にコピペしてみたのですが、テキストボックスに何もはきださない現象となっています。分からないなりに試行錯誤しましたが、どこが間違っているのかさっぱり分かりません。ご教示お願い致します。
Option Compare Database
Option Explicit
Private Sub グループヘッダー1_Format(Cancel As Integer, FormatCount As Integer)
If Me.Pages = 0 Then
Me.txt索引 = Me.txt索引 & Left(薬効87分類 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End If
End Sub
Private Sub レポートヘッダー_Format(Cancel As Integer, FormatCount As Integer)
Me.Page = 0
End Sub
↑すみません投稿し直します。
2年程前、医薬品集の索引作成で大変お世話になりました。今回、この医薬品集に大分類(薬効87分類)、中分類(拡張薬効分類)を設けてレポートも作成し直した為、分類ごと(薬効87分類)の索引も欲しいと思い、hateneさんが提示されていた『目次(索引)ページを自動作成』を元にコピペしてみたのですが、テキストボックスに何もはきださない現象となっています。分からないなりに試行錯誤しましたが、どこが間違っているのかさっぱり分かりません。ご教示お願い致します。
Option Compare Database
Option Explicit
Private Sub グループヘッダー1_Format(Cancel As Integer, FormatCount As Integer)
If Me.Pages = 0 Then
Me.txt索引 = Me.txt索引 & Left(薬効87分類 & String(12, "・"), 12) & Format(Me.Page, "@@@") & vbCrLf
End If
End Sub
Private Sub レポートヘッダー_Format(Cancel As Integer, FormatCount As Integer)
Me.Page = 0
End Sub
なにやら見覚えのあるタイトルが、と覗いてみたら懐かしい記憶が少しだけよみがえりました(ほとんど忘れてます)
今までの(薬品名を五十音ソートした)索引とはどういう関係ですか?
・削除して新たに分類ごとの索引を配置
・残したまま新たに分類ごとの索引を配置(→配置位置は?既存の索引の前? or 後 or その他)
・複合した索引を設置、薬品名は分類のグループごとに分割
・その他
hirotonさんの目にとまり良かったです。薬品名を五十音順とした索引はそのままで、分類とその
ページの索引を新たに追加したいです。五十音順の索引コードに何かあっては困るので、分類索引のコードは別で作成していました。配置は五十音順索引の前にしたいです。宜しくお願い致します。
独立した内容で新たに追加したいということであれば、改めて質問を立てたほうがいいかもしれません。既存環境に追加したいということでこの質問のURL(https://zawazawa.jp/ms-access/topic/564 )
を記載するといいと思います
今ちょっと腰を据えて手を付けられそうにないので確認と方針を挙げておきます
ひとまず分類のみの索引が出力されるか試してみる
→レポートを複製して、コードをいったん全て削除して、分類用索引のコードのみでテストする
分類の索引は出力順でいいですか?
→出力順を弄らないならコードを弄るところもほぼないと思います。(コントロール名くらい)
レポートの最初(レポートヘッダー)に出力するか最後(レポートフッター)に出力するかでコードが変わってくるので使うコードをよく見てください。また、これに合わせてコントロール(テキストボックス)の配置場所も重要かもしれません
コントロール名が正しく指定できているか?
→コントロール名
×:コントロールソースプロパティ
〇:名前プロパティ
です。
また、掲示板上のやり取りがやりやすいように具体的な名前を付けておくといいと思います
既存のコードがこの質問のコピペなら「
txt目次N
(N=0,1,2)」となっていると思います。(改めて見直したらソートしてるので「目次」じゃないですね)分かりやすいように既存のテキストボックスは
txt目次N
→txt薬品名索引N
として、今回追加する様のはtxt分類索引
とするなど分類索引も段組みにしたいのなら、その情報も必要ですね
分類だけで索引がうまく作成出来たら元のレポートと組み合わせます
既存の索引の前にということなので、レポートフッターの先頭に「txt分類索引テキストボックス」と「改ページコントロール」を挿入すればいいのでは?と思っていますがテストできていません