C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
hDC Printer, как?
Лена
Отправлено: 30.08.2006, 11:56


Мастер участка

Группа: Участник
Сообщений: 501



У меня есть метод одного из компонентов, который посылает свое содержимое на печать. Первый параметр принимает контекст устройства принтера. Как правильно получить контекст устройства?
XPrintMap->PrintMap(..., 0, 0, XPrintMap->Width,XPrintMap->Height);

Вместо многоточия должно быть из справки: hDC Printer device context.
Can be any device context.
Valdemar
Отправлено: 30.08.2006, 12:28


Мастер участка

Группа: Участник
Сообщений: 433



Попробуйте Printer()->Handle
Лена
Отправлено: 30.08.2006, 15:38


Мастер участка

Группа: Участник
Сообщений: 501



Не работает:
XPrintMap->PrintMap(Printer()->Handle ,0, 0, XPrintMap->Width,XPrintMap->Height);

[C++ Error] FPPreview.cpp(205): E2034 Cannot convert 'void *' to 'unsigned int'
[C++ Error] FPPreview.cpp(205): E2342 Type mismatch in parameter 'hDC' (wanted 'unsigned int', got 'void *')

sad.gif
Лена
Отправлено: 30.08.2006, 15:44


Мастер участка

Группа: Участник
Сообщений: 501



Так нет ошибки:
XPrintMap->PrintMap((int)Printer()->Handle,0, 0, XPrintMap->Width,XPrintMap->Height);
но ничего и не происходит...
Valdemar
Отправлено: 31.08.2006, 08:37


Мастер участка

Группа: Участник
Сообщений: 433



Можно еще так:
CODE
   char pName[100], ADriver[100], APort[100];
   int ADeviceMode;
   Printer()->GetPrinterA(pName,ADriver, APort,ADeviceMode);
   HANDLE hPrinter;
   OpenPrinter(pName, &hPrinter, NULL);

hPrinter будет Handle принтера по умолчанию.
AVC
Отправлено: 31.08.2006, 09:32


Ветеран

Группа: Модератор
Сообщений: 1583



Когда то делал эмулятор досовский печати. Выглядело так:
CODE

bool __fastcall TF_DosPrint::Print (void)
{
AnsiString prnname = системное_имя_выбранного_пользователем_принтера;
// prn->GetPrinter(вот_это_device, driver, port, devmode);

AnsiString docname = Caption;

if (prnname.IsEmpty()) return false;

AnsiString text = FPrintText->Text;
if (text.IsEmpty())  return false;

DOC_INFO_1 doc_info_1;
doc_info_1.pDocName = docname.c_str();
doc_info_1.pOutputFile = NULL;
doc_info_1.pDatatype = NULL;

HANDLE phandle = 0;
DWORD tcou = text.Length();
DWORD pcou = 0;

bool ret = true;

try {
if (!OpenPrinter(prnname.c_str(), &phandle, NULL))
throw Exception("OpenPrinter");

if (!StartDocPrinter(phandle, 1, (LPBYTE)(&doc_info_1)))
throw Exception("StartDocPrinter");

if (!WritePrinter (phandle, text.c_str(), tcou, &pcou))
throw Exception("WritePrinter");

if (!EndDocPrinter(phandle))
throw Exception("EndDocPrinter");

} // try

catch (Exception &xcp)
{ text = AnsiString("Ошибка при вызове функции ") + xcp.Message;
ShowMessage(text);
ret = false;
}

if (phandle) ClosePrinter(phandle);
return ret;
}


То же самое, что предложил Valdemar

Отредактировано AVC — 31/08/2006, 08:45
Лена
Отправлено: 31.08.2006, 10:52


Мастер участка

Группа: Участник
Сообщений: 501



Что-то не получается. Параметры, которые требует PrintMap(unsigned int hDC, long X, long Y, long W, long H). В справе прилагается пример на VB:
CODE

OBJECT.PrintMap (hDC x, y, w, h)

Part Description
OBJECT Represents a Map object.
hDC Printer device context. Can be any device context.
x Upper left corner X in HIMETRIC units.
y Upper left corner Y in HIMETRIC units.
w Width in HIMETRIC units.
h Height in HIMETRIC units.

Private Sub Command4_Click()
On Error GoTo ErrorHandler ` Set up error handler.
' coords must be in himetric
' print same size as on screen, in upper left of page
ScaleMode = 6 `set mode to mm
' there is no Printer.StartDoc method, it seems it is done
' implicitly when you use one of the printer.print methods
' so we need to print something before we print our map
' to start the page
Printer.CurrentX = 0
Printer.CurrentY = 0
Printer.Print " "

Map1.PrintMap Printer.hDC, 0, 0, Map1.Width * 100, _
Map1.Height * 100
Printer.NewPage ` Send new page.

Printer.EndDoc ` Printing is finished.
Exit Sub



У меня Map1 это XPrintMap. Я пишу так:
CODE

char pName[100], ADriver[100], APort[100];
int ADeviceMode;
Printer()->GetPrinterA(pName,ADriver, APort,ADeviceMode); // Warning
HANDLE hPrinter;
OpenPrinter(pName, &hPrinter, NULL);
XPrintMap->PrintMap(hPrinter,0, 0, XPrintMap->Width,XPrintMap->Height); // Error

Получаю ошибки:
[C++ Warning] FPPreview.cpp(165): W8030 Temporary used for parameter 'ADeviceMode' in call to '_fastcall TPrinter::GetPrinterA(char *,char *,char *,unsigned int &)'
[C++ Error] FPPreview.cpp(170): E2034 Cannot convert 'void *' to 'unsigned int'
[C++ Error] FPPreview.cpp(170): E2342 Type mismatch in parameter 'hDC' (wanted 'unsigned int', got 'void *')

Если написать так:
XPrintMap->PrintMap((int)hPrinter,0, 0, XPrintMap->Width,XPrintMap->Height);
то:
[C++ Warning] FPPreview.cpp(165): W8030 Temporary used for parameter 'ADeviceMode' in call to '_fastcall TPrinter::GetPrinterA(char *,char *,char *,unsigned int &)'

Отредактировано Лена — 31/08/2006, 10:54
VTim
Отправлено: 31.08.2006, 11:12


Ученик-кочегар

Группа: Участник
Сообщений: 4



Тяжело смотреть на женские слезы ...

hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);
//szPrinterName — Имя принтера из установленных, куда печатаем
...........
XPrintMap->PrintMap(hPrinterDC,0, 0, XPrintMap->Width,XPrintMap->Height);
...........
DeleteDC(hPrinterDC);

Лена
Отправлено: 31.08.2006, 12:12


Мастер участка

Группа: Участник
Сообщений: 501



Два вопроса:
1. Перед печатью я вызываю окно настроек принтера:
PrinterSetupDialog1->Execute(); (рис)
Как мне проинициализировать szPrinterName?

2. Чтобы не было ошибки, я пишу с (int):
XPrintMap->PrintMap((int)hPrinter,0, 0, XPrintMap->Width,XPrintMap->Height); без (int) получаю:
[C++ Error] FPPreview.cpp(175): E2034 Cannot convert 'void *' to 'unsigned int'
[C++ Error] FPPreview.cpp(175): E2342 Type mismatch in parameter 'hDC' (wanted 'unsigned int', got 'void *')
Правильно ли я добавляю (int), чтобы избежать этих ошибок? Такое привидение корректно в PrintMap?



Присоединить изображение

Присоединить изображение

VTim
Отправлено: 31.08.2006, 12:46


Ученик-кочегар

Группа: Участник
Сообщений: 4



1. char szPrinterName[] = "Adobe PDF";
Для выбора из списка PrinterSetupDialog не годится, проще всего получить список установленных принтеров с помощью API EnumPrinters.
(Для NT чуть посложнее).

2. HDC hPrinterDC;
Приводить надо (если требуется) к типу для компонента PrintMap в соотв. с заголовочным файлом.
Лена
Отправлено: 31.08.2006, 13:22


Мастер участка

Группа: Участник
Сообщений: 501



Ошибки нет, но пока ничего не происходит:
void __fastcall TForm2::sBitBtn1Click(TObject *Sender)
{
char szPrinterName[] = "Adobe PDF";
HANDLE hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);
XPrintMap->PrintMap((int)hPrinterDC,0, 0, XPrintMap->Width,XPrintMap->Height);
DeleteDC(hPrinterDC);
}
Буду разбираться.
Большое спасибо за консультации.
VTim
Отправлено: 31.08.2006, 13:34


Ученик-кочегар

Группа: Участник
Сообщений: 4



1. HANDLE hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);
Это некорректный тип контекста, надо:
HDC hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);

HANDLE и HDC разные вещи!

2. Не уверен, надо ли явно приводить к типу (int)?

3. Для отладки советовал бы попробовать вывод на обычный принтер, т.к. конверторы
и виртуальные принтеры имеют свои особенности, кроме того, возможно, компонент
поддерживает печать только на физическое устройство.
Grigoriy
Отправлено: 31.08.2006, 13:36


Мастер участка

Группа: Участник
Сообщений: 381



QUOTE (Лена @ 30/08/2006, 15:38)
Не работает:
XPrintMap->PrintMap(Printer()->Handle ,0, 0, XPrintMap->Width,XPrintMap->Height);

Нет.
Надо так писать
CODE

TPrinter* printer1= Printer();//создаем объект класса TPrinter (экземпляр класса TPrinter)
//---------------
//ХЕНДЛ канвы объекта printer1 — это и есть хендл графического устройства WINDOWS для вывода на печать
XPrintMap->PrintMap(printer1->Canvas->Handle,0,0,
XPrintMap->Width,XPrintMap->Height);
//---------------
delete printer1;


ХЕНДЛ канвы объекта класса TPrinter является тем HDC графического устройства для печати.
К примеру хендл канвы формы
Form1->Canvas->Handle
это HDC графического устройства по выводу графики в окно,

и т.п.
Лена
Отправлено: 31.08.2006, 14:09


Мастер участка

Группа: Участник
Сообщений: 501



Если написать так:
char szPrinterName[] = "Adobe PDF";
HDC hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);
XPrintMap->PrintMap((int)hPrinterDC,0, 0, XPrintMap->Width,XPrintMap->Height);
DeleteDC(hPrinterDC);
То ничего не происходит не печатает ни на виртуальный ни на реальный принтер.


Если написать так:
TPrinter* printer1= Printer();
XPrintMap->PrintMap((int)printer1->Canvas->Handle,0,0,XPrintMap->Width,XPrintMap->Height); // Без (int) вообще не компилируется.
delete printer1;
то исключение, которое на рисунке ниже.
Предварительно указала в окне PrinterSetupDialog1->Execute(); тип Adobe PDF. Получается, что Windows не воспринимает настройку в PrinterSetupDialog1->Execute();? sad.gif



Присоединить изображение

Присоединить изображение

VTim
Отправлено: 31.08.2006, 14:26


Ученик-кочегар

Группа: Участник
Сообщений: 4



<если написать так:
char szPrinterName[] = "Adobe PDF";
HDC hPrinterDC = CreateDC(NULL, szPrinterName, NULL, NULL);
XPrintMap->PrintMap((int)hPrinterDC,0, 0, XPrintMap->Width,XPrintMap->Height);
DeleteDC(hPrinterDC);
То ничего не происходит не печатает ни на виртуальный ни на реальный принтер.>

Здесь вывод происходит ТОЛЬКО на "Adobe PDF".
Вместо "Adobe PDF" надо подставить имя локального принтера, напр. "HP Laser Jet 1120" или др., как установлено в системе

Лена
Отправлено: 31.08.2006, 14:56


Мастер участка

Группа: Участник
Сообщений: 501



Я забыла выше написать, что пробовала:
char szPrinterName[] = "hp deskjet 940c";
предварительно назначив этот сетевой принтер по умолчанию. Нет, ничего не происходит — не печатает. Хотя из любой графической программы принтер печатает.
Grigoriy
Отправлено: 31.08.2006, 15:16


Мастер участка

Группа: Участник
Сообщений: 381



QUOTE (Лена @ 30/08/2006, 11:56)
Вместо многоточия должно быть из справки: hDC Printer device context.
Can be any device context.

Тогда при чём здесь тип int, без которого "не компилируется", если должен быть тип HDC ?
Лена
Отправлено: 31.08.2006, 15:25


Мастер участка

Группа: Участник
Сообщений: 501



Без int ошибки:
[C++ Error] FPPreview.cpp(178): E2034 Cannot convert 'void *' to 'unsigned int'
[C++ Error] FPPreview.cpp(178): E2342 Type mismatch in parameter 'hDC' (wanted 'unsigned int', got 'void *')
Речь идет об компоненте ActiveX при интеграции в Builder он требует то что на рисунке ниже.
В справке есть пример для VB и для классического С++. Для С++ пример такой:
CODE

// Map.PaperUnit Property
// Map.PrintMap Method
void CSampleProjectView::OnPrintMap(CDC* pDC,CPrintInfo* pInfo) {
 try {
  // get paper width in mm and convert to HIMETRIC (100th of a mm)
  m_Map.SetPaperUnit(miUnitMillimeter);
 
  double pw = m_Map.GetMapPaperWidth() * 100;
  double ph = m_Map.GetMapPaperHeight()* 100;

  m_Map.PrintMap((long)pDC->m_hDC,
pInfo->m_rectDraw.left,pInfo->m_rectDraw.
top,(long)pw,(long)ph);
 } catch (COleDispatchException *e) {

  e->ReportError();
  e->Delete();
 } catch (COleException *e) {
  e->ReportError();
  e->Delete();
 }
}

Параметры ф-ции печати для Builder 6 на рисунке ниже:


Присоединить изображение

Присоединить изображение

Лена
Отправлено: 01.09.2006, 16:19


Мастер участка

Группа: Участник
Сообщений: 501



Я вот новое исследование провела:
Написала код, который вроде работает. Возникает окно сохранения файла на диск, начинается печать (вижу в трее), но потом вываливается исключение. Рисунок прилагаю.
#include vcl/printers.hpp

Printer()->BeginDoc();
XPrintMap->PrintMap((int)Printer()->Handle,0, 0, 100,100);
Printer()->EndDoc();

Может это глюк компонента?

Отредактировано Лена — 01/09/2006, 16:20

Присоединить изображение

Присоединить изображение

Лена
Отправлено: 01.09.2006, 16:56


Мастер участка

Группа: Участник
Сообщений: 501



Интересно, что ели печатать на реальный принтер, то исключения не выскакивает, а из принтера выходит чистый лист.
E.S.
Отправлено: 07.09.2006, 19:06


Не зарегистрирован







Нужно передавать не чистый контекст, а уже заполненный.

HDC hDC = GetDC( Form1->Handle );

// печатаем... на всякий случай в блоке try { ... }

ReleaseDC( Form1->Handle, hDC );
Лена
Отправлено: 08.09.2006, 09:43


Мастер участка

Группа: Участник
Сообщений: 501



QUOTE (E.S. @ 07/09/2006, 19:06)
Нужно передавать не чистый контекст, а уже заполненный.

HDC hDC = GetDC( Form1->Handle );

// печатаем... на всякий случай в блоке try { ... }

ReleaseDC( Form1->Handle, hDC );

Спасибо, попробую.
Сейчас у меня код, который ниже. Он отлично работает для реального принтера. Для виртуального этот код, выводив в PDF файл только текст и то почему то без отступов (200,100), а строго в верхнем левом углу страницы файла PDF. BMP файл в виртуальном принтере тоже не печатается. Повторю, что код отлично работает для реального принтера:
CODE

//печать на реальный принтер
void __fastcall TForm2::sButton2Click(TObject *Sender)
{
//код формирующий картунку bmp в Clipboard пропущен
//далее:

TClipboard *pCB = Clipboard();
 if (pCB->HasFormat(CF_BITMAP))
 {
  Graphics::TBitmap *pBitmap = new Graphics::TBitmap();
   try
     {
     pBitmap->LoadFromClipboardFormat(CF_BITMAP, pCB->GetAsHandle(CF_BITMAP), 0);
     Printer()->BeginDoc();
     Printer()->Canvas->StretchDraw(Rect(200,200,XPrintMap->Width + 1800,XPrintMap->Height + 1800), pBitmap);
     Printer()->Canvas->Font->Name = "Arial Cyr";
     Printer()->Canvas->Font->Size = 10;
     Printer()->Canvas->TextOut(200,100,"Фрагмент рисунка:");
     Printer()->EndDoc();
     }
   catch (...)
      {
       sShowMessage("Не удалось распечатать");
      }

   delete pBitmap;
  }

}

На виртуальный принтер получаю только текст из TextOut и без отсупов.
Цифру 1800 пришлось добавить, чтобы картинка была большая на листе A4. Без этой цифры печатается маленькой изображение. Хотя если вставить буфер обмена в любую графическую программу Photoshop и т .п. (см.рисунок) то видно что в буфере обмена нормальное большое изображение и печатается оно нормально из графической программы. Видимо в моем коде надо еще какие-то коэффициенты масштабирования предусмотреть, чтобы не писать подобранные наугад цифры 1800.
На рисунке реальное изображение которое поподает в буфер обмена. Мне же, приходиться в коде жестко добовлять цифру 1800 чтобы увидеть на бумаге похожие размеры:

Присоединить изображение

Присоединить изображение


Вернуться в Вопросы программирования в C++Builder