Microsoft Access 掲示板

6,622 件中 5,081 から 5,120 までを表示しています。
4
hiroton 2020/09/09 (水) 15:41:07 25184@f966d >> 2

新規登録(登録前)ならフィールドの規定値を書き換えてあげればいいです

Docmd.OpenForm "新規登録ページ"
Forms!新規登録ページ!案件グループID.DefaultValue = Me!案件グループID
1

まずは、下記のリンク先の関数FormRecNoをコピーして標準モジュールに貼り付ける。

B.WH |AC : 帳票フォームで表示順に連番を付ける

消したいフィールドを覆っているテキストボックス(リンク先だと txtHideB)のプロパティを下記のように変更する。

コントロールソース
=IIf(([FieldA] Like "[!A-Z]" Or [FieldA] Is Null) And [FormRecNo] Mod 2=0,"gggg","")

前景色 グレー

次にこのテキストボックスをコピーして、詳細セクションに貼り付けてから、移動させて txtHideB の上に重ねます。
プロパティを下記のように設定します。

コントロールソース
=IIf(([FieldA] Like "[!A-Z]" Or [FieldA] Is Null) And [FormRecNo] Mod 2=1,"gggg","")
前景色 白
名前 txtHideB2

このテキストボックスのフォーカス取得時のイベントプロシージャを下記のように記述します。

Private Sub txtHideB2_Enter()
    If Me.txtHideB = "" Then
        Me.FieldB.SetFocus
    Else
        Screen.PreviousControl.SetFocus
    End If
End Sub

以上でどうでしょうか。
実際に試してはいません。
FormRecNo関数は重い処理でので、実用的かどうか不明です。

3
どんぐり 2020/09/09 (水) 14:48:08 1d451@2d897

悩んでいると書いた件につきまして、
ここ1か月くらい仕様設計を悩んでいますがいい案が思い浮かばないので書かせていただきます。
同じ案件グループに入る案件データにつきまして、期限の終わりに近づいたときに
次の案件データをアクセスで準備したいのですが、すぐには案件IDが発行されない状態です。
そこで、案件フォームの帳票にタブ切り替えで「今回の情報」と「次回の情報」を表示させているのですが
今回の「次回」と次回の「今回」が冗長になってしまうため
なんとか1つで済ませられないかと考えているのですが、
案件IDがすぐに発行されないのが厄介な状態になっています。
(案件IDは主キーから外しましたが、インデックスで重複無に設定しているので、空の状態で
 データ登録ができない。)

もし、この文では意味不明だが教えていただける、という方がいらっしゃったら
モデルデータのようなものを作成してみたいと思います。

2
どんぐり 2020/09/09 (水) 14:31:07 1d451@2d897

ありがとうございます!!とても助かりました。
じっくり確認させていただきます。

この件周辺の仕様が私には難しく、どうしたものかずっと悩みあぐねております…
絡みでもう1件質問よろしいでしょうか…すみません…

サブ案件フォームに新規登録ボタンを作り、そこから案件を登録させようとしているのですが
そのとき、自動で開いた元ページの案件グループIDが入って欲しいです。
新規登録ページへの、値の受け渡しはどうすればよいでしょうか

1
hiroton 2020/09/09 (水) 11:36:26 25184@f966d

DLooukup関数で案件グループIDと一つ前の日を指定すれば案件IDは拾えますね。「一つ前」は自身より小さいものの中で最大のものということでDMax関数で拾えます

ついでに「案件グループID」と「案件発生日」の両方のデータがないと取得できないので共通して使えるように関数化して、それぞれの更新後処理に「=set前回の案件ID()」で呼び出すとかですかね

Private Function set前回の案件ID()
Dim lastDay

If IsNull(Me!案件グループID) Or IsNull(Me!案件発生日) Then Exit Function

lastDay = DMax("案件発生日", "T案件テーブル", "案件グループID=" & Me!案件グループID & " AND 案件発生日<#" & Me!案件発生日 & "#")

If IsNull(lastDay) Then Exit Function

Me!前回の案件ID = DLookup("案件ID", "T案件テーブル", "案件グループID=" & Me!案件グループID & " AND 案件発生日=#" & lastDay & "#")
End Function
2
どんぐり 2020/09/09 (水) 09:56:53 1d451@2d897

コンボボックスをrequeryすればよいのですね…
これで、沢山のことが解決しそうです。ありがとうございます!

2
ポンタ 2020/09/09 (水) 09:52:33 1d451@2d897

2GBはまだ遠そうだったので、残すことにしました。
アドバイスいただき、大変参考になりました。助かりました。
ありがとうございました。

1

①どんどん増殖してデータが重くなるのが嫌

テーブルの正規化、インデックスの設定が適切にされていれば、データ数が増えてもそれほど重くならないので気にしなくてもよいと思ってます。

②過去のデータを登録する際TODOリストはいらない(TODOを埋める手間は省きたいしうっとうしく感じる)

ちょっと意味が分かりません。不要なら、埋める必要はないのでは。
埋める必要があるとしたら、テーブル設計が間違っている可能性が大だと思います。

古いデータを削除するとしたら、Accessファイルの最大サイズ2GBに近づいてきた時ぐらいだと思ってます。
また、すぐに2GBを超えそうになるなら、Accessで扱うには大きすぎるデータだと思いますので、本格的なRDBMS(SQLサーバーとかオラクルとか・・・)への移行を検討すべきでしょう。

2
トマト 2020/09/08 (火) 12:04:48 0029a@1c915 >> 1

就業後にじっくり確認させていただきます。色々読んできたつもりなのですが、なかなか理解しきれず…
教えていただき、本当にうれしいです。読むのが楽しみです。

1

コンボボックスを Requery すればいいでしょう。
コードをどこに書くかによってコードは異なりますが、下記のようにすればどこに書いても機能します。

Forms!メインフォーム名!サブフォームコントロール名.Form!コンボボックス名.Requery
1
hiroton 2020/09/08 (火) 10:28:50 c3560@f966d

基本的なところなので解説しているサイトをいろいろ探してみると良いです
オブジェクトを入れる変数(Office TANAKAさん)

VBAでは既定のプロパティの省略というコーディングを楽にするための仕組みがあるので、その結果として違いの判らない動作もあります。以下サンプルコードを記述するので違いを比べてみてください

ex)通常の変数宣言(文字列型)

Dim txtTitle as string '//文字列型として変数を定義
txtTitle = Me.txtタイトル
'//単純な変数の代入の場合、「式」は評価され、既定のプロパティが代入される。次の式と等価
txtTitle = Me.txtタイトル.Value

MsgBox txtTitle '//"ドラゴンクエスト"が表示される。次の式と等価
MsgBox "ドラゴンクエスト"

MsgBox Me.Controls(txtTitle) '//"ドラゴンクエスト"という名前のコントロールが参照される(多分存在しないのでエラー)。次の式と等価
MsgBox Me.Controls("ドラゴンクエスト").Value 

txtTitle = Me.txtタイトル.Name '//Nameプロパティを明示したので"txtタイトル"が代入される
MsgBox Me.Controls(txtTitle) '//"ドラゴンクエスト"が表示される。次の式と等価
MsgBox Me.Controls("txtタイトル").Value 

txtTitle = "ファイナルファンタジー"
MsgBox Me.txtタイトル '//"ドラゴンクエスト"が表示される

txtTitle.SizeToFit '//ただの文字列にメソッドはないのでエラー

ex)オブジェクトとしての変数宣言(Textbox型)

Dim txtTitle as TextBox '//テキストボックス型として変数を定義
Set txtTitle = Me.txtタイトル '//objectへの代入、Setが必要

MsgBox txtTitle '//"ドラゴンクエスト"が表示される
'//txtTitleはテキストボックスなので既定のプロパティ(Value)が参照される。次の式と等価
MsgBox Me.txtタイトル.Value

txtTitle = "ファイナルファンタジー" '//テキストボックスへの代入となり、次の式と等価
Me.txtタイトル.Value = "ファイナルファンタジー" 
MsgBox Me.txtタイトル '//"ファイナルファンタジー"が表示される

txtTitle.SizeToFit '//Me.txtタイトル.SizeToFit として動作する

※ACCESSのテキストボックスにはCopyメソッドがないので2番目の例でもtxtTitle.Copyはエラーになる(ACCESSからクリップボードを操作するのはめんどくさいです)

ex)ラベルコントロールを変数にしたい

Dim myLbl As Label
Set myLbl = Me!lblタイトル
myLbl.ForeColor = RGB(255, 0, 0)
3

そちらのフォームの状況が分からないので、下記のようだと想定してコーディングしています。

メインフォーム
名前 商品フォーム
商品フォームのレコードソースのテーブル(商品テーブル?)に「最新購入日」フィールドがある。

サブフォーム
名前 サブ案件フォーム
レコードソース T_案件
T_案件 には「購入日」フィールドがある

①VBA内の「Me!最新購入日」については「サブフォームコントロール名.Form!最新購入日」と
 しなくてよいのでしょうか。

Me!最新購入日はレコードソースの「最新購入日」フィールドになります。

If Me!最新購入日 =  Me.txt最新購入日 Then
「最新購入日」フィールドの値と「txt最新購入日」テキストボックスの値が等しいか判定してます。
「txt最新購入日」のコントロールソースは=[サブフォームコントロール名].Form![最新購入日]ですので
サブフォームの最新購入日になります。
つまり、メインフォームの「最新購入日」フィールドとサブフォームの「最新購入日」が一致しているかどうかの判定です。

②Me!最新購入日 =  Me.txt最新購入日 についてですが、
 式の左側に右側を代入するイメージだと思っていたのですが、この場合は
 Me.txt最新購入日  =  Me!最新購入日 にならないのでしょうか。

「左側に右側を代入する」であってます。
IfのElse節に入ってますので、
メインフォームの「最新購入日」フィールドとサブフォームの「最新購入日」が一致していなかったら、
サブフォームの「最新購入日」をメインフォームの「最新購入日」フィールドに代入しています。
これでサブフォームの「最新購入日」とメインフォームの「最新購入日」は常に一致していることになります。

2
どんぐり 2020/09/07 (月) 23:28:57 0029a@1c915

ありがとうございました!ところで理解力がなく申し訳ないのですが、
わからない点があり、教えていただけませんでしょうか…

①VBA内の「Me!最新購入日」については「サブフォームコントロール名.Form!最新購入日」と
 しなくてよいのでしょうか。
②Me!最新購入日 =  Me.txt最新購入日 についてですが、
 式の左側に右側を代入するイメージだと思っていたのですが、この場合は
 Me.txt最新購入日  =  Me!最新購入日 にならないのでしょうか。

5
トマト 2020/09/07 (月) 23:17:00 0029a@1c915 >> 4

>今回の質問も雰囲気的には数値型に変えてしまってもいいように見えます

アドバイスありがとうございます。見た目が数値なのに数値とテキストが混ざっていると
自分も勘違いしたり引継時にもわずらわしいかなと思って悩んでいました。
全て数値に合わせる方向で検討してみようかと思います。
ありがとうございます!

4
セロハン 2020/09/07 (月) 22:57:59 0029a@1c915 >> 1

こちらでバッチリ思い通りのものができました。ありがとうございました。

3

MSForms.DataObjectオブジェクトを使うとクリップボードのデータを直接取得でしたり設定できます。

クリップボードとデータのやりとりをする:Excel VBA|即効テクニック|Excel VBAを学ぶならmoug

1

デザインビューで高さを調整したいコントロールを選択して、リボンの[サイズ/間隔]→[自動調整]をクリックするとフォント高にあった高さに調整されます。
こういうことでしょうか?

14
セロハン 2020/09/07 (月) 17:51:45 0029a@1c915

なぜ頭にANDがついているのか疑問だったので、6の件と共にようやく理解できました。
丁寧に解説していただき、助かりました。
「dbText」も何かわからず、逆にネットで検索して10にしてしまっていたのですが、同じものだったのですね…教えていただきありがとうございます!

2
hiroton 2020/09/07 (月) 17:14:56 2d6b2@f966d

クリップボード弄るあれこれ調べてたんですけどパッとしないですねぇ

Dim strClip As String

If Nz(Me!txtデータ) = "" Then
    'クリップボードのデータをコピー'
    Me!txtデータ.SetFocus
    DoCmd.RunCommand acCmdPaste
    Me.Recalc 'これを入れないとコード実行中に張り付けた値が反映されない'
End If

If Nz(Me!txtデータ) = "" Then Exit Sub

strClip = Me!txtデータ
Me!txtデータ = Null

'クリップボードのデータを削除'
CreateObject("WScript.Shell").Run "cmd /c ""echo off | clip""", 0

「クリップボードからの直接取込」または「txtデータに入力からの取込」の両方に対応して、2重取込防止(取込実行でtxtデータとクリップボードを消去)みたいなイメージで

13
hiroton 2020/09/07 (月) 16:49:01 2d6b2@f966d

Mid関数もちゃんと使ってください

DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter, 6), , acNormal
'または'
DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter, Len(" AND ") + 1), , acNormal

6はマジックナンバーってやつですね。テンプレ的な記述ですが、意味のある形で記述しておくと後で見直した時も何をやっているのか分かりやすいコードになります

こういった検索なんかで複数の中からいくつかを選ぶ場合、例えば
「A and B and C」
「B and C」
「A and C」
「A」
のように、選択された項目数nに対して連結するための文字列がn-1必要という形になります。
コードを記述するなら

If (Aの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Aの条件
End If
If (Bの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Bの条件
End If
If (Cの条件があった場合) Then
  If strFilter <> "" Then strFilter = strFilter & " AND "
  strFilter = strFilter & Cの条件
End If

のように、毎回Ifでチェックしてもいいんですが、

If (Aの条件があった場合) Then strFilter = strFilter & " AND " & Aの条件
If (Bの条件があった場合) Then strFilter = strFilter & " AND " & Bの条件
If (Cの条件があった場合) Then strFilter = strFilter & " AND " & Cの条件

If strFilter <> "" Then
  '先頭に必ずいらない" AND "がついているので取り除く'
  strFilter = Mid(strFilter, Len(" AND ") + 1)
End If

のように作りこむとコードがすっきりするというテクニックです。このテクニックを使っているので、最後にフィルター文字列を指定する部分でMid(strFilter, 6)とするわけです


ついでですが
BuildCriteria関数の2番目に指定している「10」もマジックナンバーってやつです。関数の動きを切り替えるためのいわばモード指定なんですが、ここにはデータ型を指定することとなっています
標準関数で使うこういう数値には組み込み定数というのが用意されていて、このデータ型の場合、DataTypeEnum 列挙 (DAO)が使えます

BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")
'次の記述でも同じ'
BuildCriteria("伝票NO", dbText, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

「10」だと10ってなんだよってなりますが「dbText」だと何となく意味がわかりますね。何か調べようと思った時も「dbText」なら検索のキーワードに使いやすいです

1

タブ区切りデータは、見出しなし、
追加先のテーブルとフィールドの並び順は同じとします。

フォーム上には、下記のコントロールが配置してあるとします。
テーブル名を入力するテキストボックス「txtテーブル名」
タブ区切りデータを貼り付けるテキストボックス「txtデータ」
クリックするとテーブルにデータ追加するコマンドボタン「データ追加」

Private Sub AddData(tblname As String, ByRef s As String)
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim a, i As Long, j As Long
    Dim Datas

    Set db = CurrentDb
    Set rs = db.OpenRecordset(tblname)
    a = Split(s, vbNewLine)
    For i = 0 To UBound(a)
        Datas = Split(a(i), vbTab)
        rs.AddNew
        On Error Resume Next
        For j = 0 To UBound(Datas)
            rs(j) = Datas(j)
        Next
        On Error goto 0
        rs.update
    Next
End Sub

Private Sub データ追加_Click()
    Call AddData(Me.txtテーブル名, Me.txtデータ)
End Sub

こんな感じです。

12
セロハン 2020/09/07 (月) 15:49:45 0029a@1c915

数値の左右には*の半角も入っています。(表示で消えています)

11
セロハン 2020/09/07 (月) 15:48:31 0029a@1c915 >> 10

なぜかコードが消えてしまったのでもう一度記載します。
DoCmd.OpenForm "F_案件", acNormal, "", strFilter, , acNormal

このときのstrFilterに格納された変数
⇒" AND 案件NO Like "0001" And 案件NO Like "0002""

10
セロハン 2020/09/07 (月) 15:46:05 0029a@1c915 >> 9

ありがとうございます。
おっしゃるとおり、「10」のところはお手本にしたコードの数字(6)が理解できず、
そのまま何やら勘違いして変更してしまっていました…
下記コードで実行してみたところ、絞り込み件数は0となりましたがエラーは出ませんでした。
伝票NO「0001 0002」を表示したいのですが、


strFilterに格納された変数
⇒" AND 伝票NO Like "0001" And 伝票NO Like "0002""

どこをなおせばよいのでしょうか…

6

今日は無理ですが、明日、出先にAccess2013環境があるので試してみます。

9
hiroton 2020/09/07 (月) 15:12:52 2d6b2@f966d

ちゃんと内容見てないけど
DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal

DoCmd.OpenForm "F_案件", acNormal, "", Mid(strFilter,10), , acNormal

ここの「10」って数値もあんまり見ないので(正しいのかどうかわかりません)、このあたりプログラムがどう動くのかという基本を見直してみるといいと思います

8
セロハン 2020/09/07 (月) 14:50:06 0029a@1c915

上記7番にて、以前いただいた投稿に返信したのですが
新しい投稿がわかりづらいかもしれないため、改めて下に追記させていただきます。
スミマセン。(コードブロックも間違えておりました)
↓ ↓
以前教えていただいた検索フォームを作成中です。
そこで、教えていただいたサイトを参考に下記コードを作成しましたが、うまく動きません。

    Dim strFilter As String, strExp As String, aryOpe As Variant
'途中省略     
 
If Not IsNull(Me.txt伝票NO) Then
         strFilter = strFilter & " AND " & BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

    End If
         DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal

End Sub

①txt伝票NOに、改行区切りで入れられた複数の伝票NOについて
全て検索する。
②伝票NOは短いテキスト。

上記のコードを使うと「strFilter」のパラメータを聞いてきます。
エラー行は
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal です。

7
セロハン 2020/09/07 (月) 14:40:30 0029a@1c915 >> 3

以前教えていただいた検索フォームを作成中です。
そこで、教えていただいたサイトを参考に下記コードを作成しましたが、うまく動きません。

""" If Not IsNull(Me.txt伝票NO) Then
        strFilter = strFilter & " AND " & BuildCriteria("伝票NO", 10, "" & Replace(Me.txt伝票NO, vbCrLf, " And ") & "")

    End If
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal
"""

①txt伝票NOに、改行区切りで入れられた複数の伝票NOについて
全て検索する。
②伝票NOは短いテキスト。

このコードを使うと「strFilter」のパラメータを聞いてきます。
エラー業は
        DoCmd.OpenForm "F_案件", acNormal, "", "Mid(strFilter,10)", , acNormal です。

5
tetsusi 2020/09/07 (月) 14:24:46 28ccc@a46a9

デザインビューで試してみたところ4件、5件と追加できていました…
正直なところ2016でなぜこのエラーが出るのか分かりません

4
hatena 2020/09/07 (月) 13:07:09 修正

手元にあるフォームで試してみましたが、6件登録してもエラーにはなりませんでした。

テーブルとか作るのは面倒なので、色は配列にしました。

Private Sub Form_Load()
    Dim Fmt As FormatCondition

    Dim Colors
    Colors = Array(vbRed, vbGreen, vbYellow, vbBlue, vbMagenta, vbCyan)
    With Me!名前.FormatConditions
        .Delete
        Dim i As Long
        For i = 0 To UBound(Colors)
           Set Fmt = .Add(acExpression, acEqual, "[ID]=" & i + 1)
           Fmt.ForeColor = Colors(i)
        Next
    End With
End Sub

画像1

Access2019ですので、ひょっとしてバージョンで違うのかな。
デザインビューで手作業で条件書式を追加したときは4件以上でも登録できますか。

12
hiroton 2020/09/07 (月) 10:53:09 2d6b2@f966d

キーワードが「汎用関数」よりも「ユーザー定義関数」のほうが欲しい情報がより多く見つかるだろうくらいの話なのでその「使いどころ」は気にしなくていいですよ

4
hiroton 2020/09/07 (月) 10:26:31 2d6b2@f966d

「サロゲートキー」「ナチュラルキー」という考え方があります

例えば、「型番」なんかはユニークであることも多いのでそのまま主キーとしたりすることがあります。英数混合だったりするとテキスト型である必要があったりもします

でもだいたい「型番」がユニークかどうかわからないという恐怖体験を味わうのでIDフィールドを作ってオートナンバー振ってしまいます

実務では、このように混在させることはよくあることなのでしょうか?

必要に応じて設定すればおのずとそうなるというものですね。また、外部とデータのやり取りをする場合はどうしてもデータ的にはテキスト型(文字列)となってしまうので、インポート時に数値に変換するというのもよくある話です。今回の質問も雰囲気的には数値型に変えてしまってもいいように見えます


「00000」が存在するので、新規が全部「00000」のデータになってしまい諦めました。

テーブル設計でフィールドの規定値を設定すると回避できます。数値型のフィールドはデフォルトの規定値が「0」なのでこの値を変える(または削除する)と良いでしょう

2
tetsusi 2020/09/07 (月) 10:21:18 28ccc@a46a9

ありがとうございます
実際のコードは以下のようになっています

Dim Db      As DAO.Database
Dim Rs      As Recordset
Dim StrSQL  As String
Dim Fmt     As FormatCondition

Private Sub Form_Load()
    Set Db = CurrentDb
    StrSQL = "SELECT DISTINCT 文字色 FROM 項目MT ORDER BY 文字色"
    Set Rs = Db.OpenRecordset(StrSQL, dbOpenSnapshot)
    Me!項目.FormatConditions.Delete  →ここで削除してるはず
    Do Until Rs.EOF = True
        Set Fmt = Me!項目.FormatConditions.Add(acExpression, acEqual, "[文字色] = " & Rs!文字色)
        Fmt.ForeColor = Rs!文字色  → ループ4回目のここでエラーになります
        Rs.MoveNext
    Loop
End Sub

11
ポンタ 2020/09/07 (月) 10:11:18 0029a@1c915

お気にかけてくださり、ありがとうございます。
とりあえず値渡しで、変数の中身だけ変えてそれぞれの処理を呼び出すようにすることはできるようになりました。
ユーザー定義関数の使いどころはピンときていないので、コード、説明等書き換える時間が取れたらまた相談させていただきたいです。その際は宜しくお願いいたします。

10
hiroton 2020/09/07 (月) 08:14:38 2d6b2@f966d

一度ユーザー定義関数をキーワードに調べてみることをおすすめします

6

下記の関数を作成して、

Public Sub CtlVCenter2(ReportName As String, ControlName As String, ControlName1 As String, ControlName2 As String)
    DoCmd.OpenReport ReportName, acViewDesign
    
    Dim R As Access.Report
    Set R = Reports(ReportName)
    
    Dim C As Access.Control
    Set C = R.Controls(ControlName)
    Dim C1 As Access.Control
    Set C1 = R.Controls(ControlName1)
    Dim C2 As Access.Control
    Set C2 = R.Controls(ControlName2)
    
    C.Top = (C1.Top + C2.Top) / 2
End Sub

イミディエイトで下記を実行。

Call CtlVCenter2("レポート名", "フィールド3", "フィールド1", "フィールド2")

以上でどうでしょうか。

5

フィールドを挟むように線を二本引いて
上下の間隔を均等にする、をすると対処できるようですね

4

ありがとうございました

レポートの真ん中に移動されましたが
先述しました、あるフィールドを中央として配置することは不可能ですか?

フィールド1
      フィールド3
フィールド2

ということです

3

標準もモジュールに下記のような関数を作成します。

Public Sub CtlVCenter(ReportName As String, ControlName As String)
    DoCmd.OpenReport ReportName, acViewDesign
    
    Dim R As Access.Report
    Set R = Reports(ReportName)
    
    Dim C As Access.Control
    Set C = R.Controls(ControlName)
    
    C.Top = (R.Section(C.Section).Height / 2) - (C.Height / 2)
End Sub

イミディエイトウィンドウで下記のように記述してEnterキーを押します。

Call CtlVCenter("レポート名", "コントロール名")

これで、レポートがデザインビューで開いて、指定したコントロールがセクションの上下中央位置に移動します。
デザインビューを確認して問題なければ保存して閉じれば完了です。