checkboxとradiobuttonの印刷について


なべちゃん  2009-09-14 07:30:30  No: 35644

http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/samples/00727.html

上記のサイトのソースを使って、印刷するプログラムを
いままで作っていたアプリに追加したのですがcheckboxとradiobuttonは
印刷物に写りません。
縮尺を疑ってみたのですがPanelをどのようなサイズにしても写りませんでした。
どなたかどのような原因が考えられるか教えてください。
お願いします。


monaa  2009-09-15 00:18:32  No: 35645

リンク先のソースすら未確認ですが。
WindowsXPからそのような用途専用のAPIが実装されてます。
user32のPrintWindowってやつです。


なべちゃん  2009-09-15 23:33:00  No: 35646

お返事ありがとうございます。

調べてみたのですが、どのように実装していいのかわかりません。
ホント初心者ですいません。

なにかいいソースなどないでしょうか。
お願いします。


D  2009-09-16 07:09:44  No: 35647

>なにかいいソースなどないでしょうか。

http://delphi.about.com/od/delphitips2008/qt/print_window.htm


Mr.XRAY  2009-09-16 08:31:10  No: 35648

こんにちは.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とは描画仕様が異なりので,注意してください.


Mr.XRAY  2009-09-16 08:36:02  No: 35649

>(1) Delphiのヘルプで[フィルタ条件]を[Microsoft Windows Platform SDK]にする.

Delphi2007の場合は,右側のヘルプの種類を MSDN オンライン (英語) にしてください.
Delphi2009の場合は,そのままでOKです.
Delphi2010では確認していません.


お助けを  2009-11-19 13:38:59  No: 35650

こんにちは。
同様の印刷の問題があって検索したところここに行き着きました。
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のすぐ上)に宣言しています。

よろしくお願いします。


MSDNによると  2009-11-19 21:56:40  No: 35651

> 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に描画してからプリンタへ出力、という手順でないといけないのかも。


MSDNによると  2009-11-19 22:09:44  No: 35652

補足、PrintWindowは成功するとtrueを返します。
falseだったらエラーなので、GetLastErrorでエラーコードを調べてみてください。
成功しているのに紙に出なかったら、印刷領域から外れているかもしれないので
SetViewPortとかを外して試してみましょう。


お助けを  2009-11-19 23:00:01  No: 35653

すいません。
100にした理由は試しにやったもので、
一応Mr.XRAYさんのおっしゃっているように0と1をまず試しました。
ご指摘のことは今から試してみたいと思います。
早々のレスありがとうございます。


お助けを  2009-11-20 02:20:42  No: 35654

いろいろ試したのですが、まだできません。
ふらっと別サイトで見つけたソースを試したところパラメータが間違っていると
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をデザインに
加えるだけだと思うのどこで間違えているのか考えているのですがわかりません。
どなたか教えていただけませんでしょうか。
長文になりましたがよろしくお願いします。


確認  2009-11-20 02:31:26  No: 35655

> PrintWindow(wnd, bmp.Canvas.Handle, 0);
> ShowMessage(SysErrorMessage(GetLastError));
GetLastErrorは「最後に起こったエラーの番号」を返すもので、
直前の関数でエラーがあったかどうか教えてくれるものではないです。
PrintWindowの返り値はfalseだったんですか?

実際にエラーだとしたら、パラメータが間違っているということですから
wnd, bmp.Canvas.Handle に正しいハンドルが入っているか確認してください。


Mr.XRAY  2009-11-20 03:15:47  No: 35656

>下記がそのコードなのですが、間違いがあればお教えください。

ステハンの発言にはあまりレスしたくないのですが,名前が出ていたので.
まず,何を印刷したいのか明確にしてください.

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ではないのでしょうか?


Mr.XRAY  2009-11-20 03:21:45  No: 35657

なお,
PW_CLIENTONLY = $00000001;
のようです.


お助けを  2009-11-20 07:32:59  No: 35658

確認さん
レスありがとうございます。
trueが返ってきました。
ハンドルが入っているかの確認なのですが、
実行時に変数上にマウスをあてて、
Handle Property
Handle-System.Cardinal

hdcBlt Field パスファイル名
hdcBlt-Windows.HDC
となっています。
これで入ってると認識してよろしいのでしょうか。

Mr.XRAYさん
レスありがとうございます。
目的はPagePanelと同様にパネル上にあるコンポーネントを
印刷することです。
先ほどこのソースを書きこんだのはWindowPrintが実行できるところを
確認したかったからです。


確認  2009-11-20 08:04:59  No: 35659

> trueが返ってきました。
trueなら成功です。おめでとうございます。エラーコードを見る必要はありません。
ハンドルも型調べても意味ないので値を見てほしかったのですが
(通常は値が0だったら無効ハンドルです)関数は成功してるからたぶん問題ないです。

それで画面に表示されないんだったら原因は別でしょう。
ちなみに上でDさんの紹介しているサンプルでは
PrintWindowの前後でビットマップのCanvasをLock/Unlockしていますが
それは試しました?


お助けを  2009-11-20 08:51:02  No: 35660

確認さん
レスありがとうございます。
trueは返ってくるのですがパラメータが間違っていますと
エラーが返ってきます。
値は0ではありませんでした。

Lock/Unlockはこれから試してみます。


エラーじゃないよ  2009-11-20 09:26:57  No: 35661

本題とは関係ないけど、なんかまだわかってないみたいなので・・・
> trueは返ってくるのですがパラメータが間違っていますと
> エラーが返ってきます。
PrintWindowは成功してるんでしょ。
だったらGetLastErrorが返してるのは、それより前のどこかで何かの関数が失敗した時のエラーコードです。PrintWindowとは無関係。


エラーじゃないよさん  2009-11-20 09:39:45  No: 35662

すいません。てっきりPrintWindowでエラーだと思ってました。
PrintWindowより上にGetLastErrorを記入したら同様のエラーが出て、
ハンドルの代入の際のエラーでした。
ハンドルの内容を変更したらBitmapに描画出来ました。

あとはこれを印刷するようにプログラムを書きたいを思います。

みなさん、多くのレスありがとうございました。
ご協力ありがとうございました。


お助けを  2009-11-20 09:40:48  No: 35663

すいません。
上記のコメントはエラーじゃないよさんではなくお助けをのコメントです。


Mr.XRAY  2009-11-20 10:43:34  No: 35664

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を印刷する
ということではないのですか?


お助けを  2009-11-20 14:19:11  No: 35665

Mr.XRAYさん
レスありがとうございます。
印刷したいパネルのハンドルを渡せばいいってことですよね。
わかりました、やってみます。

はい、印刷したいものはMr.XRAYさんのおっしゃる通りのものです。

今から実家の用事で帰省するのでもしレスしていただける方が
いらっしゃいましたら、こちらからのレスは火曜日以降になると思います。
それまで反応がなくても怒らないでください。


お助けを  2009-11-20 14:36:33  No: 35666

ちなみに私の環境は、
Windows  XP(SP2)+Delphi2009です。


Mr.XRAY  2009-11-28 03:12:51  No: 35667

Mr.XRAYです.

Windows XP(SP3) + Delphi2009(UP3)で動作確認しました.


お助けを  2009-11-29 00:47:08  No: 35668

Mr.XRAYさん、レスありがとうございます。

流行にのってインフルエンザにかかってしまい、
ちょっと作業できる環境にありません。
体調がもどりしだい、再度レスしたいと思います。
ご協力いただいているのに申し訳ございません。


お助けを  2009-11-30 18:05:12  No: 35669

Mr.XRAYさんの方法で試しているのですが、
やはり印刷物にはなにも印刷されていません。

>>お助けを 2009/11/19(木) 04:38:59 

>のコードをコピペして,

>  PrintWindow(Self.Handle,DC,100);  -->   >PrintWindow(PagePanel.Handle,DC,1);

インターフェイス下にfunction PrintWindow〜を宣言するのと、
usesにPrintersを追加する以外になにかすることがあるんでしょうか?


お助けを  2009-11-30 18:09:00  No: 35670

Windows XP(SP3)にしました


Mr.XRAY  2009-11-30 18:45:12  No: 35671

>Mr.XRAYさんの方法で試しているのですが

方法もなんも,コードをそのままコピペしただけです.
他に何かコードを追加していませんか?

テストの時は,他の余分なコードを省いてやることです.
そうしないと,エラーや動作不良箇所を特定できません.
これは基本中の基本です.

テストに使用したコード,といってもPrintWindow(Self.Handle,DC,100);以外は
「お助けを 2009/11/19(木) 04:38:59」と同じです.
 
今日だけ以下にUpしておきます.試してみてください.
http://mrxray.on.coocan.jp/PrintWindowTest.zip


Mr.XRAY  2009-11-30 18:47:35  No: 35672

>今日だけ以下にUpしておきます.試してみてください.
>http://mrxray.on.coocan.jp/PrintWindowTest.zip

スミマセン.UPするときにウィルスチェック忘れました.
多分大丈夫だと思いますが.もし問題があれば...


お助けを  2009-11-30 19:07:23  No: 35673

Mr.XRAYさん、レスありがとうございます。

追加しているのはif文でPrintWindowが成功したら、適当な文字を
ShowMessageで表示させることだけです。
もちろん確認が終わったら元に戻します。

いただいたサンプルを実行しましたが、
印刷物にはなにも表示されません。

なにかほかに原因があるのでしょうか?


Mr.XRAY  2009-11-30 20:13:25  No: 35674

>印刷物にはなにも表示されません。

えっ!?
で,プリンタを変えてテストしてみました.
確かに印刷されません.実はテストは DocuWorks に出力していました.
う〜む.分かりません.
プリンタのスプールにはデータはくるのですが.一体?


お助けを  2009-11-30 20:18:38  No: 35675

Mr.XRAYさん、レスありがとうございます。

試しにpritersetupdialogでXPS documentに出力するようにしたのですが
こちらもダメでした。


Mr.XRAY  2009-12-01 17:39:16  No: 35676

なんか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;


お助けを  2009-12-02 00:56:22  No: 35677

Mr.XRAYさん、レスありがとうございます。

私もビットマップして印刷する方法を試してたんですが、
いただいたコードの短いこと。
だらだら書いて失敗していたので困っていました。

印刷できたときは感動しました。
何度もレスしていただいてありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加