http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/samples/00727.html
上記のサイトのソースを使って、印刷するプログラムを
いままで作っていたアプリに追加したのですがcheckboxとradiobuttonは
印刷物に写りません。
縮尺を疑ってみたのですがPanelをどのようなサイズにしても写りませんでした。
どなたかどのような原因が考えられるか教えてください。
お願いします。
リンク先のソースすら未確認ですが。
WindowsXPからそのような用途専用のAPIが実装されてます。
user32のPrintWindowってやつです。
お返事ありがとうございます。
調べてみたのですが、どのように実装していいのかわかりません。
ホント初心者ですいません。
なにかいいソースなどないでしょうか。
お願いします。
>なにかいいソースなどないでしょうか。
http://delphi.about.com/od/delphitips2008/qt/print_window.htm
こんにちは.Mr.XRAYです.
既に具体的なコードのレスがありますが,また別のということで.
>調べてみたのですが、どのように実装していいのかわかりません。
どのように調べたのかは分かりませんが,少なくともOSのバージョンはXP以降ということが
話の展開で判断できました.Delphiのバージョンが不明ですので,Delphi2007以降と
仮定します.
PrintWindow関数はDelphiのVCLでは定義されていません.このような関数を使うには
(1) Delphiのヘルプで[フィルタ条件]を[Microsoft Windows Platform SDK]にする.
(2) 今回の場合検索語句をPrintWindowにして[検索]ボタンをクリック
(3) 今回の場合,PrintWindowが先頭で,反転表示されるので,それをダブルクリック
(4) 表示された関数定義をDelphi言語に直す.
のようにして使用します.
手前みそですが,以下を参考にしてください.
http://mrxray.on.coocan.jp/Others/Usage_Win32API.htm
今回の場合は,例えば以下ように書けます(変数名もヘルプと同じにしていますが,
同じである必要はありません.型は同じにします).
function PrintWindow(
hwnd : HWND;
hdcBlt : HDC;
nFlags : UINT ) : BOOL; stdcall; external 'user32.dll';
これを,最初に提示されているサンプルコードのPagePanel.PaintTo(DC, 0, 0);の代わりに使用します.
ヘルプでは,nFlagsの値が判断しかねますが,0か1で試してみてください.
ただし,PrintWindow関数は,Form1.Printと同じで,ビットマップ出力です.
PaintToとは描画仕様が異なりので,注意してください.
>(1) Delphiのヘルプで[フィルタ条件]を[Microsoft Windows Platform SDK]にする.
Delphi2007の場合は,右側のヘルプの種類を MSDN オンライン (英語) にしてください.
Delphi2009の場合は,そのままでOKです.
Delphi2010では確認していません.
こんにちは。
同様の印刷の問題があって検索したところここに行き着きました。
Mr.XRAYさんの方法でPrintWindowをPaintToの代わりにコードを変えて実行したのですが、印刷物にはなにも書かれていませんでした。
下記がそのコードなのですが、間違いがあればお教えください。
procedure TPreviewForm.Button1Click(Sender: TObject);
var
DC: HDC;
DevPPIX, DevPPIY: integer;
begin
try
Printer.BeginDoc;
DC := Printer.Canvas.Handle;
DevPPIX := GetDeviceCaps( DC, LOGPIXELSX );
DevPPIY := GetDeviceCaps( DC, LOGPIXELSY );
SetMapMode( DC, MM_ANISOTROPIC );
SetViewPortExtEx(DC, DevPPIX, DevPPIY, nil );
SetViewPortOrgEx(DC, 0, 0, nil );
SetWindowExtEx( DC,
Round( PagePanel.Width * DevPPIX / Printer.PageWidth ),
Round( PagePanel.Height * DevPPIY / Printer.PageHeight ), nil);
// 幅を合わせて等倍
// Round( PagePanel.Width * DevPPIX / Printer.PageWidth ), nil);
// PagePanel.PaintTo(DC, 0, 0);
PrintWindow(Self.Handle,DC,100);
finally
Printer.EndDoc;
end;
end;
もちろん、
function PrintWindow(
hwnd : HWND;
hdcBlt : HDC;
nFlags : UINT ) : BOOL; stdcall; external 'user32.dll';
をinterfaceの最後(varのすぐ上)に宣言しています。
よろしくお願いします。
> PrintWindow(Self.Handle,DC,100);
第3引数は100とか適当な数字でいいの? nFlagsに指定できる値は以下のいずれか(って一つしか書いてない)ですけど。
・PW_CLIENTONLY Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.
PW_CLIENTONLYの具体的な値が分からないけど、ウィンドウ全体を印刷したいなら単に0でいいのかな。
後は、Remarksに Before calling PrintWindow, first select a bitmap into hdcBlt とあるのが気になりますね。
Mr.XRAYさんもちょっと触れているけど、まずビットマップのCanvasに描画してからプリンタへ出力、という手順でないといけないのかも。
補足、PrintWindowは成功するとtrueを返します。
falseだったらエラーなので、GetLastErrorでエラーコードを調べてみてください。
成功しているのに紙に出なかったら、印刷領域から外れているかもしれないので
SetViewPortとかを外して試してみましょう。
すいません。
100にした理由は試しにやったもので、
一応Mr.XRAYさんのおっしゃっているように0と1をまず試しました。
ご指摘のことは今から試してみたいと思います。
早々のレスありがとうございます。
いろいろ試したのですが、まだできません。
ふらっと別サイトで見つけたソースを試したところパラメータが間違っていると
GetLastErrorを自分のプログラムで実行したときと同じエラーが出ました。
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TForm2 = class(TForm)
Button1: TButton;
Image1: TImage;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
function PrintWindow(SourceWindow: hwnd; Destination: hdc; nFlags: cardinal): bool; stdcall; external 'user32.dll' name 'PrintWindow';
var
Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
bmp : TBitmap;
wnd : cardinal;
rec : TRect;
begin
wnd := FindWindow('TScreenRecurF', nil); // get the handle
// of your window
GetWindowRect(wnd, rec);
bmp := TBitmap.Create;
try
bmp.Width := rec.Right - rec.Left;
bmp.Height := rec.Bottom - rec.Top;
bmp.PixelFormat := pf24bit;
PrintWindow(wnd, bmp.Canvas.Handle, 0);
ShowMessage(SysErrorMessage(GetLastError));
Image1.Picture.Assign(bmp);
finally
bmp.Free;
end;
end;
end.
サイトにはButton1Clickの中身だけのソースが上がっていたのですが、
interfaceの最後にprintwindowの宣言をして、button1とimage1をデザインに
加えるだけだと思うのどこで間違えているのか考えているのですがわかりません。
どなたか教えていただけませんでしょうか。
長文になりましたがよろしくお願いします。
> PrintWindow(wnd, bmp.Canvas.Handle, 0);
> ShowMessage(SysErrorMessage(GetLastError));
GetLastErrorは「最後に起こったエラーの番号」を返すもので、
直前の関数でエラーがあったかどうか教えてくれるものではないです。
PrintWindowの返り値はfalseだったんですか?
実際にエラーだとしたら、パラメータが間違っているということですから
wnd, bmp.Canvas.Handle に正しいハンドルが入っているか確認してください。
>下記がそのコードなのですが、間違いがあればお教えください。
ステハンの発言にはあまりレスしたくないのですが,名前が出ていたので.
まず,何を印刷したいのか明確にしてください.
PrintWindowの引数の意味は,
http://msdn.microsoft.com/ja-jp/library/dd162869(en-us,VS.85,lightweight).aspx
です.つまり
hwnd
A handle to the window that will be copied.
ですから,hwndは印刷対象のウィンドウハンドルです.
提示されたコードから推察すると,印刷したいのはPagePanelではないのでしょうか?
なお,
PW_CLIENTONLY = $00000001;
のようです.
確認さん
レスありがとうございます。
trueが返ってきました。
ハンドルが入っているかの確認なのですが、
実行時に変数上にマウスをあてて、
Handle Property
Handle-System.Cardinal
hdcBlt Field パスファイル名
hdcBlt-Windows.HDC
となっています。
これで入ってると認識してよろしいのでしょうか。
Mr.XRAYさん
レスありがとうございます。
目的はPagePanelと同様にパネル上にあるコンポーネントを
印刷することです。
先ほどこのソースを書きこんだのはWindowPrintが実行できるところを
確認したかったからです。
> trueが返ってきました。
trueなら成功です。おめでとうございます。エラーコードを見る必要はありません。
ハンドルも型調べても意味ないので値を見てほしかったのですが
(通常は値が0だったら無効ハンドルです)関数は成功してるからたぶん問題ないです。
それで画面に表示されないんだったら原因は別でしょう。
ちなみに上でDさんの紹介しているサンプルでは
PrintWindowの前後でビットマップのCanvasをLock/Unlockしていますが
それは試しました?
確認さん
レスありがとうございます。
trueは返ってくるのですがパラメータが間違っていますと
エラーが返ってきます。
値は0ではありませんでした。
Lock/Unlockはこれから試してみます。
本題とは関係ないけど、なんかまだわかってないみたいなので・・・
> trueは返ってくるのですがパラメータが間違っていますと
> エラーが返ってきます。
PrintWindowは成功してるんでしょ。
だったらGetLastErrorが返してるのは、それより前のどこかで何かの関数が失敗した時のエラーコードです。PrintWindowとは無関係。
すいません。てっきりPrintWindowでエラーだと思ってました。
PrintWindowより上にGetLastErrorを記入したら同様のエラーが出て、
ハンドルの代入の際のエラーでした。
ハンドルの内容を変更したらBitmapに描画出来ました。
あとはこれを印刷するようにプログラムを書きたいを思います。
みなさん、多くのレスありがとうございました。
ご協力ありがとうございました。
すいません。
上記のコメントはエラーじゃないよさんではなくお助けをのコメントです。
Mr.XRAYです.
>お助けを 2009/11/19(木) 04:38:59
のコードをコピペして,
PrintWindow(Self.Handle,DC,100); --> PrintWindow(PagePanel.Handle,DC,1);
にして印刷できていますよ.こちらでは.
ただし,Windows XP(SP3) + Delphi7 Pro です.
そちらの環境はどうなっていますか.
くどいようですが,
>提示されたコードから推察すると,印刷したいのはPagePanelではないのでしょうか?
PagePanel1の上に載っているものを印刷するということは,PagePanel1を印刷する
ということではないのですか?
Mr.XRAYさん
レスありがとうございます。
印刷したいパネルのハンドルを渡せばいいってことですよね。
わかりました、やってみます。
はい、印刷したいものはMr.XRAYさんのおっしゃる通りのものです。
今から実家の用事で帰省するのでもしレスしていただける方が
いらっしゃいましたら、こちらからのレスは火曜日以降になると思います。
それまで反応がなくても怒らないでください。
ちなみに私の環境は、
Windows XP(SP2)+Delphi2009です。
Mr.XRAYです.
Windows XP(SP3) + Delphi2009(UP3)で動作確認しました.
Mr.XRAYさん、レスありがとうございます。
流行にのってインフルエンザにかかってしまい、
ちょっと作業できる環境にありません。
体調がもどりしだい、再度レスしたいと思います。
ご協力いただいているのに申し訳ございません。
Mr.XRAYさんの方法で試しているのですが、
やはり印刷物にはなにも印刷されていません。
>>お助けを 2009/11/19(木) 04:38:59
>のコードをコピペして,
> PrintWindow(Self.Handle,DC,100); --> >PrintWindow(PagePanel.Handle,DC,1);
インターフェイス下にfunction PrintWindow〜を宣言するのと、
usesにPrintersを追加する以外になにかすることがあるんでしょうか?
Windows XP(SP3)にしました
>Mr.XRAYさんの方法で試しているのですが
方法もなんも,コードをそのままコピペしただけです.
他に何かコードを追加していませんか?
テストの時は,他の余分なコードを省いてやることです.
そうしないと,エラーや動作不良箇所を特定できません.
これは基本中の基本です.
テストに使用したコード,といってもPrintWindow(Self.Handle,DC,100);以外は
「お助けを 2009/11/19(木) 04:38:59」と同じです.
今日だけ以下にUpしておきます.試してみてください.
http://mrxray.on.coocan.jp/PrintWindowTest.zip
>今日だけ以下にUpしておきます.試してみてください.
>http://mrxray.on.coocan.jp/PrintWindowTest.zip
スミマセン.UPするときにウィルスチェック忘れました.
多分大丈夫だと思いますが.もし問題があれば...
Mr.XRAYさん、レスありがとうございます。
追加しているのはif文でPrintWindowが成功したら、適当な文字を
ShowMessageで表示させることだけです。
もちろん確認が終わったら元に戻します。
いただいたサンプルを実行しましたが、
印刷物にはなにも表示されません。
なにかほかに原因があるのでしょうか?
>印刷物にはなにも表示されません。
えっ!?
で,プリンタを変えてテストしてみました.
確かに印刷されません.実はテストは DocuWorks に出力していました.
う〜む.分かりません.
プリンタのスプールにはデータはくるのですが.一体?
Mr.XRAYさん、レスありがとうございます。
試しにpritersetupdialogでXPS documentに出力するようにしたのですが
こちらもダメでした。
なんかPrintWindow関数の挙動がよく分かりません.
こうなりゃ,まずビットマップにして,そのビットマップを印刷するしか
ないんじゃないでしょうか.先のレスでDさんの指摘したページのはそういう
意味だったのかはわかりませんが,
なんとなくスッキリはしませんが,目的が達せられれば良しということで.
// 動作確認
// Windows XP(SP3) + Delphi2009(UP3)
// プリンタEPSON PM-3300C + SplConv.exe(DEKO氏作)
//
procedure TForm1.Button3Click(Sender: TObject);
var
bmp : TBitmap;
DevPPIX : Integer;
DevPPIY : Integer;
ALeft : Integer;
ATop : Integer;
AWidth : Integer;
AHeight : Integer;
ARect : TRect;
begin
if not PrintDialog1.Execute then exit;
//PagePanelのビットマップを作成
bmp := TBitmap.Create;
GetWindowRect(PagePanel.Handle, ARect);
bmp.Width := ARect.Right - ARect.Left;
bmp.Height := ARect.Bottom - ARect.Top;
bmp.Canvas.Lock;
try
PrintWindow(PagePanel.Handle, bmp.Canvas.Handle,1);
finally
bmp.Canvas.Unlock;
end;
//作成したビットマップを印刷
Printer.Title := 'テスト印刷';
Printer.BeginDoc;
try
//プリンタの解像度等を取得
DevPPIX := GetDeviceCaps( Printer.Canvas.Handle, LOGPIXELSX );
DevPPIY := GetDeviceCaps( Printer.Canvas.Handle, LOGPIXELSY );
//余白等の設定(mm単位) 値は適当に...
ALeft := Trunc (20 * DevPPIX / 25.4);
ATop := Trunc (23 * DevPPIY / 25.4);
AWidth := Trunc (Printer.PageWidth - (20 * DevPPIX / 25.4));
AHeight := Trunc (AWidth * bmp.Height / bmp.Width);
ARect := Rect(ALeft, ATop, AWidth, AHeight);
Printer.Canvas.StretchDraw(ARect, bmp);
finally
Printer.EndDoc;
bmp.Free;
end;
end;
Mr.XRAYさん、レスありがとうございます。
私もビットマップして印刷する方法を試してたんですが、
いただいたコードの短いこと。
だらだら書いて失敗していたので困っていました。
印刷できたときは感動しました。
何度もレスしていただいてありがとうございました。
ツイート | ![]() |