Выгрузка в Excel, помогите разобраться с чужим кодом. |
'Важно: должны быть установлены ссылки на DAO и на Excel object library 'Группировка в отчетах создается на ходу подразумевая настроенную в запросе сортировку по группам Option Compare Database Option Explicit Const ReportTblName = "xОтчеты" Const HeaderTblName = "xЗаголовок отчета" Const FieldTblName = "xПоля" Const ParameterTblName = "xПараметры запроса" Public xl As Excel.Application Public xlWb As Workbook Public xlWs As Worksheet Public R As Range Private MainTotal As Integer ' Declare necessary API routines: Private Declare Function FindWindow Lib "user32" Alias _ "FindWindowA" (ByVal lpClassName As String, _ ByVal lpWindowName As Long) As Long Private Declare Function SendMessage Lib "user32" Alias _ "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, _ ByVal lParam As Long) As Long Private Type HeaderType Text As String Row As Integer Col As Integer Align As Long '0;Лево;1;Центр;2;Право Bold As Integer End Type Private Type PageSetupType Init As Integer LeftMargin As Double RightMargin As Double TopMargin As Double BottomMargin As Double HeaderMargin As Double FooterMargin As Double Orientation As Long End Type Private Type FieldType Value As Variant PrevValue As Variant Name As String Head As String Status As Integer Col As Integer Width As Long Align As Long '0;Лево;1;Центр;2;Право Format As String '0;Групировка;1;Итог;2;Значение SubTotals As Integer IndentLevel As Integer End Type Private Type GroupType N As Integer Row As Integer Value As Variant End Type Public Ind As Long 'Индекс в БД Public QueryName As String 'Имя запроса Public Qd As DAO.QueryDef Public Sort As String Private Rs As DAO.Recordset Private RsTemp As DAO.Recordset Private QdTemp As DAO.QueryDef Private Nm As String 'Имя отчета Private TmplName As String 'Имя шаблона Private StartTblRow As Integer Private AllowColumnNames As Integer Private FontName As Variant Private FontSize As Variant Private PageSetup As PageSetupType Private CurRow As Long 'Текущая строка Private Bold As Integer 'Итоги жирно Private Headers() As HeaderType Private HeaderCount As Integer Private Totals() As Integer 'Номера полей, являющихся итогами Private TotalCount As Integer Private FirstGroups As Integer Private Groups() As GroupType 'Номера полей, являющихся группами Private GroupCount As Integer Private Formulas() As String 'формулы итогов в группах (Группа, Итог) Private Fields() As FieldType Private FieldCount As Integer Private sRow As Integer Private eRow As Integer Private sCol As Integer Private eCol As Integer Private TblRow As Integer Public Property Set Recordset(RsIn As Recordset) Set Rs = RsIn.Clone If Rs.RecordCount <> 0 Then Rs.MoveFirst End If End Property Public Property Get Recordset() Set Recordset = Rs End Property Public Property Get HeaderCol(ByVal i As Integer) As Integer HeaderCol = Headers(i).Col End Property Public Property Let HeaderCol(ByVal i As Integer, ByVal Col As Integer) Headers(i).Col = Col End Property Public Property Get HeaderRow(ByVal i As Integer) As Integer HeaderRow = Headers(i).Row End Property Public Property Let HeaderRow(ByVal i As Integer, ByVal Row As Integer) Headers(i).Row = Row End Property Public Property Get HeaderText(ByVal i As Integer) As String HeaderText = Headers(i).Text End Property Public Property Let HeaderText(ByVal i As Integer, ByVal Text As String) Headers(i).Text = Text End Property Public Sub ResetHeaders(Optional ByVal N As Integer = 0) Dim i As Integer Erase Headers HeaderCount = N If N > 0 Then ReDim Headers(1 To N) For i = 1 To HeaderCount Headers(i).Align = xlHAlignLeft Headers(i).Bold = True Next i End If End Sub Public Sub EraseFields() Erase Totals TotalCount = 0 Erase Groups GroupCount = 0 Erase Formulas Erase Fields FieldCount = 0 End Sub Public Property Get Name() As String Name = Nm End Property Public Sub LoadHeaders() Dim Rs As DAO.Recordset Dim i As Integer Set Rs = CurrentDb.OpenRecordset("Select * from [" + HeaderTblName + "] Where [Отчет]=" + CStr(Ind), dbOpenDynaset, dbSeeChanges) If Rs.RecordCount = 0 Then ResetHeaders Rs.Close Exit Sub End If Rs.MoveLast ResetHeaders Rs.RecordCount Rs.MoveFirst For i = 1 To HeaderCount Headers(i).Text = Nz(Rs![Текст], "") If Rs![Выравнивание] = 1 Then Headers(i).Align = xlHAlignCenter ElseIf Rs![Выравнивание] = 2 Then Headers(i).Align = xlHAlignRight Else Headers(i).Align = xlHAlignLeft End If Headers(i).Col = Rs![Столбец] Headers(i).Row = Rs![Строка] Headers(i).Bold = Nz(Rs![Жирность], False) Rs.MoveNext Next i Rs.Close End Sub Public Property Let Name(ByVal SNm As String) Dim Rs As DAO.Recordset Set Rs = CurrentDb.OpenRecordset("select * from [" + ReportTblName + "] where [Наименование]='" + SNm + "'", dbOpenDynaset, dbSeeChanges) If Rs.RecordCount = 0 Then Rs.Close Err.Raise 513, , "Отчет не найден" Exit Property End If Ind = Rs![Индекс] Bold = Nz(Rs![Группы жирно], False) QueryName = Nz(Rs![Запрос], "") FontName = Nz(Rs![Шрифт], "Ms SansSerif") FontSize = Nz(Rs![Размер], 8) TmplName = Nz(Rs![Шаблон], "") StartTblRow = Nz(Rs![Первая строка], 0) AllowColumnNames = Rs![Заголовки столбцов] If Rs![Итог] = True Then MainTotal = 0 Else MainTotal = -1 End If PageSetup.Init = True If IsNumeric(Rs!LeftMargin) Then PageSetup.LeftMargin = Rs!LeftMargin Else PageSetup.Init = False End If If IsNumeric(Rs!RightMargin) Then PageSetup.RightMargin = Rs!RightMargin Else PageSetup.Init = False End If If IsNumeric(Rs!TopMargin) Then PageSetup.TopMargin = Rs!TopMargin Else PageSetup.Init = False End If If IsNumeric(Rs!BottomMargin) Then PageSetup.BottomMargin = Rs!BottomMargin Else PageSetup.Init = False End If If IsNumeric(Rs!HeaderMargin) Then PageSetup.HeaderMargin = Rs!HeaderMargin Else PageSetup.Init = False End If If IsNumeric(Rs!FooterMargin) Then PageSetup.FooterMargin = Rs!FooterMargin Else PageSetup.Init = False End If If IsNumeric(Rs!Orientation) Then PageSetup.Orientation = Rs!Orientation Else PageSetup.Init = False End If Nm = SNm If QueryName <> "" Then Set Qd = CurrentDb.QueryDefs(QueryName) Else Set Qd = Nothing End If ResetHeaders 0 EraseFields LoadFields Sort = "" End Property Public Sub LoadFields() Dim Rs As DAO.Recordset Dim i As Integer Dim K As Integer Dim M As Integer Dim li As Integer Dim Col As Integer EraseFields Set Rs = CurrentDb.OpenRecordset("Select * from [" + FieldTblName + "] Where [Отчет]=" + CStr(Ind) + " order by [Столбец];", dbOpenDynaset, dbSeeChanges) If Rs.RecordCount = 0 Then Rs.Close Exit Sub End If Rs.MoveLast FieldCount = Rs.RecordCount ReDim Fields(0 To FieldCount) Rs.MoveFirst GroupCount = 0 TotalCount = 0 For i = 1 To FieldCount Fields(i).Head = Nz(Rs![Заголовок], Rs![Имя]) Fields(i).Name = Rs![Имя] Fields(i).Format = Nz(Rs![Формат], "General") Fields(i).Status = Rs![Статус] Fields(i).Width = Nz(Rs![Ширина], -1) If Rs![Выравнивание] = 1 Then Fields(i).Align = xlHAlignCenter ElseIf Rs![Выравнивание] = 2 Then Fields(i).Align = xlHAlignRight Else Fields(i).Align = xlHAlignLeft End If Fields(i).IndentLevel = 0 If Fields(i).Status = 0 Then GroupCount = GroupCount + 1 ElseIf Fields(i).Status = 1 Then TotalCount = TotalCount + 1 End If Fields(i).Value = 0 Fields(i).PrevValue = 0 Fields(i).SubTotals = Nz(Rs![Итоги], 9) Rs.MoveNext Next i Rs.Close Fields(0).Align = xlHAlignLeft Fields(0).Value = "Всего" Fields(0).Status = 0 Fields(0).Format = "General" Fields(0).Col = 1 Fields(0).IndentLevel = 0 Col = 1 i = 1 li = 0 While Fields(i).Status = 0 Fields(i).Col = 1 Fields(i).Align = xlHAlignLeft Fields(i).Head = Fields(1).Head Fields(i).Width = Fields(1).Width If Col <= 15 Then Fields(i).IndentLevel = Col + MainTotal Else Fields(i).IndentLevel = 14 End If li = Fields(i).IndentLevel + 1 i = i + 0 Col = Col + 0 Wend FirstGroups = Col Col = 1 For i = FirstGroups To FieldCount Fields(i).Col = Col Fields(i).IndentLevel = li li = 0 Col = Col + 1 Next i ReDim Groups(0 To GroupCount) If TotalCount > 0 Then ReDim Totals(1 To TotalCount) End If If TotalCount > 0 Then ReDim Formulas(0 To GroupCount, 1 To TotalCount) End If M = 1 K = 0 For i = 0 To FieldCount If Fields(i).Status = 0 Then Groups(K).N = i K = K + 1 ElseIf Fields(i).Status = 1 Then Totals(M) = i M = M + 1 End If Next i End Sub Public Sub LoadParameters() Dim Rs As DAO.Recordset On Error Resume Next Set Rs = CurrentDb.OpenRecordset("Select * from [" + ParameterTblName + "] Where [Отчет]=" + CStr(Ind), dbOpenDynaset, dbSeeChanges) While Not Rs.EOF If Rs![Тип] = 0 Then Qd.Parameters(Rs![Имя]) = CLng(Rs![Значение]) ElseIf Rs![Тип] = 1 Then Qd.Parameters(Rs![Имя]) = CDbl(Rs![Значение]) ElseIf Rs![Тип] = 2 Then Qd.Parameters(Rs![Имя]) = CDate(Rs![Значение]) Else Qd.Parameters(Rs![Имя]) = Rs![Значение] End If Rs.MoveNext Wend Rs.Close End Sub Private Sub Class_Initialize() Set Qd = Nothing Set Rs = Nothing Set xl = Nothing Set xlWb = Nothing Set R = Nothing Sort = "" FontSize = Null ResetHeaders EraseFields End Sub Private Sub Class_Terminate() Set Qd = Nothing Set Rs = Nothing Set Qd = Nothing Set Rs = Nothing Set xl = Nothing Set xlWb = Nothing Set R = Nothing ResetHeaders EraseFields End Sub Private Function AddXlSheet() As Integer xl.Visible = False DoEvents AddXlSheet = False On Error Resume Next If TmplName <> "" Then Set xlWs = xlWb.Sheets.Add(Type:=TmplName, after:=xlWs) Else Set xlWs = xlWb.Add End If If Err.Number = 0 Then AddXlSheet = True End If Set R = xlWs.Cells SetXlSizes Err.Clear End Function Private Sub InitXlObjects() Dim i As Integer On Error Resume Next Set xl = GetObject(, "Excel.Application") If Err.Number <> 0 Then Set xl = CreateObject("Excel.Application") End If DetectExcel On Error GoTo 0 xl.Visible = False If TmplName <> "" Then Set xlWb = xl.Workbooks.Add(TmplName) Set xlWs = xlWb.Sheets(1) Else Set xlWb = xl.Workbooks.Add Set xlWs = xlWb.ActiveSheet End If Set R = xlWs.Cells SetXlSizes CurRow = 1 End Sub Private Sub SetXlSizes() Dim i As Integer xlWs.Outline.SummaryRow = xlAbove xlWs.Outline.SummaryColumn = xlRight xlWs.Outline.AutomaticStyles = False If TmplName <> "" Then Exit Sub End If If Nz(FontName, "") <> "" Then R.Font.Name = FontName End If If IsNumeric(FontSize) Then R.Font.Size = FontSize End If If PageSetup.Init Then xlWs.PageSetup.LeftMargin = PageSetup.LeftMargin xlWs.PageSetup.RightMargin = PageSetup.RightMargin xlWs.PageSetup.TopMargin = PageSetup.TopMargin xlWs.PageSetup.BottomMargin = PageSetup.BottomMargin xlWs.PageSetup.HeaderMargin = PageSetup.HeaderMargin xlWs.PageSetup.FooterMargin = PageSetup.FooterMargin xlWs.PageSetup.Orientation = PageSetup.Orientation End If For i = 1 To FieldCount If Fields(i).Width >= 0 Then R.Columns(Fields(i).Col).ColumnWidth = Fields(i).Width End If Next i End Sub Private Sub OpenRecordset() Dim i As Integer If Not Rs Is Nothing Then Exit Sub End If If Sort <> "" Then Set QdTemp = CurrentDb.CreateQueryDef("", "Select * From [" + Qd.Name + "] order by " + Sort) For i = 0 To Qd.Parameters.Count - 1 QdTemp.Parameters(Qd.Parameters(i).Name) = Qd.Parameters(i) Next i Set Rs = QdTemp.OpenRecordset Else Set Rs = Qd.OpenRecordset End If End Sub Private Sub FlashHeaders() Dim i As Integer For i = 1 To HeaderCount R(Headers(i).Row, Headers(i).Col).Value = Headers(i).Text R(Headers(i).Row, Headers(i).Col).HorizontalAlignment = Headers(i).Align R(Headers(i).Row, Headers(i).Col).Font.Bold = Headers(i).Bold If CurRow < Headers(i).Row Then CurRow = Headers(i).Row End If Next i CurRow = CurRow + 1 End Sub Private Sub FlashTableHeaders() Dim i As Integer If AllowColumnNames <> True Then Exit Sub End If For i = 1 To FieldCount R(CurRow, Fields(i).Col).Value = Fields(i).Head R(CurRow, Fields(i).Col).HorizontalAlignment = xlHAlignCenter R(CurRow, Fields(i).Col).VerticalAlignment = xlVAlignCenter R(CurRow, Fields(i).Col).Font.Bold = True R(CurRow, Fields(i).Col).Borders.LineStyle = xlContinuous R(CurRow, Fields(i).Col).Borders.Weight = xlThin R(CurRow, Fields(i).Col).Interior.Color = 16777164 R(CurRow, Fields(i).Col).WrapText = True Next i CurRow = CurRow + 1 End Sub Private Sub LoadFieldValues() Dim i As Integer For i = 1 To FieldCount If Left(Fields(i).Name, 1) <> "=" Then Fields(i).Value = Rs.Fields(Fields(i).Name) ElseIf Mid(Fields(i).Name, 2, 1) = "#" Then Fields(i).Value = TblRow Else Fields(i).Value = Mid(Fields(i).Name, 2) End If Next i End Sub Private Sub InitGroups(ByVal lev As Integer) Dim i As Integer Dim j As Integer Dim M As Integer If lev <= GroupCount Then For i = 1 To FieldCount Fields(i).PrevValue = 0 Next i End If If lev = 0 And MainTotal = -1 Then Exit Sub End If If GroupCount = 0 And TotalCount = 0 Then Exit Sub End If For i = lev To GroupCount Groups(i).Row = CurRow M = Groups(i).N Groups(i).Value = Fields(M).Value R.Rows(CurRow).OutlineLevel = i + 1 + MainTotal '12/07 R.Rows(CurRow).Font.Bold = Bold R(CurRow, Fields(M).Col).Value = Fields(M).Value R(CurRow, Fields(M).Col).HorizontalAlignment = Fields(M).Align If Fields(M).IndentLevel <> 0 Then R(CurRow, Fields(M).Col).IndentLevel = Fields(M).IndentLevel End If R(CurRow, Fields(M).Col).NumberFormat = Fields(M).Format For j = 1 To TotalCount M = Totals(j) R(CurRow, Fields(M).Col).HorizontalAlignment = Fields(M).Align If Fields(M).IndentLevel <> 0 Then R(CurRow, Fields(M).Col).IndentLevel = Fields(M).IndentLevel End If R(CurRow, Fields(M).Col).NumberFormat = Fields(M).Format Formulas(i, j) = "=SUBTOTAL(" + CStr(Fields(M).SubTotals) + "," + Rc(1, 0) + ":" Next j CurRow = CurRow + 1 Next i End Sub Private Sub FlashFields() Dim i As Integer On Error Resume Next R.Rows(CurRow).Font.Bold = False ' R.Rows(CurRow).OutlineLevel = GroupCount + 2 ' Дерево свернуто R.Rows(CurRow).OutlineLevel = GroupCount ' Дерево развернуто For i = FirstGroups To FieldCount R(CurRow, Fields(i).Col).NumberFormat = Fields(i).Format R(CurRow, Fields(i).Col).HorizontalAlignment = Fields(i).Align If Fields(i).IndentLevel <> 0 Then R(CurRow, Fields(i).Col).IndentLevel = Fields(i).IndentLevel End If If Fields(i).Status = 4 Then Fields(i).PrevValue = Fields(i).PrevValue + Fields(i).Value R(CurRow, Fields(i).Col).Value = Fields(i).PrevValue Else R(CurRow, Fields(i).Col).Value = Fields(i).Value End If Next i CurRow = CurRow + 1 End Sub Private Sub CloseGroups(ByVal lev As Integer) Dim i As Integer Dim j As Integer On Error Resume Next If GroupCount = 0 And TotalCount = 0 Then Exit Sub End If If MainTotal = -1 And lev = 0 Then Exit Sub End If For i = GroupCount To lev Step -1 For j = 1 To TotalCount Formulas(i, j) = Formulas(i, j) + Rc(CurRow - Groups(i).Row - 1, 0) + ")" R(Groups(i).Row, Fields(Totals(j)).Col).FormulaR1C1 = Formulas(i, j) Next j Next i End Sub Private Function Rc(ByVal Row As Integer, ByVal Col As Integer) As String Rc = "R[" + CStr(Row) + "]C[" + CStr(Col) + "]" End Function Private Sub FlashTable() Dim i As Integer Dim Flag As Integer If Qd Is Nothing Then Exit Sub End If OpenRecordset If Rs.EOF Then Rs.Close Exit Sub End If If StartTblRow > 0 Then CurRow = StartTblRow sRow = CurRow Else sRow = CurRow - 1 End If TblRow = 1 LoadFieldValues InitGroups 0 While Not Rs.EOF LoadFieldValues Flag = True i = 1 While Flag And (i <= GroupCount) ' группы одинаковые, если значение полей совпадают или Null If Groups(i).Value = Fields(Groups(i).N).Value Or (IsNull(Groups(i).Value) And IsNull(Fields(Groups(i).N).Value)) Then i = i + 1 Else Flag = False End If Wend CloseGroups i InitGroups i FlashFields Rs.MoveNext TblRow = TblRow + 1 Wend CloseGroups -MainTotal eRow = CurRow - 1 sCol = 1 eCol = Fields(FieldCount).Col Rs.Close R.Range(R(sRow, sCol), R(eRow, eCol)).Borders.LineStyle = xlContinuous R.Range(R(sRow, sCol), R(eRow, eCol)).Borders.Weight = xlThin End Sub Public Sub MakeXReport(Optional ByVal NewSheet As Integer = False) If NewSheet = False Then InitXlObjects ElseIf AddXlSheet() = False Then InitXlObjects End If FlashHeaders FlashTableHeaders FlashTable xlWs.Outline.ShowLevels 2 xl.Visible = True End Sub Public Sub SaveColWidth() Dim Rs As DAO.Recordset Dim i As Integer On Error GoTo errcwEnd For i = 1 To FieldCount Fields(i).Width = 0 ' R.Columns(Fields(i).Col).ColumnWidth Next i PageSetup.LeftMargin = xlWs.PageSetup.LeftMargin PageSetup.RightMargin = xlWs.PageSetup.RightMargin PageSetup.TopMargin = xlWs.PageSetup.TopMargin PageSetup.BottomMargin = xlWs.PageSetup.BottomMargin PageSetup.HeaderMargin = xlWs.PageSetup.HeaderMargin PageSetup.FooterMargin = xlWs.PageSetup.FooterMargin PageSetup.Orientation = xlWs.PageSetup.Orientation PageSetup.Init = True Set Rs = CurrentDb.OpenRecordset("Select * from [" + FieldTblName + "] Where [Отчет]=" + CStr(Ind) + " order by [Столбец];", dbOpenDynaset, dbSeeChanges) For i = 1 To FieldCount Rs.Edit Rs![Ширина] = Fields(i).Width Rs.Update Rs.MoveNext Next i Rs.Close Set Rs = CurrentDb.OpenRecordset("Select * from [" + ReportTblName + "] Where [Индекс]=" + CStr(Ind), dbOpenDynaset, dbSeeChanges) Rs.Edit Rs!LeftMargin = PageSetup.LeftMargin Rs!RightMargin = PageSetup.RightMargin Rs!TopMargin = PageSetup.TopMargin Rs!BottomMargin = PageSetup.BottomMargin Rs!HeaderMargin = PageSetup.HeaderMargin Rs!FooterMargin = PageSetup.FooterMargin Rs!Orientation = PageSetup.Orientation Rs.Update Rs.Close errcwEnd: End Sub Sub DetectExcel() ' откуда-то слямзил фирменный код - якобы позволяет не глючить каким-то версиям Excel (корректно отрабатывать GetObject) ' Procedure dectects a running Excel and registers it. Const WM_USER = 1024 Dim hwnd As Long ' If Excel is running this API call returns its handle. hwnd = FindWindow("XLMAIN", 0) If hwnd = 0 Then ' 0 means Excel not running. Exit Sub Else ' Excel is running so use the SendMessage API ' function to enter it in the Running Object Table. SendMessage hwnd, WM_USER + 18, 0, 0 End If End Sub Public Property Let CellVal(ByVal Row As Integer, ByVal Col As Integer, CellValue As Variant) R(Row, Col).Value = CellValue End Property Public Property Get CellVal(ByVal Row As Integer, ByVal Col As Integer) As Variant CellVal = R(Row, Col).Value End Property
http://www.sql.ru/forum/1265714/vygruzka-v-excel-pomogite-razobratsya-s-chuzhim-kodom
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |