|
При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Работа с печатью и изображениями
Печать содержимого PictureBox
Теперь займемся печатью изображений, помещенных в PictureBox. Добавляем на форму элементы PrintDocument, PageSetupDialog, PrintPreviewDialog и PrintDialog. На этот раз мы не будем настраивать визуально свойства этих элементов. Создаем обработчиков пунктов меню, в которых просто вызываем диалоговые окна:
private void mnuPageSetup_Click(object sender, System.EventArgs e)
{
PageSetupDialog diag = new PageSetupDialog();
diag.Document = printDocument1;
diag.ShowDialog();
}
private void mnuPreview_Click(object sender, System.EventArgs e)
{
PrintPreviewDialog diag = new PrintPreviewDialog();
diag.Document = printDocument1;
diag.ShowDialog();
}
private void mnuPrint_Click(object sender, System.EventArgs e)
{
PrintDialog diag = new PrintDialog();
diag.Document = printDocument1;
if (diag.ShowDialog() == DialogResult.OK)
{
printDocument1.Print();
}
}
Листинг
6.9.
Обратите внимание на свойство диалоговых окон Document — мы программно устанавливаем значение printDocument1. Переключаемся в режим дизайна, выделяем объект printDocument1 и в окне Properties дважды щелкаем в поле события PrintPage:
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
}Дальнейший код будет относиться к этому обработчику. Проверяем наличие изображения в pictureBox1:
if (pictureBox1.Image == null)
{
e.Cancel = true;
return;
}Определяем печатную область страницы:
float leftMargin = e.MarginBounds.Left; float rightMargin = e.MarginBounds.Right; float topMargin = e.MarginBounds.Top; float bottomMargin= e.MarginBounds.Bottom; float printableWidth = e.MarginBounds.Width; float printableHeight = e.MarginBounds.Height;
Cоздаем экземпляр graph класса Graphics:
Graphics graph = e.Graphics;
В документе, формируемом для печати, не содержится текста — ведь мы имеем дело с изображением. Но интересно будет выводить на печать строку, указывающую, к примеру, размер изображения. Для этого создадим экземпляр font класса Font:
Font font= new Font("Comic Sans MS", 16);
//Определяем высоту шрифта
float fontHeight = font.GetHeight(graph);
//Определяем размер пробелов
float spaceWidth = graph.MeasureString(" ", font).Width;Определяем область, в которую будет вписываться изображение; размер наибольшей стороны изображения составляет 90% от кратчайшей стороны листа:
float imageLength;
float Xposition = leftMargin;
float Yposition = topMargin + fontHeight;
if (printableWidth < printableHeight)
{
imageLength = printableWidth * 90/100;
Yposition += imageLength;
}
else
{
imageLength = printableHeight * 90/100;
Xposition += imageLength + spaceWidth;
}Выводим изображение в области rectImage:
Rectangle rectImage= new Rectangle((int)leftMargin + 1, (int)topMargin + 1, (int)imageLength,(int)imageLength); graph.DrawImage(pictureBox1.Image,(int)leftMargin + 1, (int)topMargin + 1, (int)imageLength,(int)imageLength);
Определяем область rectText и выводим в нее строку с указанием размера файла (используется метод PrintTextString ):
RectangleF rectText = new RectangleF(Xposition, Yposition, rightMargin - - Xposition, bottomMargin - Yposition); PrintText (graph, font,"Размер изображения: ", Convert.ToString (pictureBox1.Image.Size), ref rectText); }
На этом код метода printDocument1_PrintPage заканчивается. Для вывода изображения все готово. Остается только написать метод PrintText, который будет выводить текстовую строку. Привожу код этого метода с комментариями:
protected void PrintText( Graphics graph, Font font, string name, string text, ref RectangleF rectText)
{
// Определяем размеры печатной области для текста:
float leftMargin = rectText.Left;
float rightMargin = rectText.Right;
float topMargin = rectText.Top;
float bottomMargin = rectText.Bottom;
//Определяем высоту текста и координаты, где он будет выводиться:
float fontHeight = font.GetHeight(graph);
float Xposition = rectText.Left;
float Yposition = topMargin + fontHeight;
//Определяем ширину текста и размер пробелов
float spaceWidth = graph.MeasureString(" ", font).Width;
float nameWidth = graph.MeasureString(name, font).Width;
graph.DrawString(name, font,
Brushes.Black, new PointF(Xposition, Yposition));
leftMargin += nameWidth + spaceWidth;
Xposition = leftMargin;
// Формируем несколько строк для текста в случае,
// если он не будет умещаться на одной строке
string[] words
= text.Split(" \r\t\n\0".ToCharArray());
foreach (string word in words)
{
float wordWidth = graph.MeasureString(
word, font).Width;
if (wordWidth == 0.0)
continue;
if (Xposition + wordWidth > rightMargin)
{
// Начало с новой строки
Xposition = leftMargin;
Yposition += fontHeight;
if (Yposition > bottomMargin)
{
break;
}
}
graph.DrawString(word, font,Brushes.Black, new PointF(Xposition, Yposition));
Xposition += wordWidth;
}
// Исключаем область, на которую был выведен текст, из области печати
//для избежания наложения текста и рисунка
rectText.Y = Yposition;
rectText.Height = bottomMargin - Yposition;
}
Листинг
6.10.
Запускаем приложение. При выборе книжной ориентации страницы рисунок вписывается с сохранением своих пропорций (рис. 6.14), затем выводится на печать (рис. 6.15).
В конце лекции приводится полный листинг приложения Picture Viewer, а исходный проект имеется на диске, прилагаемом к книге (Code\Glava6\ Picture Viewer).

