Часть
1. Основы Visual Basiс
|
||||||
29.01.2005 | ||||||
Глава
13.
|
||||||
Вывод
на печать (работа с принтером). Объект Printer.
Его свойства и методы. Функция InStr. |
||||||
Ну, друзья мои, мы дошли до 13-й чертовой главы. Не будем суеверными и попробуем разобраться, как вывести на печать результаты нашей программной деятельности. Не хочу тебя огорчать, но для этого нужен принтер, который подключен к твоему компьютеру и готов к работе. Если его нет, эту главу не читай.
Традиционно во всех учебных изданиях разбирается пример, как вывести на печать всю форму целиком. На фига нужно выводить всю форму, какая от этого нам польза, остается для меня загадкой на протяжении долгого времени и гнетет мое сознание. Однако, отдавая дань традициям, все-таки напомню, что форма выводится на печать с помощью метода PrintForm. То бишь, ты берешь любую готовую программу, добавляешь кнопку Command, называешь ее "Печать", и в код ее процедуры гордо пишешь:
Form1.PrintForm
Запускаешь программу, нажимаешь эту созданную кнопку и у тебя на печать выходит Form1 со всеми элементами-объектами, видимыми на момент печати. Ты некоторое время смотришь на это безумие, потом перед командой PrintForm делаешь невидимыми кнопки и в надежде на чудо, снова повторяшь процесс, но чуда не произошло. Кнопок теперь нет, но распечатка красивше от этого не стала. И понося на чем свет VB, Microsoft и его хозяина, выключаешь все и идешь пить пиво.
Вот про печать и все.
Шучу. Во-первых на печать надо выводить именно то, что мы хотим, а не то, что можем, и в полном объеме. Во-вторых, расположение объектов на форме может быть красиво, но на листе дизайн должен быть совсем иной и объекты расположены по-другому, а форма для создания печатного документа вообще не годится.
А теперь скажу, что подготовка для печати красивой страницы - достаточно кропотливый процесс. То есть, надо программно расчитывать месторасположение всех элементов страницы, причем в зависимости от формата листа и размера шрифта и всего остального. Зато тщательно подготовленная страница выглядит, как настоящий документ, очень достойно.
Основной
объект, с которым мы будем работать - Printer. Несмотря на то, что это
объект, ни самого объекта в окне инструментов или на форме, ни свойств в окне
свойств мы не увидим. Он невидим. Поэтому все надо делать программно. Но этот
объект имеет очень много свойств и методов, большинство из которых нам нужны.
Постараемся разобраться подробнее. Хочу заметить, что не все принтеры поддерживают
все свойства объекта Printer. В этом случае разные свойства могут вызывать одинаковое
действие, не вызвать никакого действия или же вообще привести к ошибке. Я использовал
довольно-таки старый лазерный черно-белый принтер HP LaserJet 5L, и основываясь
на его возможностях и готовил пример. Можно было взять цветной струйник, но
струйники - дороги в эксплаутации и, как правило, документы печатаются на лазерных
принтерах.
Итак, начнем со свойств, список важнейших из них приведен в таблице ниже:
Теперь, как ни печально, надо переходить к методам, но их не так много. На мой взгляд важные приведены в таблице ниже:
Метод
|
Характеристика
|
Синтаксис
|
.EndDoc | завершает формирование листа для печати и начинает печать | Printer.EndDoc |
.KillDoc | немедленно завершает печать сформированной страницы | Printer.KillDoc |
.NewPage | завершает текущую страницу на объекте Printer и переходит на следующую | Printer.NewPage |
.TextHeight и .TextWidth | возвращают высоту (TextHeight ) и длину (TextWidth) текстовой строки, которая получится при ее выводе на печать или на форму с использованием текущего шрифта. В возвращаемое значение включаются и интервалы. | Text1.Text=Printer.TextHeight("vbzero") Text2.Text=Printer.TextWidth("vbzero") |
Tеперь попробуем
разобраться, как все это использовать на примере программки Printing. Чтобы
у нас было, что выводить на печать, я набросал подобие программки, представляющую
собой рабочее места продавца мобильных телефонов. Советую вам скачать ее вверху
страницы, чтобы иметь перед глазами, а потом продолжать читать главу.
Создадим новый exe-проект. Первая ее часть представляет собой интерфейс для
работы с базой мобильных телефонов: вывод на экран изображения и технических
характеристик телефона, две кнопки навигации - вперед и назад и кнопка Печать.
Изображение и теххарактеристики грузятся из файлов, имеющих имена 1.jpg и 1.txt,
2.jpg и 2.txt, и так далее, т.е., аналогично программке Tester, которую
мы разбирали в Главе 8.
Итак стандартное
начало:
Option Explicit
Option Base 1
Объявляем статический
одномерный массив для двенадцати строк технических характеристик телефона:
Dim
MassiveData(12) As
String
Затем несколько
необходимых переменных
Dim
FileName As
String 'для имени загружаемых файлов
Dim F As Long 'для
номера свободного файла
Dim X As Long 'для
переменной цикло For...Next
Dim QuantityFonts As Long
'для числа найденых шрифтов
Затем процедура загрузки
формы. Здесь мы просто изначально устанавливаем имя загружаемого файла - "1"
("1.jpg" и "1.txt") и переходим к созданной нами процедуре
загрузки этих файлов DataLoading().
Private Sub
Form_Load()
FileName = "1"
DataLoading
End Sub
Private Sub DataLoading()
Загружаем изображение телефона в Image1
Image1.Picture = LoadPicture(App.Path & "\" & FileName
& ".jpg")
Восстанавливаем положение
Image1 от левой и верхней границы экрана соответственно
Image1.Left = 24
Image1.Top = 128
Центрируем положение картинки
в зависимости от того, вертикальная она (Image1.Height > Image1.Width
- высота больше ширины) или горизонтальная (Image1.Width > Image1.Height
- ширина больше высоты)
If Image1.Width > Image1.Height Then
Image1.Top = Image1.Top + (250 - Image1.Height) / 2
If Image1.Height > Image1.Width Then
Image1.Left = Image1.Left + (250 - Image1.Width) / 2
Открываем текстовой файл
с тем же именем, что и картинка и грузим 12 строк текста в 12 элементов массива
F = FreeFile
Open App.Path & "\" & FileName
& ".txt" For Input As #F
For X = 1 To 12
Line Input #F, MassiveData(X)
Тут же выводим содержание
массива в Label9. Обратите внимание, что Label9 представляет собой
Control Array (по сути - это одномерный массив объекта), т.е. группу
лейблов с именем Label9(индекс). По этому индексу мы можем перебирать
Label9 в цикле. Делается это так: мы кладем на форму Label9, затем
копируем его. VB спрашивает "Создавать Control Array?", ты отвечаешь
"Да", после чего на форме появляется копия Label9 с именем
Label9(1). Наш же просто лейбл Label9 становится Label9(0).
Я про это писал, но повторюсь. Продолжаем этот процесс до получения нужного
количества лейблов в Control Array. А потом, ненужные элементы надо уничтожить.
У нас, поскольку мы используем оператор Option Base 1, и элементы массива
начинаются с единицы - это Label9(0). Аналогично создается и Control
Array и для Label8, куда присваиваются наименования технических характеристик
телефона. Для облегчения кода я сделал это присвоение в окне свойств Label8.
Label9(X).Caption = MassiveData(X)
Next X
Close #F
End Sub
В кнопках Command1
и Command2 мы пишем код для смены имени загружаемого файла. Все это опять-таки
похоже на программку Tester из Главы 8, и на этом я подробно останавливаться
не буду.
Private Su
b Command1_Click()
If Val(FileName) > 1 Then
FileName = Str(Val(FileName) - 1)
FileName = Right(FileName, Len(FileName) - 1)
DataLoading
End If
End Sub
Private Sub Command2_Click()
FileName = Str(Val(FileName) + 1)
FileName = Right(FileName, Len(FileName) - 1)
If Dir(App.Path & "\" & FileName
& ".txt") <> "" Or
Dir(App.Path & "\" & FileName & ".jpg") <>
"" Then
DataLoading
Else
FileName = Str(Val(FileName) - 1)
FileName = Right(FileName, Len(FileName) - 1)
DataLoading
End If
End Sub
А вот сейчас мы переходм к тому, ради чего мы все это затеяли. Попробуем подготовить для печать документ. В процедуре кнопки Command3 мы начнем формировать страницу для печати. Сперва объявим кое-какие переменные
Private Sub
Command3_Click()
Dim OrientTelefona As Single
' меняет отступ от картинки в зависимости горизонтальная
она или вертикальная
Dim Fonts() As String
'одномерный динамический массив для хранения существующих
шрифтов
Dim VertCoord As Single
'накапливает сдвиг по вертикали по мере создания строк
в документе
Dim NumberFont As Long
' номер шрифта
обнуляем переменную,
содержащую количество шрифтов на всякий случай
QuantityFonts =
0
В смысле определения шрифтов
на текущем принтере я пошел по пути наименьшего сопротивления. Исходя из того,
что на любом компьютере установлен хотя бы один из четырех общеупотребимых шрифтов,
я проверяю их наличие и имена найденых шрифтов загружаю в динамический массив
Fonts(). Для этого мы организуем цикл, где перебираем все существующие
на текущем компьютере шрифты (их количество нам возвращает свойство .FontCount),
и грузим их имена в массив Fonts(). При этом счетчик QuantityFonts отражает,
сколько из четырех шрифтов найдено.
For
NumberFont = 0 To Printer.FontCount - 1
If Printer.Fonts(NumberFont) = "Arial Cyr"
Or Printer.Fonts(NumberFont) = "Times New
Roman" _
Or Printer.Fonts(NumberFont) = "Courier New"
Or Printer.Fonts(NumberFont) = "MS Sans Serif" Then
QuantityFonts = QuantityFonts + 1
ReDim Preserve Fonts(QuantityFonts)
Fonts(QuantityFonts) = Printer.Fonts(NumberFont)
End If
Next NumberFont
Затем, если хоть один шрифт
найден, мы устанавливаем его из первого элемента массива
If
QuantityFonts > 0 Then Printer.FontName = Fonts(1)
Ну уж если не найдено ни
одного шрифта, то в надежде, что какой-то там шрифт в принтере по умолчанию
все же есть, продолжаем формировать документ.
Для удобства и наглядности все будем мерять в сантиметрах, поэтому устанавливаем
размерность в сантиметрах
Printer.ScaleMode
= vbCentimeters
Хочу сказать, что начинать
формирование страницы методом Printer.NewPage (создание новой страницы)
не надо, иначе первой вылезет пустая страница. У тебя нет еще ни одной страницы,
и нет необходимости переходить на новую. Вот для второй, третьей и т.д. страницы
- пожалуйста.
Устанавливаем размер шрифта для первой строки
Printer.FontSize
= 12
'устанавливаем подчеркивание
Printer.Font.Underline = True
'устананавливаем качество печати - среднее
Printer.PrintQuality = 3
Прижимаем вправо первую строчку с названием фирмы. Для установки положения начала вывода по-горизонтали используется свойство .CurrentX. Чтобы строчка прижалась вправо мы из общей ширины нашего документа Printer.ScaleWidth вычтем длину нашей строчки Printer.TextWidth(Label1.Caption), которую она займет при печати объявленным нами шрифтом:
Printer.CurrentX
= Printer.ScaleWidth - Printer.TextWidth(Label1.Caption)
В переменной VertCoord мы будем накапливать сдвиг по вертикали. Сначала запишем в нее, сколько высоты заняла первая строка (вместе с отступами).
VertCoord = Printer.TextHeight(Label1.Caption)
Теперь встраиваем в страницу первую строчку. Никакой печати при этом не происходит. Собственно принтер начинает работать только тогда, когда VB посчитает, что формирование документа полностью закончено. Это произойдет, если будет написан оператор Printer.EndDoc, либо если ты выйдешь из программы совсем.
Printer.Print Label1.Caption
'устанавливаем большой размер шрифта для названия
модели телефона
Printer.FontSize = 20
'отменяем подчеркивание
Printer.Font.Underline = False
'зато ставим жирный
Printer.Font.Bold = True
'делаем отступ вниз на 1,5 см от первой строчки, меняя
вертикальную координату
Printer.CurrentY = VertCoord + 1.5
'выравниваем вторую строчку по-середине
Printer.CurrentX = (Printer.ScaleWidth - Printer.TextWidth(Label9(1).Caption
& "Лидер продаж - телефон ")) / 2
'добавляем, сколько высоты мы использовали на вторую строчку
вместе с отступами
VertCoord = VertCoord + Printer.TextHeight(Label9(1).Caption) + 1.5
'встраиваем в страницу вторую строчку
Printer.Print "Лидер продаж - телефон "
& Label9(1).Caption
'устанавливаем размер шрифта поменьше для заглавия технических
характеристик телефона
Printer.FontSize = 14
'добавляем курсив
Printer.Font.Italic = True
'отступаем вниз еще на 2 см
Printer.CurrentY = VertCoord + 2
'добавляем высоту третьей строчки вместе с отступами
VertCoord = VertCoord + Printer.TextHeight(Label4.Caption) + 2
'оставляем 8 см слева под картинку, а остальное справа
- под текст
'строчку центрируем на ее Printer.ScaleWidth = 8 см
Printer.CurrentX = (Printer.ScaleWidth - 8 - Printer.TextWidth(Label4.Caption))
/ 2
'встраиваем в страницу третью строчку
Printer.Print Label4.Caption
Для печати изображения телефона
берем текущую координату по вертикали VertCoord.
Печатаем картинку, центрируя ее на своей площади и меняя пустое расстояние перед
ней, в зависимости от того, горизонтальная она (OrientTelefona = 0.5) или вертикальная
(OrientTelefona = 2.25). Тогда картинка будет располагаться красиво, по центру
выделенной ей площади.
If
Image1.Height > Image1.Width
Then
OrientTelefona = 2.25
Else
OrientTelefona = 0.5
End If
Встраиваем картинку в наш документ
Printer.PaintPicture Image1.Picture, Printer.ScaleWidth - ScaleX(Image1.Width,
vbPixels, vbCentimeters) - OrientTelefona, VertCoord
'отменяем курсив и жирность
Printer.Font.Italic = False
Printer.Font.Bold = False
'устанавливаем размер шрифта еще меньше
Printer.FontSize = 12
'отступаем вниз от 3-ей строки на 1 см
Printer.CurrentY = VertCoord + 1
VertCoord = VertCoord + 1
Теперь, остальные строки
- технические данные( с 2-ой по 11-ую) мы встроим в цикле (всего 10 строк) не
меняя размеров, жирности и т.п. шрифта.
Обратите внимание, что наименование характеристик
в Label8(X) и сами характеристики в Label9(X) прописаны отдельно
друг от друга и перед каждым установлены свои координаты начала печати Printer.CurrentX
и Printer.CurrentY. Тогда печать осуществится красиво, двумя столбиками.
For
X = 2 To
11
'отступаем слева по сантиметру
Printer.CurrentX = 1
Printer.CurrentY = VertCoord
Printer.Print Label8(X).Caption
Printer.CurrentX = 5
Printer.CurrentY = VertCoord
Printer.Print Label9(X).Caption
VertCoord = VertCoord + 0.6 'увеличение вертикальной координаты
с каждой новой строчкой
Next X
Теперь для акцента на цену
телефона, выведем на печать прямоугольник через все страницу. Подробно о рисовании
простых графических фигур программным методом мы поговорим в
следующей главе. Здесь мы используем метод Line.
VertCoord = VertCoord + 1
Printer.Line (1, VertCoord)-(17.5, VertCoord + 0.7), vbBlack, BF
Printer.CurrentY = VertCoord + 0.1
Printer.CurrentX = 6
'теперь пишем цену
Printer.Font.Bold = True
Printer.Print "Самая лучшая цена: " & Label9(12).Caption &
" руб."
Printer.Font.Bold = False
А вот теперь даем команду о завершении формирования страницы и принтер начинает
печать:
Printer.EndDoc
End Sub
Этот пример имеет некоторую недоработочку. Строка, которая выводит особенности телефона (Label9(8)) длинная и не входит в рамки страницы, а при печати все, что не влезает в страницу безжалостно отсекается и на печать не выводится. Та же проблема возникает при печати неформатированного текста из текстового файла. Попробуй решить эту проблему самостоятельно. Возможно позже я по этому поводу чего-нибудь напишу, но не здесь, а в Части 3 - "Релизация некоторых задач".
Разбивать текст можно по пробелам. Возможно, ты захочешь использовать функцию InStr.
Функция InStr. |
Эта функция используется при текстовом поиске. Она возвращает значение (если совпадение обнаружено)- позицию (номер символа), с которого искомая строка входит в строку, в которой выполняется поиск. Если поиск не удался или строка, в которой проводится поиск - пустая, возвращаемое значение - 0. Ее синтаксис следующий
Числовая переменная=InStr(номер символа, строка поиска, критерий поиска, способ сравнения)
номер символа - необязательный
аргумент определяет с какого символа в строке (третьего, десятого и т.п.) надо
начинать поиск. Если не задан, поиск начинается с первого символа.
строка поиска - строка, в которой ведется поиск
критерий поиска - искомое строковое выражение
способ сравнения - необязательно. Указывает способ сравнения строк (0-двоичное
сравнение, 1 -посимвольное сравнение без учета регистра, 2 - только в Microsoft
Access). Если аргумент опущен, способ сранения определяется параметром инструкции
Option Compare.
Вот пример поиска фамилии Иванов по по критерию из четырех начальных букв "иван" в массиве A(4) без учета регистра.
Dim
A(4) As
String
Dim X As Long
A(1) = "Петров"
A(2) = "Сидоров"
A(3) = "Иванов"
A(4) = "Глюкоза"
For X = 1 To 4
If InStr(1, A(X), "иван", 1) > 0 Then
MsgBox "Найден " & A(X) & " в строке " & X
End If
Next X
Удачи!
|
Copyright
|