Chcielibyśmy aby w kolejnej zakładce (np. faktura proforma, oferta) wybór w pierwszej zakładce z listy rozwijanej (walidacja w Excelu) zawierał posortowaną listę występujących kategorii nadrzędnych. Wybór kategorii nadrzędnej ma spowodować rozwinięcie w sąsiedniej komórce listy kategorii podrzędnych tylko tych, które należą do kat. nadrzędnej. Z kolei wybór kategorii podrzędnej ma spowodować rozwinięcie w sąsiedniej komórce kodów. Tylko tych kodów, które należą do wybranej kat. podrzędnej. Wybór kodu ma wypełnić pozostałe sąsiadujące komórki informacją o cenie, opisem etc. ...
Konieczne jest zainstalowanie Access Runtime i dołączenie referencji do Microsoft ActiveX Data (łatwe i za darmo, patrz cz.1)
Oto propozycja rozwiązania w VBA:
W kodzie aktywującym (trigger) makra związane z wykonywanymi operacjami na arkuszu należy wprowadzić następujące makro (należy kliknąć prawym przyciskiem myszy na zakładkę arkusza z naszą fakturą proformą i wybrać z wyświetlonego menu "View Code"):
Private Sub Worksheet_Change(ByVal Target As Range) If Not Intersect(Target, Me.Range("Table1[Major]")) Is Nothing Then DependentLists1 ElseIf Not Intersect(Target, Me.Range("Table1[Minor]")) Is Nothing Then DependentLists2 ElseIf Not Intersect(Target, Me.Range("Table1[Code]")) Is Nothing Then DependentLists3 Else Exit Sub End If End Sub Private Sub Worksheet_SelectionChange(ByVal Target As Range) If Not Intersect(Target, Me.Range("Table1[Major]")) Is Nothing Then DependentLists0 ElseIf Not Intersect(Target, Me.Range("Table1[Minor]")) Is Nothing Then GoLeftOnEmpty ElseIf Not Intersect(Target, Me.Range("Table1[Code]")) Is Nothing Then GoLeftOnEmpty End If End Sub Sub GoLeftOnEmpty() 'If empty cell, go back higher up. If ActiveCell.Offset(0, -1).Value = "" And ActiveCell.ListObject.ListColumns.Count <> 1 Then Cells(ActiveCell.Row, Range("Table1[Major]").Column).Activate Exit Sub End If End SubA teraz posłużymy się schematem z Cz1. Bazę produktów będziemy odpytywać prostymi zapytaniami SQL i zwracać wynik do listy walidacyjnej Excela. W nowym module kodu VBA należy wprowadzić dla listy rozwijanej w pierwszej kolumnie:
Sub DependentLists0() On Error Resume Next Dim Myconnection As Connection Dim Myrecordset As Recordset Dim Myworkbook, strSQL, DataStr As String Set Myconnection = New Connection Set Myrecordset = New Recordset Application.ScreenUpdating = False 'Identify the workbook you are referencing Myworkbook = Application.ThisWorkbook.FullName 'Open connection to the workbook Myconnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=" & Myworkbook & ";" & _ "Extended Properties=Excel 8.0;" & _ "Persist Security Info=False" 'edytuj strSQL = "SELECT DISTINCT [MajorName] " & _ "FROM [Data$] " & _ "ORDER BY 1 ASC" 'Load the Query into a Recordset Myrecordset.Open strSQL, Myconnection, adOpenStatic 'Load Recordset to string variable DataStr = Myrecordset.GetString(, , , ",", "") 'Options: StringFormat np. adClipString, NumRows, ColumnDelimiter, RowDelimiter, NullExpr 'Change validation for one cell left With Selection.Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _ xlBetween, Formula1:=DataStr .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .ErrorTitle = "" .InputMessage = "" .ErrorMessage = "" .ShowInput = True .ShowError = True End With Application.SendKeys ("%{DOWN}") 'Remove Garbage Set Myrecordset = Nothing Myconnection.Close Application.ScreenUpdating = True End SubZaś w nowym module kodu VBA wkleić kod dla listy rozwijanej w drugiej kolumnie:
Sub DependentLists1() On Error Resume Next Dim Myconnection As Connection Dim Myrecordset As Recordset Dim Myworkbook, strSQL, DataStr As String Set Myconnection = New Connection Set Myrecordset = New Recordset Application.ScreenUpdating = False 'Identify the workbook you are referencing Myworkbook = Application.ThisWorkbook.FullName 'Open connection to the workbook Myconnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=" & Myworkbook & ";" & _ "Extended Properties=Excel 8.0;" & _ "Persist Security Info=False" 'Build SQL Statement strSQL = "SELECT DISTINCT [MinorName] " & _ "FROM [Data$] " & _ "WHERE [MajorName] = '" & ActiveCell.Value & "' " & _ "ORDER BY 1 ASC" 'Load the Query into a Recordset Myrecordset.Open strSQL, Myconnection, adOpenStatic 'Load Recordset to string variable DataStr = Myrecordset.GetString(, , , ",", "") 'Options: StringFormat np. adClipString, NumRows, ColumnDelimiter, RowDelimiter, NullExpr 'Change validation for one cell left ActiveCell.Offset(0, 1).Select With Selection.Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _ xlBetween, Formula1:=DataStr .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .ErrorTitle = "" .InputMessage = "" .ErrorMessage = "" .ShowInput = True .ShowError = True End With Application.SendKeys ("%{DOWN}") 'Remove Garbage Set Myrecordset = Nothing Myconnection.Close Application.ScreenUpdating = True End SubDla list rozwijanych w trzeciej kolumnie:
Sub DependentLists2() On Error Resume Next Dim Myconnection As Connection Dim Myrecordset As Recordset Dim Myworkbook, strSQL, DataStr As String Set Myconnection = New Connection Set Myrecordset = New Recordset Application.ScreenUpdating = False 'Identify the workbook you are referencing Myworkbook = Application.ThisWorkbook.FullName 'Open connection to the workbook Myconnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=" & Myworkbook & ";" & _ "Extended Properties=Excel 8.0;" & _ "Persist Security Info=False" 'Build SQL Statement strSQL = "SELECT DISTINCT [Code] " & _ "FROM [Data$] " & _ "WHERE [MinorName] = '" & ActiveCell.Value & "' " & _ "ORDER BY 1 ASC" 'Load the Query into a Recordset Myrecordset.Open strSQL, Myconnection, adOpenStatic 'Load Recordset to string variable DataStr = Myrecordset.GetString(, , , ",", "") 'Options: StringFormat np. adClipString, NumRows, ColumnDelimiter, RowDelimiter, NullExpr 'Change validation for one cell left ActiveCell.Offset(0, 1).Select With Selection.Validation .Delete .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _ xlBetween, Formula1:=DataStr .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .ErrorTitle = "" .InputMessage = "" .ErrorMessage = "" .ShowInput = True .ShowError = True End With Application.SendKeys ("%{DOWN}") 'Remove Garbage Set Myrecordset = Nothing Myconnection.Close Application.ScreenUpdating = True End Sub
Dla wypełnienia pozostałych kolumn poslużymy się zaś takim kodem:
Sub DependentLists3() Dim Myconnection As Connection Dim Myrecordset As Recordset Dim Myworkbook, strSQL, DataStr1, DataStr2 As String Dim DataVal1 As Single Set Myconnection = New Connection Set Myrecordset = New Recordset Application.ScreenUpdating = False 'Identify the workbook you are referencing Myworkbook = Application.ThisWorkbook.FullName 'Open connection to the workbook Myconnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _ "Data Source=" & Myworkbook & ";" & _ "Extended Properties=Excel 8.0;" & _ "Persist Security Info=False" 'Build SQL Statement strSQL = "SELECT DISTINCT [Desc_1], [Desc_2],[Value]" & _ "FROM [Data$] " & _ "WHERE [Code] = '" & ActiveCell.Value & "' " & _ "ORDER BY 1 ASC" 'Load the Query into a Recordset Myrecordset.Open strSQL, Myconnection, adOpenStatic 'Load Recordset to variables DataStr1 = IIf(IsNull(Myrecordset.Fields("Desc_1").Value), "n/a", Myrecordset.Fields("Desc_1").Value) DataStr2 = IIf(IsNull(Myrecordset.Fields("Desc_2").Value), "n/a", Myrecordset.Fields("Desc_2").Value) DataVal1 = IIf(IsNull(Myrecordset.Fields("Value").Value), "n/a", Myrecordset.Fields("Value").Value) 'Change validation for one cell left ActiveCell.Offset(0, 1).Value = DataStr1 ActiveCell.Offset(0, 2).Value = DataStr2 ActiveCell.Offset(0, 3).Value = DataVal1 'Remove Garbage Set Myrecordset = Nothing Myconnection.Close Application.ScreenUpdating = True End Sub
Przykładowy plik tutaj.
Brak komentarzy:
Prześlij komentarz