2017-05-31 123 views
0

我有一个Excel工作簿2013捕获了很多不同的设备的数据的多页的报告。为了使输入用户友好,它被分成两个工作表“设备”和“设备数据”。设备是一个前端,以易于阅读/编辑/打印格式显示来自Equipment-Data的数据。 Equipment-Data是由100件设备组成的85列数据的后端数据表。使用Excel 2013 VBA建立从用户窗体选项

导航是通过选择位于用户窗体上的ListBox上的设备来执行的,该窗体允许用户在项目之间快速导航。当列表框选择更改时,数据表中相应的行将读入数组并写入前端。任何更改都会无缝地推回到数据表中。根据最终用户的熟悉程度,Excel选择了Access,而且两个工作表是不适合Access的大型工作簿的一部分。此外,该工作簿支持一个交付物,并且不会长期更新。

我正在开发一种方式来收集所有设备页面并将它们导出到由Word和PDF混合构建的报表中(最终输出PDF)。我确定有十几种方法可以做到这一点,但我想知道是否有更好的方法。我对VBA还比较陌生 - 已经重写了此项目上的代码,将子例程从表单移动到模块,在subs之间传递变量而不是使用全局变量,并且读取/写入数组而不是循环遍历单元格,因为我学到了更好的方法做事。

我看到它的方式,我的选择是:

  1. 创建临时表,通过列表框圈,从前端复制范围,粘贴特殊到临时表。我从实验中发现,我需要将paste-first xlPasteColumnWidths和xlPasteValuesAndNumberFormats加倍。我尝试使用“值&源格式”(xlPasteAllUsingSourceTheme),但我得到关于合并单元格的错误。在第一次迭代之后,我可以用.Paste替换xlPasteColumnWidths,但由于存在方程式,因此仍然需要跟踪值&数字格式。粘贴后,向前跳过ListIndex * 78以进入下一页的开头并重复。最后,将临时表导出为PDF并删除临时表。
  2. 与#1相同,但使用CopyPicture方法使用xlPicture获取向量输出。循环后,导出到PDF并删除临时表。这个应该在选项#1的最终输出中无法区分,不知道我是否会用100页图像加速或记忆问题。
  3. 在列表框中循环并使用ExportAsFixedFormat创建PDF,使用ListIndex & Equipment_Name作为文件名。然后使用外部PDF工具将文件合并为一个。
  4. 创建Access数据库,采用设备数据表为数据源,并建立报告,以模仿设备表的格式。
  5. 同1或2,但复制的每个列表项到新工作表,选择所有工作表,导出为PDF,删除工作表。

有没有更好的方法,我失踪了?我认为选项1和3是最好的选择。 3似乎是一个很好的快速修复程序,因为不太可能有其他人需要构建报告,但对于某些将来可能在共享驱动器上找到电子表格并希望在不同项目上重复使用的用户,这样做更好。

回答

0

我测试了选项1和2.选项1在大约30秒内运行,使用另存为..PDF(手动,还没有编码它)产生了2.3MB PDF(95页)。选项2在100秒内运行并生成1.0MB PDF。两个PDF都是相似的,但是选项2显示一个文本框,即使设置了CopyPicture方法的xlPrinter外观属性,该文本框也不会被打印。保存选项1 temp工作表将500KB添加到xlsm文件,选项2仅添加115KB,这是令人惊讶的。

代码如下的人谁可能对这个绊倒在未来:

Sub PrintEqEst() 
Dim tmpSht As Worksheet, EqSht As Worksheet 
Dim i as Long 
Dim TWB As Workbook 
PrintingReport = True 'Global boolean used to keep display updating from being turned back on in event routine 
Set TWB = ThisWorkbook 
Set EqSht=TWB.Worksheets("Equipment") 
Set cMyListBox2 = UserForm1.ListBox2 
t(1) = timer *1000 
If cMyListBox2.Rowsource = "" Then PopulateListBox 
Set tmpSht = TWB.Sheets.Add(After:=TWB.Sheets(TWB.Sheets.Count)) 
Application.ScreenUpdating = False  
For i = 0 to cMyListBox2.ListCount - 2 '-1 because it ListIndex starts at 0, -1 because there is intentional blank item at end of List 
    DoEvents 
    cMyListBox2.ListIndex = i 'Triggers event that updates Equipment Sheet 
    EqSht.Range("C2:L73").Copy 
    If i = 0 Then tmpSht.Cells(1, 1).PasteSpecial Paste:=xlPasteColumnWidths 
    tmpsht.Cells(77*i+1, 1).PasteSpecial Paste:=xlPasteAll 
    tmpsht.Cells(77*i+1, 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats 
Next i 
tmpSht.UsedRange.RowHeight = 11.25 
If ListBox2Index >= 1 Then cMyListBox2.ListIndex = ListBox2Index 'If something previously selected, go back to it. (ListBox2Index is global that keeps track of selected item) 
With tmpSht.PageSetup 
    [...] 
End With 
Application.ScreenUpdating=True 
PrintingReport=False 
Debug.Print "Create Report: " & Round(timer * 1000 - t(1), 0) & "ms" 
End Sub 

选项2使用上面的代码除了用于循环使用:

EqSht.Range("C2:L73").CopyPicture Appearance:=xlPrinter, Format:=xlPicture 
tmpSht.Cells(64 * i + 2, 1).Select 
tmpSht.Paste 
1

我觉得选项1将是最好的。它给了你很大的灵活性,如果你以一种好的方式构建你的代码,它也会很容易维护。如果您在运行时禁用屏幕更新,则最终用户将会非常顺利。
另一种可能性(因为你提到Word)是可以从你的宏中创建一个Word文档。只需在工具 - 参考下添加对“Microsoft Word nn.n对象库”的引用即可。然后,您可以访问Word的对象模型,并可以从Excel数据创建文档。

+0

选项1个运行得很好约40秒。我稍后会发布代码。 – MattD

相关问题