Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Организация печати в VBA 2008 ExpresEdition (http://forum.oszone.net/showthread.php?t=186894)

CODE43 29-09-2010 20:14 1507618

Организация печати в VBA 2008 ExpresEdition
 
Привет всем! Помогите разобраться с организацией печати в 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 1507856

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

CODE43 03-10-2010 17:02 1510373

Цитата:

Цитата Delirium
Так, может, речь все таки идет о 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 1510405

Здесь 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 1511447

Цитата:

Цитата Admiral
AddHandler prndoc.PrintPage, AddressOf PrintDocumentOnPrintPage 'назначить процедуру подготовки документа »

Можно подробнее о процедуре подготовки документа?
После ввода куска кода (где описывается та самая процедура PrintDocumentOnPrintPage) из
Цитата:

Цитата Admiral
ftp://ftp.charlespetzold.com/ProgWinVB/Lines Curves and Area Fills/PrintableForm/PrintableForm.vb »

через всю страницу печатаются две диагональные линии крестом.... А нужно чтоб печатался выводимый в ТекстБокс текст. Как добавить в процедуру подготовки TextBox.Text?
Обидно, что приложение полностью готово и выполняет полностью те физические расчеты, которые было нужно, осталось как-то все это выводить на печать, а печатать полностью всю форму как-то не профессионально. Обязательно Майкрософт и Бил Гейтс максимально все усложнят (Само приложение написалось на ура за 2-3 дня, а вот с выводом на печать уже как месяц воюю. :shot: ).

Admiral 05-10-2010 15:28 1511957

Код:

    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).
Пример использования PrintableForm к ранее написанной форме >>

Предположим есть некая форма (в примере ниже собирающая информацию о локальных дисках)
>>
Код:

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



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

CODE43 05-10-2010 19:20 1512136

Огромное спасибо, Admiral, :hi: !!!
С выводом на печать ТекстБоксов разобрался. Все прекрасно работает.
Вы писали
Цитата:

Цитата Admiral
Если в системной директории данного файла нет (система не ХР или файл просто удалён) данную строчку надо закомментировать, проверка на отсутствие не проводится, или указать путь к своему графическому файлу. »

.
Как правильно здесь
Цитата:

Цитата Admiral
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 1512155

CODE43, эквивалент с абсолютным путём grfx.DrawImage(New Bitmap("C:\windows\Gone Fishing.bmp"), New Point(cx / 2, cy / 6)) для систем установленных на диск С и не с переименованной системной папкой.

CODE43 06-10-2010 19:42 1513003

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

Вставляем в меню объект 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


Время: 22:15.

Время: 22:15.
© OSzone.net 2001-