• 締切済み

ExcelVBAについてです。

ユーザーフォーム1に縦に4つ横に4つの計16個のコンボボックスとコマンドボタンが1つ存在するとします。横の4つのコンボボックスを1つのまとまりとして、16個のコンボボックスを4つのまとまりにします。例えば、1つ目のまとまりに含まれるコンボボックスに全て入力が行われていたら、アクティブシートのB2~E2のセルに入力を行えるようにしたいのです。さらに、その中の1つに入力が行われていないコンボボックスがある時、「入力されていない項目があります」というメッセージを出したいと考えています。また、1つ目と2つ目のまとまりを入力する際は、1つ目と2つ目のまとまりのコンボボックスの計8個に入力がされていない項目がないか調べて、全て入力されていたら下のセルへとどんどん書き込むようにし、入力されていない項目がある際は、同じ警告文を出したいのです。同様に、3つ目のまとまりまで入力した際は、1つ目~3つ目を調べ、同じ動作を行います。4つ目のまとまりも、1つ目~4つ目を調べるようにし同じ動作を行います。どなたかご教授おねがいしますm(__)m

みんなの回答

  • imogasi
  • ベストアンサー率27% (4737/17070)
回答No.2

私の力では、てこづりりました。一応やってみたので、参考にしてください。 質問者の現状のプログラム力はわからないが、仕様をもっと単純にすることをお勧めします。 なお、クラスClassの考え方は利用してません。 == 道具だて Sheet1=入力データが蓄積されるシートのシート名 Sheet2⁼コンボに設定するアイテムの(文字列?)の入力しておく場所 A-P列 Userform2=入力するユーザーフォーム これらの名前指定は、ご存じでしょうが、プログラムの該当箇所を変えれば、自由に変えられる。 ==== エクセルVBAでユーザーフォーム上に、コントロールを多数個「動的に作製して」、サイズや位置をプログフラムで整える方法は、よくやっていて、できたのですが、ユーザーフォームを閉じたとき、コントロール等の状態が、保存されないので、これではどうかな、と思い、手動で下記コントロール関連の処理は手動で行った。 この点は小生の知識不足かもしれない。(SaveやUnloadやWEBを調べたが分らなかった)。 (1)ユーザーフォームに、コンボ16個(4列4行)とコマンドボタン1つを張り付けます。 手動で貼りつけます。 (A)コンボ ユーザーフォームに1つツールボックスよりD&D 横方向にコピペ3回(計4つ)。その4個を縦方向に3回コピペ。  VBE画面の「整列」で、4X4個の位置を揃える。 サイズと位置や間隔はご自由に設定。 (B)コマンドボタン 1つツールボックスからD&D Captionは、私は「シートへ転記」としておく。 (2)各コンボのアイテムの設定をエクセルVBAで行う。 (A)Sheet2のAーP列まで16列の各行に、「各コンボに設定するアイテム」を 入力しておく。 (B)ユーザーフォームUserForm2のInitializeイベントで、各コンボのRowSourceの セル範囲の設定を行う。その際、各列ごとに、データ最終行をプログラムで、捉えて、そこまでの行データをRowSourceプロパティに設定する。 Private Sub UserForm_Initialize() With UserForm2 For i = 1 To 16 dl = Worksheets("Sheet2").Cells(100, i).End(xlUp).Row With .Controls("ComboBox" & i) .RowSource = "Sheet2!" & Chr(64 + i) & "1:" & Chr(64 + i) & dl End With Next i End With End Sub (3)コマンドボタンのClickイベントで、 (A)入力(選択)済のデータのチェック(といっても有無だけですが)と (B)Sheet1にその入力データ設定(転記)を行う。 終わったらコンボの選択を解除する。 (2)ユーザーフォームは UserForm2を使う。 (3)は、コンボで選択したアイテムの値をコマンドボタンのクリックイベントで、Sheet1のセルに設定設定する。今までの入力行の次行から累積していく。 '====メイン2 'コンボの値のチェックとシートSheet1のセルに転記 Private Sub CommandButton1_Click() '--- s = "" kara = 1 made = 4 '---チェック For i = 1 To 16 Vl = Me.Controls("ComboBox" & i).Value If i = 5 Or i = 9 Or i = 13 Then 'MsgBox i & "に来た" If s = "y" Then MsgBox kara & "-" & made & "未入力コンボあり。補完入力せよ" Exit Sub End If s = "" kara = i made = i + 3 End If If Vl = "" Then s = "y" End If Next i '---シートへ転記 st = Worksheets("Sheet1").Cells(100000, 1).End(xlUp).Row + 1 MsgBox "Sheet1の第" & st & "行から記録" '-- For i = 1 To 16 '16個のコンボを対象に繰り返し With Me.Controls("ComboBox" & i) r = Int((i - 1) / 4) + st c = ((i - 1) Mod 4) + 1 Worksheets("Sheet1").Cells(r, c) = Me.Controls("ComboBox" & i).Value 'データをシートへ転記 End With Next i End Sub ーーーーー 操作・使用方法説明 VBE画面をだして、プロジェクト画面のUserForm2を指定 オブジェクトの表示ー>UserForm2が現れるのでそれを選択しておく 実行ーSUB/ユーザーフォームの実行を選択。 UserForm2が受付状態になる。 データを入力=>コンボの16個について、1個のアイテムを選択クリック。16個について繰り返す。選択し終わると Commndbutton1(Captionは(私の場合)「シートへ転記」とした)をクリックー>チェック作業とSheet1へデータセットがなされる。 ・終了はユーザーフォームの閉じるボタンXをクリック ・未入力コンボがあれば注意コメントを出し、元のユーザーフォームに戻るので それらの未入力コンボに入力して、コマンドボタンをクリックする(それ以外のコンボは元のままで画面に残っているから) == 注意 この回答のポイントは、多数あるコンボの指定を  .Controls("ComboBox" & i) で行っている、という処理にあります。 VBAでは、コントロール配列が使えないので、コンボの特定には、Combobox○○の○○の数字が頼りです。だから ユーザーフォーム上で 1-2-3-4 5-6-7-8 ・・ の順序に並びになるよう名前を付けて、かつ配置してください。 一旦コントロールを貼り付けて、一部を何かの事情でDeleteすることはしない方がよい。

すると、全ての回答が全文表示されます。
回答No.1

こんにちは。 1) コマンドボタンを押した時に、 2) コンボボックス の入力状況が     1-4まで入力済である場合、     1-8まで入力済である場合、     1-12まで入力済である場合、     1-16まで入力済である場合、      以上の場合は入力済のデータをすべて出力     それ以外の場合は、      '「入力されていない項目があります」というメッセージ' 3) 出力先は 'アクティブシートの' B:E列 最下行 直下の空セル ということで宜しいでしょうか? 〓以下、実際に作成したテスト用サンプルブックの概要です。  (オブジェクト名)   'ユーザーフォーム1'             UserForm1     '横の4つのコンボボックス...のまとまり' 【1】                         ComboBox1、ComboBox2、ComboBox3、ComboBox4     '横の4つのコンボボックス...のまとまり' 【2】                         ComboBox5、ComboBox6、ComboBox7、ComboBox8     '横の4つのコンボボックス...のまとまり' 【3】                         ComboBox9、ComboBox10、ComboBox11、ComboBox12     '横の4つのコンボボックス...のまとまり' 【4】                         ComboBox13、ComboBox14、ComboBox15、ComboBox16     'コマンドボタンが1つ'          CommandButton1   新規に追加挿入するクラスモジュール     Class1 〓 一応、ご質問で例示されたオブジェクトに対して、 こちらでテスト用(動作確認用)に仮に付けた名前や条件設定、 をメモしておきました。 これだけ準備すれば、 仮に、私が提示するスクリプトをそちらでの実情に合わせて修正することが難しかったとしても、 新規のブックで簡単に内容(動作)を確認することが出来るようにと、という意図で書いています。 何れにしても、動かしてみた上で何かこちらの誤解があるようでしたらば、補足ください。 或いは、ComboBoxのオブジェクト名が順番通りに並んでいない状況への対策が必要な場合は、 '横の4つのコンボボックス...のまとまり' 4つ毎に、ComboBoxのオブジェクト名の対応を示してください。 そちらで確認しておいて欲しい技術的な要件は、 「Bit演算」「VBA クラスモジュール」などのキーワードで、調べてみて下さい。 '〓以下、上記条件で動作確認した、UserForm1 モジュールの記述内容です。 ' ' === UserFormモジュール === Option Explicit Private colClassCbx As New Collection Private Const Filled1 = 15, Filled12 = 255, Filled123 = 4095, Filled1234 = 65535 Private nBit As Long ' ' = 以上、モジュール先頭、宣言部 = Private Sub UserForm_Initialize() Dim i As Long   For i = 1 To 16     colClassCbx.Add New Class1, CStr(i)     colClassCbx(CStr(i)).IntClass Me.Controls("ComboBox" & i), 2 ^ (i - 1)   Next i End Sub Private Sub CommandButton1_Click() Dim nRowPos As Long Dim i As Long   Select Case nBit   Case Filled1, Filled12, Filled123, Filled1234     nRowPos = Cells(Rows.Count, "B").End(xlUp).Row + 1     With Cells(nRowPos, "B").Resize(4, 4) '      For i = 1 To Int(Log(nBit) / Log(2)) + 1       For i = 1 To Log(nBit) / Log(2)         .Cells(i) = colClassCbx(CStr(i)).Value       Next i     End With   Case Else     MsgBox "入力されていない項目があります"   End Select End Sub Public Sub RcvCbx(ByVal nCbxIdx As Long, ByVal IsNull As Boolean)   If IsNull Then     nBit = nBit Xor nCbxIdx And IsNull   Else     nBit = nBit Or nCbxIdx   End If '  Debug.Print nBit End Sub ' ' ================= '〓以下、上記条件で動作確認した、Class1 モジュールの記述内容です。 ' ' === Class モジュール ==== (オブジェクト名) = Class1 Option Explicit Private WithEvents cbxEv As MSForms.ComboBox Private myValue Private nBit As Long ' ' = 以上、モジュール先頭、宣言部 = Public Sub IntClass(ByVal cbx As MSForms.ComboBox, ByVal n As Long)   Set cbxEv = cbx   nBit = n End Sub Private Sub cbxEv_Change()   UserForm1.RcvCbx nBit, (cbxEv.ListIndex < 0)   Value = cbxEv.Value End Sub Public Property Let Value(v)   myValue = v End Property Public Property Get Value()   Value = myValue End Property ' ' =================

すると、全ての回答が全文表示されます。

関連するQ&A