Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2011.04.24;
Скачать: [xml.tar.bz2];

Вниз

Насколько я неправильно вывожу на печать через TPrinter?   Найти похожие ветки 

 
Студент   (2011-01-18 23:30) [0]

Здравствуйте... Нужно было срочно сделать чтоб программа распечатывала нарисованное... Так как срочно - сойдёт и на VCL...
Нашёл что можно подключить модуль Printers и появится переменная Printer (экземпляр класса TPrinter) при помощи которой можно "печатать"...

Найденные примеры про него не работали в моём случае (пока не понял почему)... А отрисовка прямо на холст Printer не получается - моя процедура рисования совершенно не рассчитана на масштабирование...
Сделал пока что через временный TBitmap... В принципе работает, только выглядит страшновато (ибо битмап масштабируется интерполяцией по соседним):

Procedure TForm1.SpeedButton7Click(Sender: TObject);
Var Bmp: TBitmap; i, MinX, MinY, MaxX, MaxY: Integer;
Begin
If PrintDialog1.Execute Then
     Begin
     Bmp:=TBitmap.Create;
     Bmp.PixelFormat:=pf24bit;
     Bmp.Width:=PaintBox1.Width;
     Bmp.Height:=PaintBox1.Height;
     Draw_All(Bmp.Canvas);
     MinX:=Bmp.Width;
     MinY:=Bmp.Height;
     MaxX:=0;
     MaxY:=0;
     For i:=0 To .......
           Begin
           ....... // тут считались отступы до рисунка
           End;
     MinX:=MinX-40;
     MinY:=MinY-40;
     MaxX:=MaxX+41;
     MaxY:=MaxY+41;
     Bmp.Canvas.Draw(-MinX, -MinY, Bmp);
     Bmp.Width:=MaxX-MinX;
     Bmp.Height:=MaxY-MinY;
     // Bmp.SaveToFile("Q:\Test.bmp");
     If (Bmp.Width>Bmp.Height) Then
           Printer.Orientation:=poLandscape
     Else
           Printer.Orientation:=poPortrait;
     Printer.BeginDoc;
     Printer.Canvas.Refresh;
     If (Printer.PageWidth/Bmp.Width>Printer.PageHeight/Bmp.Height) Then
           Printer.Canvas.StretchDraw(Rect(0, 0, Round(Bmp.Width*Printer.PageHeight/Bmp.Height), Printer.PageHeight), Bmp)
     Else
           Printer.Canvas.StretchDraw(Rect(0, 0, Printer.PageWidth, Round(Bmp.Height*Printer.PageWidth/Bmp.Width)), Bmp);
     Printer.EndDoc;
     Bmp.Free;
     End;
End;


Как оно у меня получилось для сделанного впопыхах и на коленке? Нужно будет потом поизучать как печатать на чистом Api...


 
Ega23 ©   (2011-01-18 23:39) [1]


> Как оно у меня получилось для сделанного впопыхах и на коленке?

Некрасиво получилось. И небезопасно.


 
Студент   (2011-01-18 23:48) [2]

Небезопасно? о__О
В каком смысле?


 
Ega23 ©   (2011-01-18 23:57) [3]


> Небезопасно? о__О


SomeObject := TSomeObject.Create;
try
 ... // Работа с SomeObject
finally
 SomeObject.Free;
end;


 
Студент   (2011-01-19 00:04) [4]

Работу с TBitmap в try/finally? Ни разу не видел чтоб кто-то так делал...
Да и чтоб моли быть ошибки при работой с битмапом тоже не было никогда...


 
Ega23 ©   (2011-01-19 00:16) [5]


>  Ни разу не видел чтоб кто-то так делал...

Любое исключение между Create и Destroy даст тебе утечку памяти. В случае try..finally утечки не будет.
Впрочем, можешь писать так, как тебе хочется. только тогда в следующий раз не спрашивай "Как оно у меня получилось"


 
Студент   (2011-01-19 00:35) [6]

Добавил try/finally... Спасибо.....)
Только их же вроде нельзя больше 2-х вложенных, да? А что ж поделать когда SomeObject глобальная или поле класса и во многих процедурах используется?

Так что ещё можно поправить в получившейся печати? Мне до утра не успеть переделать процедуру рисования...


 
KilkennyCat ©   (2011-01-19 01:20) [7]

оно работает? если да, то зачем спешить до утра?


 
Servy ©   (2011-01-19 01:35) [8]


> В принципе работает, только выглядит страшновато (ибо битмап
> масштабируется интерполяцией по соседним):


Задать режим интерполяции можно так:

SetStretchBltMode(Printer.Canvas.Handle, HALFTONE);

HALFTONE - самый качественный и соответственно, медленный режим. Не скажу наверняка, что сработает для кенвас принтера (хотя должно), но можно использовать промежуточный Bitmap с размерами Printer.PageWidth на Printer.PageHeight и потом печатать уже этот промежуточный Bitmap.


> А отрисовка прямо на холст Printer не получается - моя процедура
> рисования совершенно не рассчитана на масштабирование...


Это напрасно ^_^.


> Нужно будет потом поизучать как печатать на чистом Api...


Можно нескромный вопрос - нафига? Ну то есть оно конечно полезно и интересно, но вы бы для начала про объекты таки почитали да с ООП разобрались. Ибо большие программы на чистом api писать удовольствие еще то. Хотя знание, как оно работает на низком уровне весьма полезно, чтобы правильно использовать подготовленные для вас предыдущими поколениями программистов удобные обертки ^_^.


> Только их же вроде нельзя больше 2-х вложенных, да?


Можно.


> А что ж поделать когда SomeObject глобальная


Если она один раз создается в начале и один раз удаляется в конце - то очевидно утечке памяти здесь появиться неоткуда. Использовать глобальную переменную чтобы то создавать в нее объект, то удалять его - имхо плохая идея, нужно пересмотреть архитектуру.


> или поле класса

Если поле класса (обычно сие называется аггрегацией), то классический подход - создать вложенный объект в конструкторе класса-вместилища, а удалить в деструкторе. Если наш свежесозданный класс будут использовать с умом (то есть, не забудут уничтожить каждый экземпляр), то и вложенный объект будет успешно удален.


 
KilkennyCat ©   (2011-01-19 01:38) [9]

но я бы не стал бы так сложно...

во-первых, у меня был бы глобальный битмап, который все хранит и выводится на паинтбокс. это многое упрощает, особенно - масштабирование (хотя, конечно, зависит от тз, но в простом варианте можно изначально рисовать в максимальном разрешении и стретчить на паинт).
а раз есть глобальный битмап, то остается его скопировать на канву принтера, с выполнением ряда условий, которые, вроде как, уже есть (поля, поворот и т.д.).

вот только диалоговое окно я бы сделал свое, ибо удобно. например, предпросмотр. ты поворачиваешь принудительно, а должно быть три варианта, автомат и два типовых. ну и поля, масштаб, центровка... можно и до утра успеть. а можно и на торри глянуть, наверняка есть.


 
Servy ©   (2011-01-19 02:23) [10]


> Так что ещё можно поправить в получившейся печати?

По самой печати ничего в голову не приходит, так как требования к ней не озвучены. В простейшем варианте, если не учитывать возможные желательные дополнительные возможности типа уже упомянутых предпросмотра и более широкого контроля пользователем чего куда печатать, все вроде как нормально. Что в процедуре рисования - неизвестно, ну а в выводе битмепа на принтер особо накосячить то и негде :).

Из эстетических соображений, можно переименовать SpeedButton7 во что-нибудь более говорящее, например sbPrint, SpeedButtonPrint или PrintSpeedButton (это уж как вам кажется удобнее). А то мне как-то пришлось разбираться с чужой программой, где был в частности Edit67; не могу сказать, что исходный код читался легко (удержать в памяти за что какой из 67 с лишним эдитов на одной огромной форме отвечает я не смог; фреймы автор почему-то тоже использовать не стал).

Кроме того, при составных названиях методов или переменных обычно используют или "CamelCase" (есть еще вариант "camelCase" с первой маленькой буквой, который например часто встречается в исходниках на Java) или "name_with_underline". Использовать и то и другое, как в случае с Draw_All, насколько мне известно не принято и вызывает некоторое недоумение. Впрочем, это уже _весьма_ несущественная придирка :).


> во-первых, у меня был бы глобальный битмап, который все
> хранит и выводится на паинтбокс. это многое упрощает, особенно
> - масштабирование


Наличие глобального битмепа не сильно помогает в масштабировании - если у нас есть процедура, рисующая на указанный Canvas в максимальном разрешении, то сделать из нее Bitmap - раз плюнуть, что и демонстрирует авторский код (правда, там еще какие-то наполовину спрятанные от нас шаманства с отступами, существенно код удлинившие).

Глобальный битмеп (то есть, по сути промежуточный буфер между рисованием и отображением куда-либо, в своем роде кеширование) может пригодиться, если отрисовка занимает довольно много времени, чтобы не повторять ее при каждой перерисовке окна или выводе на печать, а скопировать уже готовый битмеп куда надо. Впрочем, так как мы не знаем, что там в Draw_All, то нельзя быть уверенным, что у автора такое кеширование уже не реализовано :).


 
Студент   (2011-01-19 02:56) [11]


> оно работает? если да, то зачем спешить до утра?


Ну... Боюсь может припомнится мне "кубикообразное" распечатывание... Она ж смахивает на картинку из 8-мибитных игр...


> изначально рисовать в максимальном разрешении и стретчить
> на паинт


Без хорошего сглаживания получится просто каша из пикселей...
У меня векторно всё рисуется... И довольно динамически изменяется... Не очень хорошо пойдёт "глобальный битмап"...


> Это напрасно ^_^.


Говорю ж - делал наспех... :3


> Задать режим интерполяции можно так:


Боюсь ошибиться, но вроде читал где-то что для полноцветных HDC оно выставляется само, автоматически... И это оно и есть - по соседним...
Во всяком случае добавление SetStretchBltMode + HALFTONE внешне не изменило вообще ничего...

Но всё резко изменится когда я наконец-то доберусь до GDIPlus... (с)


 
KilkennyCat ©   (2011-01-19 02:56) [12]


>  если у нас есть процедура, рисующая на указанный Canvas
> в максимальном разрешении,

в случае с векторной графикой - обеими руками за.
в случае с растровой - не все так просто.


 
Студент   (2011-01-19 03:02) [13]


> Из эстетических соображений, можно переименовать SpeedButton7
> во что-нибудь более говорящее, например sbPrint, SpeedButtonPrint
> или PrintSpeedButton (это уж как вам кажется удобнее).


Это хороший тон работы в коллективах... Я же всегда один... Кроме меня никто никогда не увидит исходник...)


 
KilkennyCat ©   (2011-01-19 03:08) [14]


> Но всё резко изменится когда я наконец-то доберусь до GDIPlus.
> ..

это точно. я добрался :)


 
Servy ©   (2011-01-19 03:25) [15]


> Боюсь ошибиться, но вроде читал где-то что для полноцветных
> HDC оно выставляется само, автоматически... И это оно и
> есть - по соседним...


Легко ж проверить:

procedure TForm1.Button1Click(Sender: TObject);
var
 Bmp: TBitmap;
 Mode: Integer;
 S: string;
begin
 Bmp := TBitmap.Create;
 try
   Bmp.PixelFormat := pf24bit;
   Bmp.SetSize(100, 100);

   Mode := GetStretchBltMode(Bmp.Canvas.Handle);
   S := "24bit bitmap default stretch mode: " + IntToStr(Mode) + #13#10;

   Printer.BeginDoc;
   try
     Mode := GetStretchBltMode(Printer.Canvas.Handle);
     S := S + "Printer canvas stretch mode: " + IntToStr(Mode);
   finally
     Printer.EndDoc;
   end;
 finally
   Bmp.Free;
 end;

 MessageBox(Handle, PChar(S), "Result", MB_OK or MB_ICONINFORMATION);
end;


У меня вышло так (принтер чернобелый ^_^)

---------------------------
Result
---------------------------
24bit bitmap default stretch mode: 1

Printer canvas stretch mode: 1
---------------------------
ОК  
---------------------------


1 это BLACKONWHITE. HALFTONE это 4.


> Во всяком случае добавление SetStretchBltMode + HALFTONE
> внешне не изменило вообще ничего...


HALFTONE помогает получить качественное маленькое изображение, если есть большое. Дефолтное "ужимание" изображений корячит их весьма некрасиво, а с помощью HALFTONE получаются вполне неплохие копии.

А вот если исходное изображение 100 на 100 пикселей, то существенно увеличить его "без кубиков" мало что поможет. Рисуйте в бОльшем разрешении - уменьшать то легче, чем увеличивать.


 
Ega23 ©   (2011-01-19 06:29) [16]


> Студент   (19.01.11 00:35) [6]
>
> Только их же вроде нельзя больше 2-х вложенных, да?


Плюнь в того, кто тебе это сказал.


 
han_malign   (2011-01-19 09:21) [17]


> > Нужно будет потом поизучать как печатать на чистом Api...
> Можно нескромный вопрос - нафига?

- нескромный ответ:
 TPrinter - не оценивает результатов вызова StartDoc и StartPage/EndPage, в результате при попытке блитинга на DC отключенного принтера(в моем случае сетевого) возникает AV, которое там не надо...
Также он не позволяет одновременную печать на несколько принтеров, но это уже довольно экзотическая задача...

> моя процедура рисования совершенно не рассчитана на масштабирование
...
> У меня векторно всё рисуется...

- SetWorldTransform - и твоя процедура рассчитана на масштабирование...


 
han_malign   (2011-01-19 09:53) [18]


> SetWorldTransform

- также смотри (Set|Scale)(Window|Viewport)ExtEx... Обычно в изометрическом режиме(если "квадратность" экрана и принтера разные).
SetWorldTransform - произвольные афинные преобразования координат с хорошей точностью, и не исключено что вектор таки останется вектором(а не растянутым растром) - не проверял...

Или тупо SetWindowExtEx - размер твоей области не масштабируемого рендеринга, SetViewportExtEx - размер который хочешь увидеть на бумаге, и voilà... (с этими добиться нормального масштабирования(на экранных DC) у меня ни разу не получилось, какие то там странные ошибки округления вылезают)


 
Amoeba_   (2011-01-19 16:33) [19]

О преобразованиях координат и масштабировании есть в книжке Тейксейры и Пачеко.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2011.04.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.004 c
6-1191246733
__Unnamed__
2007-10-01 17:52
2011.04.24
Вопрос про сокеты, а точнее про FD_CLOSE и FD_READ


2-1295595110
HF-Trade
2011-01-21 10:31
2011.04.24
Цвет шрифта и фон заголовков TPageControl в Windows 7 x64


15-1294598101
from_california
2011-01-09 21:35
2011.04.24
заполнение таблиц в ms sql server management studio


15-1293701642
12
2010-12-30 12:34
2011.04.24
Произношение комплексного числа. По каким буквам "ударять"?


2-1295432083
Scott Storch
2011-01-19 13:14
2011.04.24
упростить алгоритм TStrings.SetDelimiterText





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский