PDA

Показать полную графическую версию : Организация печати в VBA 2008 ExpresEdition


CODE43
29-09-2010, 20:14
Привет всем! Помогите разобраться с организацией печати в VBA 2008, а то методы, которые применялись в VB6 не работают. Совсем не работают....
Суть проблемы:
Есть форма с множеством ТекстБоксов с Лейблами в которые выводятся результаты некоторых вычислений.
Нужно, что-бы при нажатии в меню пункта "Печать" принтер печатал страницу А4 с данными из тех самых ТекстБоксов + некоторую картинку из папки Resources проекта и чтоб это все как-то выглядело красиво.
С VBA 2008 как-то с помощью Интернета разобрался, а вот с выводом на печать не могу - не могу найти толковой литературы по VBA 2008.
Есть справочник по VBA 2005. Кое-что работает а кое-что нет.
По рекомендациям из данного справочника пока-что получилось вот что:

Начало:
Option Explicit On
Imports System.IO
Imports System.Drawing.Printing

Public Class Form1
.
.
.
. Private Sub ToolStripMenuItem5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItem5.Click
If PrintDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Printing()
End If "Вызов диалогового окна "Печать", ели нажали "Печать" то переходим к формированию страницы
End Sub

Private Sub Printing()

PrintDocument1.DefaultPageSettings.Margins = New Margins(150, 150, 150, 150) "Установки принтера"
PrintDocument1.DefaultPageSettings.Landscape = False

А здесь непонятно что писать.......

Try
PrintDocument1.Print() (насколько я понял из справочника, то данная команда запускает процесс печати)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub

Delirium
30-09-2010, 01:18
Так, может, речь все таки идет о Visual Basic .Net , а не о VBA? VBA используется в продуктах MS office для написания макросов. VB.NET - для написания приложений.
Для печати есть много способов - можно использовать встроенный Report Viewer, и создать там нужный отчет. Можно использовать просто Me.Print() - напечатает текущую форму. Можно использовать сторонние создатели отчетности, такие как Fast Report. Можно, в конце концов, формировать вручную отчет в Word или Excel.

CODE43
03-10-2010, 17:02
Так, может, речь все таки идет о Visual Basic .Net , а не о VBA? »

Речь идет о VISUAL BASIC 2008 EXPRESS EDITION из пакета VISUAL STUDIO 2008.
Раньше, например в VB 6 для формирования страницы для вывода на печать использовался оператор Printer, с помощью которого задавались шрифт, отступы, положение на странице и т. д.:

Printer.Print "Текст" & Label().Caption
Printer.EndDoc,
после чего принтер начинал печатать.
Здесь же таких операторов и в помине нет. Есть похожие, но как их использовать - фиг знает....

Admiral
03-10-2010, 18:05
Здесь ftp://ftp.charlespetzold.com/ProgWinVB/Lines Curves and Area Fills/PrintableForm/PrintableForm.vb пример организации печати формы по клику.
Если приложение реализовать с нуля можно прямо брать и наследоваться от класса PrintableForm, а не как по умолчанию студия предлагает от Form.
Для уже написанного проекта можно воспользоваться и этим способом (попутно устраняя все замечания студии) или скопировать только необходимы функционал из примера, а именно
Dim prndoc As New Printing.PrintDocument() 'Создаём объект печати
prndoc.DocumentName = Text '"Hello" 'Названия задание печати, берётся с заголовка формы
AddHandler prndoc.PrintPage, AddressOf PrintDocumentOnPrintPage 'назначить процедуру подготовки документа
prndoc.Print()'Выполнить печать на принтере по умолчанию, никакого диалога на выбор принтера (при наличии нескольких) не предлагается.
‘Во избежание перевода бумаги рекомендую воспользоваться виртуальным принтером печающий в PDF файл

CODE43
04-10-2010, 21:58
AddHandler prndoc.PrintPage, AddressOf PrintDocumentOnPrintPage 'назначить процедуру подготовки документа »
Можно подробнее о процедуре подготовки документа?
После ввода куска кода (где описывается та самая процедура PrintDocumentOnPrintPage) изftp://ftp.charlespetzold.com/ProgWinVB/Lines Curves and Area Fills/PrintableForm/PrintableForm.vb » через всю страницу печатаются две диагональные линии крестом.... А нужно чтоб печатался выводимый в ТекстБокс текст. Как добавить в процедуру подготовки TextBox.Text?
Обидно, что приложение полностью готово и выполняет полностью те физические расчеты, которые было нужно, осталось как-то все это выводить на печать, а печатать полностью всю форму как-то не профессионально. Обязательно Майкрософт и Бил Гейтс максимально все усложнят (Само приложение написалось на ура за 2-3 дня, а вот с выводом на печать уже как месяц воюю. :shot: ).

Admiral
05-10-2010, 15:28
Sub PrintDocumentOnPrintPage(ByVal obj As Object, _
ByVal ppea As Printing.PrintPageEventArgs)
Dim grfx As Graphics = ppea.Graphics 'Задаём контекст печати. Через объект grfx будет формироватся страница
Dim szf As SizeF = grfx.VisibleClipBounds.Size 'взять допустимые размеры страницы
DoPage(grfx, Color.Black, CInt(szf.Width), CInt(szf.Height)) 'передать контекст, цвет шрифта и допустимые размеры в процедуру DoPage, сейчас там рисуется только Х, однако данную процедуру можно переназначить в наследниках
End Sub
Пример ниже берёт текст из ячеек ListView, аналогично можно работать и с TextBox. Форматировать страницу можно через табуляцию (vbTab) и перенос строки (vbLf).

Предположим есть некая форма (в примере ниже собирающая информацию о локальных дисках)
Imports System
Imports System.Drawing
Imports System.Windows.Forms

Class AbstractForm
Inherits Form
Dim VolumeListView As New ListView
Shared Sub Main()
Application.Run(New AbstractForm)
End Sub
Sub New()
Text = "Sample"
BackColor = SystemColors.Window
ForeColor = SystemColors.WindowText
ResizeRedraw = True

With VolumeListView
.Parent = Me
.Location = Point.Empty
.Size = New Size(ClientSize.Width, ClientSize.Height \ 2)
.View = View.Details
.HeaderStyle = ColumnHeaderStyle.Clickable
.FullRowSelect = True
.MultiSelect = True
.BorderStyle = BorderStyle.Fixed3D
'.Dock = DockStyle.Fill
.Columns.Add("Volume")
.Columns.Add("Layout")
.Columns.Add("Type")
.Columns.Add("File System")
.Columns.Add("Status")
.Columns.Add("Capacity")
.Columns.Add("Free Space")
.Columns.Add("% Free")
End With

Dim Drives As IO.DriveInfo() = IO.DriveInfo.GetDrives()
For Each Drive In Drives
If Drive.IsReady Then
Dim item1 As ListViewItem = New ListViewItem(New String() {Drive.Name})
With item1.SubItems
.Add("") '.Add("Simple") 'ToDo
.Add(Drive.DriveType.ToString) 'Some other type req(see diskmgmt.msc)
.Add(Drive.DriveFormat)
.Add("") 'ToDo'.Add("Healthy") 'ToDo
.Add(Math.Ceiling(Drive.TotalSize / 1024) & " KB")
.Add(Math.Ceiling(Drive.AvailableFreeSpace / 1024) & " KB") ' (Drive.TotalFreeSpace)
.Add(Math.Ceiling(100 * Drive.AvailableFreeSpace / Drive.TotalSize) & " %")
End With
VolumeListView.Items.AddRange(New ListViewItem() {item1})
End If
Next
End Sub
Protected Overrides Sub OnResize(ByVal re As EventArgs)
VolumeListView.Size = New Size(ClientSize.Width, VolumeListView.Size.Height)
End Sub
End Class
Допустим потребовалось вывести изображаемую информацию на печать. Код формы был создан вручную, а не сгенерирован студией, по этому переделываем приложение по первому способу - заменяем наследование от Form на наследование от PrintableForm. В этом случаи в точки входа потребуется добавить ключевое слово Shadows выйдет так Shared Shadows Sub Main(). В свойствах проекта так же нужно поменять точку входа на имя класса (в данном примере на AbstractForm).
Если сейчас запустить проект кроме "Х" на всей форме ничего не поменяет (а на печать только этот Х и будет отправлен). Поэтому переназначаем процедуру DoPage для формы.
Именно здесь будет формироваться страница. Помимо этого она будет отображаться на самой форме - очень удобно если нужна форма предварительного просмотра.
В данном пример, сам сформированный текст будет скрыт за ListView, а вот картинка %WinDir%\Gone Fishing.bmp будет видна из ListView.
Если в системной директории данного файла нет (система не ХР или файл просто удалён) данную строчку надо закомментировать, проверка на отсутствие не проводится, или указать путь к своему графическому файлу.
Если на рабочей формы никакого предварительного просмотра не надо, просто переназначаем событие OnPaint (в примере ниже раскомментируем соответственные строчки, кроме MyBase.OnPaint(pea)).
В результате получим
Imports System
Imports System.Drawing
Imports System.Windows.Forms

Class AbstractForm
Inherits PrintableForm
Dim VolumeListView As New ListView
Shared Shadows Sub Main()
Application.Run(New AbstractForm)
End Sub
Sub New()
Text = "Sample"
BackColor = SystemColors.Window
ForeColor = SystemColors.WindowText
ResizeRedraw = True

With VolumeListView
.Parent = Me
.Location = Point.Empty
.Size = New Size(ClientSize.Width, ClientSize.Height \ 2)
.View = View.Details
.HeaderStyle = ColumnHeaderStyle.Clickable
.FullRowSelect = True
.MultiSelect = True
.BorderStyle = BorderStyle.Fixed3D
'.Dock = DockStyle.Fill
.Columns.Add("Volume")
.Columns.Add("Layout")
.Columns.Add("Type")
.Columns.Add("File System")
.Columns.Add("Status")
.Columns.Add("Capacity")
.Columns.Add("Free Space")
.Columns.Add("% Free")
End With

Dim Drives As IO.DriveInfo() = IO.DriveInfo.GetDrives()
For Each Drive In Drives
If Drive.IsReady Then
Dim item1 As ListViewItem = New ListViewItem(New String() {Drive.Name})
With item1.SubItems
.Add("") '.Add("Simple") 'ToDo
.Add(Drive.DriveType.ToString) 'Some other type req(see diskmgmt.msc)
.Add(Drive.DriveFormat)
.Add("") 'ToDo'.Add("Healthy") 'ToDo
.Add(Math.Ceiling(Drive.TotalSize / 1024) & " KB")
.Add(Math.Ceiling(Drive.AvailableFreeSpace / 1024) & " KB") ' (Drive.TotalFreeSpace)
.Add(Math.Ceiling(100 * Drive.AvailableFreeSpace / Drive.TotalSize) & " %")
End With
VolumeListView.Items.AddRange(New ListViewItem() {item1})
End If
Next
End Sub
Protected Overrides Sub OnResize(ByVal re As EventArgs)
VolumeListView.Size = New Size(ClientSize.Width, VolumeListView.Size.Height)
End Sub
Protected Overrides Sub DoPage(ByVal grfx As System.Drawing.Graphics, ByVal clr As System.Drawing.Color, ByVal cx As Integer, ByVal cy As Integer)

Dim text2Print As String = vbNullString
For Each Column As ColumnHeader In VolumeListView.Columns
text2Print = text2Print & Column.Text & vbTab
Next

text2Print = text2Print & vbLf

For Each ListItem As ListViewItem In VolumeListView.Items
For Each SubItem As ListViewItem.ListViewSubItem In ListItem.SubItems
text2Print = text2Print & SubItem.Text & vbTab
Next SubItem
text2Print = text2Print & vbLf
Next ListItem

grfx.DrawString(text2Print, Font, New SolidBrush(clr), New Point(cx / 20, cy / 20))

grfx.DrawImage(New Bitmap(System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "Gone Fishing.bmp")), New Point(cx / 2, cy / 6))

End Sub
'Protected Overrides Sub OnPaint(ByVal pea As System.Windows.Forms.PaintEventArgs)
''MyBase.OnPaint(pea)
'End Sub
End Class

http://s49.radikal.ru/i124/1010/53/6c1a1c1d3f76x.jpg (http://s49.radikal.ru/i124/1010/53/6c1a1c1d3f76.png)

P.S.
PrintableForm печатает только на одну страницу. Разбивку по страницам не производит. Всё что не поместилось отсекается.

CODE43
05-10-2010, 19:20
Огромное спасибо, Admiral, :hi: !!!
С выводом на печать ТекстБоксов разобрался. Все прекрасно работает.
Вы писали Если в системной директории данного файла нет (система не ХР или файл просто удалён) данную строчку надо закомментировать, проверка на отсутствие не проводится, или указать путь к своему графическому файлу. ».
Как правильно здесь grfx.DrawImage(New Bitmap(System.IO.Path.Combine(Environment.GetEnvironmentVariable("windir"), "Gone Fishing.bmp")), New Point(cx / 2, cy / 6) » прописать путь к графическому файлу, а то студия опять матерится.
Как только разберусь с выводом на печать изображения, напишу полный отчет :).

Admiral
05-10-2010, 19:35
CODE43, эквивалент с абсолютным путём grfx.DrawImage(New Bitmap("C:\windows\Gone Fishing.bmp"), New Point(cx / 2, cy / 6)) для систем установленных на диск С и не с переименованной системной папкой (http://www.oszone.net/2758#r02).

CODE43
06-10-2010, 19:42
Вот, как и обещал, выкладываю то, что у меня получилось.
Приложение по описываемому выше методу не переделывал. Просто в уже существующий код формы дописал показанный ниже код. Не знаю насколько он оптимален с точки зрения программирования, но он работает и результат меня устраивает.

Вставляем в меню объект ToolStripMenuItem, называем его «Печать», Вставляем в проект объект PrintDialog.

Описываем процедуру выбора пункта «Печать»:

Private Sub ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItem5.Click
If PrintDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Pechat() ‘При выборе в меню приложения пункта «Печать»
выводится стандартное диалоговое окно для выбора
принтера. Если в диалоге нажать «Печать» то
запускается процедура Pechat ’
End If
End Sub

Собственно, сама процедура:

Private Sub Pechat()
Dim prndoc As New Printing.PrintDocument
prndoc.DocumentName = Text
AddHandler prndoc.PrintPage, AddressOf PrintDocumentOnPrintPage
prndoc.Print()
End Sub

Private Sub PrintDocumentOnPrintPage(ByVal obj As Object, ByVal ppea As PrintPageEventArgs)
Dim grfx As Graphics = ppea.Graphics
Dim szf As SizeF = grfx.VisibleClipBounds.Size
DoPage(grfx, Color.Blue, CInt(szf.Width), CInt(szf.Height))
End Sub

Процедура DoPage формирования страницы для вывода на печать:

Private Sub DoPage(ByVal grfx As System.Drawing.Graphics, ByVal clr As System.Drawing.Color, ByVal cx As Integer, ByVal cy As Integer)
Dim Text2print As String = vbNullString
Dim Font As New Font("Courier New", 14) ‘Шрифт и его размер для
печати’
Text2print = vbTab & vbTab & "Здесь можна напечатать заглавие страницы по центру" & vbLf
Text2print = Text2print & Label1.Text & vbTab & "Какой нибудь текст" & vbTab & TextBox1.Text & vbTab & "Еще какой нибудь текст" & vbLf
Text2print = Text2print & “И так далее, собственно и формируем то что нужно для вывода на печать ”

grfx.DrawString(Text2print, Font, New SolidBrush(clr), New Point(cx / 20, cy / 20)) ‘Печатаем сформированый текст’
grfx.DrawImage(New Bitmap("C:\Папка\Картинка.jpg"), New Point(cx / 4, cy / 3)) ‘Печатаем картинку приблизительно по центру листа (зависит от сх и су)’
End Sub




© OSzone.net 2001-2012