ChangeDataクラスのShtAndShtプロシージャを用いてShee1の各品番と型式名、品名をSheet2のそれぞれのセルにコピーします
業務に必要なマスタデータを処理する過程でアクセスのフィールドのあるレコードの値をユーザーフォームのテキストボックスやワークシートのセルにコピーするなど、異なるオブジェクト間でデータのコピー・ペーストを行うことが多くなってきたので、それをChangeDataクラスで作ってみました。
データのやり取りをするのは、以下の6パターン(読み込み先と書き込み先)です
アクセスのレコード⇔ワークシートのセル
アクセスのレコード⇔ユーザーフォームのテキストボックス
ワークシートのセル⇔ユーザーフォームのテキストボックス
現在ChangeDataクラス内のそれぞれのプロシージャでforループを回して処理しているのですが、それをクラスモジュールではなく、標準モジュールからforループ処理をすることを考えています。
単純に考えたら、ShtAndSht関数にstartRowとEndRow、LengthOfArray を渡せば良いのかな思ったのですが、そうすると省略不可の引数が7個になってしまうので、これはさすがに多すぎると感じています。
そこで、引数を別の形で処理して減らす方法などありましたら教えていただければ幸いです。
今一つクラスモジュールの使い方をつかめていないので、何卒わかりやすい説明をお願い致します。
標準モジュール(自作クラスモジュールの現状の使用例)
Sub test1() Dim cd As ChangeData Set cd = New ChangeData Dim makeArr As MakeStrArrForSetObject Set makeArr = New MakeStrArrForSetObject Dim Readlist() As Variant Dim Writelist() As Variant Readlist() = makeArr.ArrPartNum Writelist() = makeArr.ArrPartNum 'このモジュールでループ処理を行いたい Call cd.SheAndSht("Sheet1", "Sheet2", Readlist(), Writelist()) End Sub
###クラスモジュール1 MakeStrArrForSetObj
Private Const Partnum = "品番" Private Const Model = "型式名" Private Const Item = "品名" Public Function ArrPartNum() As Variant() ArrPartNum = Array(PartNum, Model, Item) End Function
###クラスモジュール2 ChangeData
Public Sub SheAndSht(ByVal TarShtToREAD As String, ByVal TarShtToWRITE As String, ByRef ReadList() As Variant, ByRef WriteList() As Variant) Dim CntRow As Long Dim readobj As Object Dim writeobj As Object Dim StartRow As Long Dim EndRow As Long Dim LengthOfArray As Long Dim reObj As returnObject Set reObj = New returnObject StartRow = 3 EndRow = 10 'ここの二重ループをクラスモジュールの外に出し、さらに関数に渡す引数を減らしたい For CntRow = StartRow To EndRow For LengthOfArray = LBound(ReadList) To UBound(ReadList) Set reObj.Cls_ws = Worksheets(TarShtToREAD) Set readobj = reObj.SetObjToRead("CELL", ReadList(), LengthOfArray, CntRow) Set reObj.Cls_ws = Worksheets(TarShtToWRITE) Set writeobj = reObj.SetObjToWrite("CELL", WriteList(), LengthOfArray, CntRow) writeobj.Value = readobj.Value Next LengthOfArray Next CntRow End Sub
###クラスモジュール3 returnObject
・クラス変数 Public Cls_ws As Worksheet Public Cls_ADORes As ADODB.Recordset Public Cls_Frm As UserForm Public Function SetObjToRead(ByVal strTarObj As String, ByRef Cls_strArrForSetObj() As Variant, ByVal TarCol As Long, Optional TarRowForCell As Long = 1) As Object 'データを読み込む(コピーする)オブジェクトを選択 Select Case strTarObj Case "CELL" Set SetObjToRead = ObjCell(Cls_strArrForSetObj(TarCol), TarRowForCell) Case "FIELD" Set SetObjToRead = ObjField(Cls_strArrForSetObj(TarCol)) Case "CONTROL" Set SetObjToRead = ObjControl(Cls_strArrForSetObj(TarCol)) End Select End Function Public Function SetObjToWrite(ByVal strTarObj As String, ByRef Cls_strArrForSetObj() As Variant, ByVal TarCol As Long, Optional TarRowForCell As Long = 1) As Object 'データを書き込む(ペーストする)オブジェクトを選択 Select Case strTarObj Case "CELL" Set SetObjToWrite = ObjCell(Cls_strArrForSetObj(TarCol), TarRowForCell) Case "FIELD" Set SetObjToWrite = ObjField(Cls_strArrForSetObj(TarCol)) Case "CONTROL" Set SetObjToWrite = ObjControl(Cls_strArrForSetObj(TarCol)) End Select End Function Private Function ObjCell(ByRef Cls_strForSetObj As Variant, ByVal TarRow As Long) As Range Set ObjCell = Cls_ws.Cells(TarRow, ColSlctByTitle(Cls_strForSetObj, Cls_ws)) End Function
#修正
追加の返信をいただく前に標準モジュールにしてしまいました。申し訳ないです。
アクティブシートのデータを取得したい行を「行番号」のテキストボックスに入力してから、「コピー元決定」ボタンを押すとcmdC_DecideParts_Clickが動きます
データのやりとりを行うオブジェクトはSetObjToRead関数とSetObjToWrite関数で決めており、どのオブジェクトのどの要素をやりとりの対象とするのかを文字列として渡すことで目的のオブジェクトを決めています。
(例:データを読み込みたい(値をコピーしたい)オブジェクトをアクティブシートの7行目にある品番列のRangeオブジェクトにする場合)
→strTarObjName="CELL"、TarRowForCell=7,strTarElement="品番",TarObj=ActivesheetをSetObjToRead関数に引数として渡す
セルをデータのやり取りの対象にしたい場合は単純に列番号を渡すと列の順番を変更できないので、さらにcolslctbytitle関数に列名を文字列として渡して、渡した文字列とシートの列名が一致したらそのときの列番号をcolslctbytitle関数の返り値としています
ReadArray(),WriteArray()ではSetObjToRead関数とSetObjToWrite関数に渡すための文字列を決めています
現状はShtToFrm関数のように(データの読み込み先:Worksheet)To(データの書き込み先:UserForm)として関数の名前を付けていますが、6パターン文の関数(ShtToFrm,FrmToSht,ShtToAccessDB,AccessDBToSht,FrmToAccessDB,AccessDBToFrm)
(データの書き込み先がAccessDBの場合は新規追加と更新もあるので、さらに関数が増えそう)
を作るのではなく、2,3つの関数にまとめられたらと考えています。
ユーザーフォームのモジュール(FrmCopyContentsInfoOfParts)
Private Sub cmdC_DecideParts_Click() Dim TarRow As Integer TarRow = Me.txtRowNum.Value Dim ReadArray() As Variant Dim WriteArray() As Variant '配列の要素はそれぞれ対応していなければならない(e.g:品番⇔txtC_PartNum) ReadArray() = Array("品番", "図番", "図番改定", "品名", "型式名", "アキクラコード", "メーカー名", "メーカーコード", "仕入先", "仕入先コード", "標準原価単価", "標準発注単価", _ "ロット発注", "ロット単位数", "部品_在庫小数桁", "在庫用発注_棚卸変換値", "標準発注LT", "製番製品No_ロットNo", _ "部品単位", "発注単位", "品番分類", "在庫分類", "発注手配", "引当手配", "品番備考") WriteArray() = Array("txtC_PartNum", "txtC_ChartNum", "txtC_ChartNumRev", "txtC_Item", "txtC_Model", "txtC_AkikuraCode", "txtC_maker", "txtC_MakerCode", "txtC_Vendor", "txtC_VendorCode", "txtC_Price", "txtC_OrderPrice", _ "txtC_Lot", "txtC_LotQty", "txtC_Digit", "txtC_ConversionValue", "txtC_LT", "txtC_LotNo", _ "txtC_PartsUnit", "txtC_OrderUnit", "txtC_PartNumClassCode", "txtC_StockClassCode", "txtC_OrderArrgtCode", "txtC_AllocArrgtCode", "txtC_Remark") Call ShtToFrm(ReadArray(), WriteArray(), TarRow) End Sub
以下、標準モジュール
Public Sub ShtToFrm(ByRef strArrayToRead() As Variant, ByRef strArrayToWrite() As Variant, ByVal TarRow As Long) If UBound(strArrayToRead) <> UBound(strArrayToWrite) Then MsgBox "読み込み先の配列の要素数と書き込み先の配列の要素数が違います" & vbCrLf & "処理を中止します" Exit Sub End If Dim StartRow As Long Dim LengthOfArray As Long Dim ReadObj As Object Dim WriteObj As Object For LengthOfArray = LBound(strArrayToRead) To UBound(strArrayToRead) Set ReadObj = SetObjToRead("CELL", ActiveSheet, strArrayToRead(LengthOfArray), TarRow) Set WriteObj = SetObjToWrite("CONTROL", FrmCopyContentsInfoOfParts, strArrayToWrite(LengthOfArray)) WriteObj.Value = ReadObj.Value Next LengthOfArray End Sub
前回ではSetObjToReadやSetObjToWriteに配列を渡していたので、それを配列内の文字列を直接渡すようにしたのですが、こうしてみるとShtToFrmにも配列で渡す必要なかったですね
そうすれば、forループを関数の外で処理できそうです
Option Explicit Public Function SetObjToRead(ByVal strTarObjName As String, ByVal TarObj As Object, ByVal strTarElement As String, Optional TarRowForCell As Long = 1) As Object 'データを読み込む(コピーする)オブジェクトを選択 On Error GoTo Err Select Case strTarObjName Case "CELL" Set SetObjToRead = TarObj.Cells(TarRowForCell, ColSlctByTitle(strTarElement, TarObj)) Case "FIELD" Set SetObjToRead = TarObj.Fields(strTarElement) Case "CONTROL" Set SetObjToRead = TarObj.Controls(strTarElement) End Select Exit Function Err: Call ErrHndl(Err.Number, Err.Description) End Function Public Function SetObjToWrite(ByVal strTarObjName As String, ByVal TarObj As Object, ByVal strTarElement As String, Optional TarRowForCell As Long = 1) As Object 'データを書き込む(ペーストする)オブジェクトを選択 On Error GoTo Err Select Case strTarObjName Case "CELL" Set SetObjToWrite = TarObj.Cells(TarRowForCell, ColSlctByTitle(strTarElement, TarObj)) Case "FIELD" Set SetObjToWrite = TarObj.Fields(strTarElement) Case "CONTROL" Set SetObjToWrite = TarObj.Controls(strTarElement) End Select Exit Function Err: Call ErrHndl(Err.Number, Err.Description) End Function Private Sub ErrHndl(ByVal ErrNum As Long, ByVal ErrDiscription As Variant) Select Case ErrNum Case Else MsgBox "エラー番号:" & Err.Number & vbCrLf & "エラーの種類:" & ErrDiscription End Select End Sub
Public Const StartRow = 5 Public Function ColSlctByTitle(ByVal Title As String, ByVal ws As Worksheet, Optional ByVal DefaultRow As Integer = StartRow) As Integer Dim CountCol As Integer Dim titleRow As Integer Dim MaxCol As Integer titleRow = DefaultRow ' タイトル行番号 With ws MaxCol = .Cells(DefaultRow, .Columns.Count).End(xlToLeft).Column For CountCol = 1 To MaxCol If .Cells(titleRow, CountCol).Text() = Title Then ColSlctByTitle = CountCol Exit Function ' 正常終了 End If Next End With 'エラー終了 Err.Description = ws.Name & "のタイトル行に指定文字列( " + Title + " ) が見つかりませんでした" Err.Raise (60000) MsgBox (Err.Description) End Function
回答1件
あなたの回答
tips
プレビュー