喫茶XRAYトップページ

[▲前のスレッド]

[3460] ワード・エクセル操作フォームの印刷機能返信 削除
2010/6/16 (水) 10:38:12 Mr.XRAY
エクセル(Microsoft Excel)とワード(Microsoft Word)は,
プリンタの情報を内部で独自に持っています.
そのため,DelphiのTPrinterオブジェクトでは制御できません.
(DEVMODE構造体を設定しても,エクセル内部の設定が使用されます)

エクセルの場合,詳細なプロパティを設定して印刷したい場合は,
エクセルのダイアログを表示して印刷してください.
参考コードは,以下にあります.

[エクセルの印刷ダイアログ]
http://mrxray.on.coocan.jp/Delphi/plExcelEx/T_PrintDialog.htm

//=============================================================================
//  [印刷]ボタンクリックでエクセルの印刷ダイアログを表示して印刷する方法
//
//  継承フォームの[印刷]ボタンクリックイベントで
//  (1)inherited; を無効にする
//     (継承元のエクセル操作フォームの印刷コードを無効にする)
//  (2)印刷ダイアログを表示するコードを書く
//
//  エクセルの印刷ダイアログ表示のコードは以下を参照
//  [エクセルの印刷ダイアログ]
//  http://mrxray.on.coocan.jp/Delphi/plExcelEx/T_PrintDialog.htm
//=============================================================================
procedure TplExcelFormEx2.btnPrintClick(Sender: TObject);
begin
//  inherited;

  エクセルの印刷ダイアログ表示のコード,あるいは印刷コードを書く
end;


あるいは,独自の印刷ダイアログを作成するの1つの方法かも知れません
VBAのヘルプを[印刷]で調べるといろいろでてきます.
例えば,印刷対象となっているシートを,倍率を指定して印刷するには,

  xlfExcelSheet.PageSetup.Zoom := 200; //200%の意味
 
でできます.


[3461] Re:ワード・エクセル操作フォームの印刷機能返信 削除
2010/6/16 (水) 10:50:01 Mr.XRAY
オンライン・マニュアルのメソッドの記事には書いていませんが,
当然,元のエクセルや,ワードオブジェクトのプロパティやメソッドも
使用できます.

エクセルのシートの印刷であれば,

xlfExcelSheet.PrintOut;

[3462] [印刷プレビュー]ボタン返信 削除
2010/6/16 (水) 15:44:35 Mr.XRAY
> エクセルの場合,詳細なプロパティを設定して印刷したい場合は,
> エクセルのダイアログを表示して印刷してください.


エクセルの印刷ダイアログを表示すると.
[印刷プレビュー]ボタンが表示されます.
エクセル操作フォームExでは,印刷プレビューを実行すると,
その後,本体の表示がおかしくなります.
この回避方法は,現在のところ残念ながらありません.

そこで,[印刷プレビュー]のボタンを使用不可にすることが考えられますが,
これも難しいです.
方法としては,

(1) 何らかの方法で,[印刷]ダイアログのハンドルを取得
(2) 何らかの方法で[印刷プレビュー]ボタンのID値を取得して
  そのハンドル値を取得し,以下のように使用不可に設定する
    http://mrxray.on.coocan.jp/Delphi/plSamples/016_PrinterSetupDialog.htm#01

(1)は,フック(WH_CALLWNDPROCRET)でないとできないかも知れません.

[3463] Re:[印刷プレビュー]ボタン返信 削除
2010/6/16 (水) 16:11:13 Mr.XRAY
> (1)は,フック(WH_CALLWNDPROCRET)でないとできないかも知れません.

エクセルやワードには,Delphiのように,各種ダイアログ表示時,
あるいは,閉じるときのイベントはありませんので.


[3464] エクセル操作フォームExの仕様の限界返信 削除
2010/6/16 (水) 18:32:55 Mr.XRAY
もし,Delphiの印刷ダイアログ以外のプロパティを設定するのでいれば,
自作の印刷ダイアログを作成し,その設定をエクセルのPrintメソッド
で設定する方がいいかも知れません.

当然,この場合もプリンタ固有の設定はできませんが.
エクセルまたはワード操作フォームExの仕様と解釈してください.

いや,もっと詳細な設定がしたい!!
のであれば,エクセル操作フォームExを使用しないで,
エクセルそのものを,Delphiのコードで制御するしかないでしょう.


[3465] Re:[印刷プレビュー]ボタン返信 削除
2010/6/16 (水) 23:38:21 Mr.XRAY
> (1)は,フック(WH_CALLWNDPROCRET)でないとできないかも知れません.

えっと,WndProcで取得できそうです.
テストしてみました.
続きは明日以降ということで.
動作確認環境は, Windows XP(SP3) + Delphi2010

function GetWindowTextStr(hWindow: HWND): String;
var
    Buffer : Array[0..MAX_PATH-1] of char;
begin
    Result := '';
    if (GetWindowText(hWindow, Buffer, MAX_PATH)<>0) then begin
      Result := Buffer;
    end;
end;

procedure TplExcelFormEx2.WndProc(var Message: TMessage);
var
  ACaption : String;
begin
  inherited;

  if Message.Msg = WM_ACTIVATE then begin
    ACaption := GetWindowTextStr(Message.lParam);
    Caption  := ACaption;
  end;
end;



[3466] Re2:[印刷プレビュー]ボタン返信 削除
2010/6/17 (木) 14:37:57 Mr.XRAY
>続きは明日以降ということで.

報告です.
結果的に[印刷プレビュー]ボタンは無効にも非表示もできませんでした.
ハンドルまたはIDの値が取得できません(添付図の上図参照)

ハンドルあるいはID値が取得できれば,例えば以下のように値をセットしたり
できます.
(結果は添付図の下の図参照)

procedure TplExcelFormEx2.WndProc(var Message: TMessage);
var
  DialogWnd   : HWND;
  S1,S2,S3    : String;
  Id1,Id2,Id3 : Integer;
begin
  inherited;

  if Message.Msg = WM_ACTIVATE then begin
    DialogWnd := Message.LParam;
    if GetWindowTextStr(DialogWnd) <> '印刷' then exit;

    Id1:=33;  //Excel97,2000印刷開始頁コントロールID
    Id2:=34;  //Excel97,2000印刷終了コントロールID
    Id3:=40;  //Excel97,2000印刷部数コントロールID

    S1 :=IntToStr(1);  //印刷開始頁
    S2 :=IntToStr(10); //印刷終了頁
    S3 :=IntToStr(5);  //印刷部数

    //印刷開始頁等に文字列をセット}
    SendDlgItemMessage(DialogWnd, Id1, WM_SETTEXT, 0, LongInt(PChar(S1)));
    SendDlgItemMessage(DialogWnd, Id2, WM_SETTEXT, 0, LongInt(PChar(S2)));
    SendDlgItemMessage(DialogWnd, Id3, WM_SETTEXT, 0, LongInt(PChar(S3)));
  end;
end;


[3474] Re3:[印刷プレビュー]ボタン返信 削除
2010/6/18 (金) 11:03:10 Mr.XRAY
> ハンドルあるいはID値が取得できれば,例えば以下のように値をセットしたり
> できます.


えっと,わさわざこんなことしなくても,エクセルのオブジェクトの
プロパティで設定できますので.
ハンドルが取得できれば,こんなことも可能だという例ですので.
念のため.


[3467] まとめ返信 削除
2010/6/17 (木) 14:53:45 Mr.XRAY
拙作コンポ類をご利用いただき,ありがとうございます.

まとめです.
結論として,エクセルの[印刷]ダイアログは使用しない方がよい.

もし,印刷の際にエクセル操作フォームExの印刷ダイアログで設定可能
以外の値を設定したい場合は,

(1) サンプルプログラム集の[016]のコード類を参考に
    その設定用のコントロールを追加し,
    設定した値をエクセルのプロパティにセットする
 
(2) 専用の新しい印刷設定用のダイアログを作成し,
    そこで設定した値をエクセルのPrintメソッドの引数等に与える
 
(3) エクセル操作フォームExの使用は止めて,独自にエクセルを操作する
    コードを作成する
 
ということになるでしょうか.

エクセル操作フォームExでの[印刷プレビュー]の使用は基本的に
無理があります.
また,エラー発生時の時のいろいろな問題は利用者が対応してください.
例えば,DLLを動的にロードしていませんので,あらかじめ存在を確認
するとかですね.

エクセルのオブジェクトの操作についは,サンプルプログラム集にも
ありますので,参考にしてください.
添付のExcelKill.exeを使用しなくて,オブジェクトを取得してKillする
こともできます.

エクセルのダイアログ等が,Delphiのダイアログのような仕様であれば,
問題ないのですが,現状ではいたし方ありません.

以上です.よろしくお願い致します.


[3468] 姑息な方法返信 削除
2010/6/17 (木) 15:53:09 Mr.XRAY
> (1) サンプルプログラム集の[016]のコード類を参考に

を参考に非常に「姑息」な方法を試してみました.
[印刷プレビュー]ボタンの上にTPanelをかぶせてしまう方法です.
ただし,他のウィンドウを前面にして,また戻ると表示されていまいます.

//=============================================================================
//  継承フォームの[印刷]ボタン
//  エクセルの[印刷]ダイアログを表示する
//=============================================================================
procedure TplExcelFormEx2.btnPrintClick(Sender: TObject);
var
    pType    : OleVariant;
    pID      : OleVariant;
    pTag     : OleVariant;
    pVisible : OleVariant;
begin
    MyPanel := TPanel.Create(Self);
    try
      pType    := EmptyParam;
      pID      := 4;
      pTag     := EmptyParam;
      pVisible := EmptyParam;

      try
        xlfExcelApp.CommandBars.FindControl(pType,pID,pTag,pVisible).Execute;
      except
      end;
    finally
      FreeAndNil(MyPanel);
    end;
end;

//=============================================================================
//  このフォームのWndProcメソッド
//  エクセルの[印刷]ダイアログを表示したら,表示前に作成したMyPanel(TPanel)を
//  [印刷プレビュー]ボタンの上に配置して使用不可にする姑息な方法
//=============================================================================
procedure TplExcelFormEx2.WndProc(var Message: TMessage);

  //---------------------------------------------------------------------------
  //  ウィンドウハンドルからウィンドウのタイトルを取得
  //---------------------------------------------------------------------------
  function GetWindowTextStr(hWindow: HWND): String;
  var
      Buffer : Array[0..MAX_PATH-1] of char;
  begin
      Result := '';
      if (GetWindowText(hWindow, Buffer, MAX_PATH)<>0) then begin
        Result := Buffer;
      end;
  end;

//-----------------------------------------------------------------------------
var
  DialogWnd : HWND;
  ARect     : TRect;
  APos      : TPoint;
begin
  inherited;

  if Message.Msg = WM_ACTIVATE then begin
    DialogWnd := Message.LParam;
    if GetWindowTextStr(DialogWnd) <> '印刷' then exit;

    GetWindowRect(DialogWnd, ARect);
    APos.x := ARect.Left;
    APos.y := ARect.Bottom;

    MyPanel.Width        := 150;
    MyPanel.Height       := 30;
    MyPanel.BevelOuter   := bvNone;
    MyPanel.ParentWindow := DialogWnd;

    APos := MyPanel.ScreenToClient(APos);

    MyPanel.Left := APos.X;
    MyPanel.ToP  := APos.Y - MyPanel.Height;
  end;
end;

プロジェクトのダウンロード
http://mrxray.on.coocan.jp/Delphi/zipothers/DD_ExcelPrintDialog_NonPreviewButton.zip


[3469] Re:姑息な方法 修正版返信 削除
2010/6/17 (木) 20:15:46 Mr.XRAY
修正しました.
こちらの方がいいようです.
ダウンロードのプロジェクトも更新しました.
動作確認環境は,Windows XP(SP3) + Delphi 2010 + Excel2000 です.
他の環境では全くテストしていません.

procedure TplExcelFormEx2.WndProc(var Message: TMessage);
var
  DialogWnd : HWND;
  ARect     : TRect;
begin
  inherited;

  if Message.Msg = WM_ACTIVATE then begin
    DialogWnd := FindWindow(nil, '印刷');
    if DialogWnd = 0 then exit;

    Windows.GetClientRect(DialogWnd, ARect); //ClientRectの方がいいですね (^^;

    MyPanel.Width        := 150;
    MyPanel.Height       := 30;
    MyPanel.BevelOuter   := bvNone;
    MyPanel.ParentWindow := DialogWnd;

    MyPanel.Left := 0;
    MyPanel.ToP  := (ARect.Bottom - ARect.Top) - MyPanel.Height;
    MyPanel.Update; //Updateする
  end;
end;

[3470] Re2:姑息な方法 修正版返信 削除
2010/6/17 (木) 20:25:52 Mr.XRAY
質問メールを下さった方へ.
情報の共有の意味でこちらにレスしました.

メールの返信はしませんので,このスレッドを参考にしてください.
これで問題があれば,このスレッドに書き込みしてください.
どうしてもここに書き込みしにくい場合は,メールをください.

メールに関しては,以下の注意をお読みください.
事情により設定ができない場合は,その旨,メールに書いていただける
と幸いです.

では,がんばってください.
健闘を祈っています.

http://mrxray.on.coocan.jp/Delphi/Info/OtherInfo19_OutlookMail.htm

[3472] Re3:姑息な方法 修正版返信 削除
2010/6/18 (金) 09:38:27 Bigstone 〔HomePage
▼ Mr.XRAYさん

今回の質問に対し、早々対応して頂き誠に有難うございました。
おかげさまで解決する事ができました。
このサイトもコンポーネントもXRAYさんの発言も、毎日見させて
させて頂いています。Delphi で開発するにあたって非常に参考に
なり助かってます。このような掲示板に発言するのは初めてで
どうしょうか迷っていましたがただお礼を言いたくて書きました。

これからもどうぞよろしくお願いします。

[3473] Re4:姑息な方法 修正版返信 削除
2010/6/18 (金) 10:54:25 Mr.XRAY
▼ Bigstoneさん,こんにちは.

こちらにおいでいただいて,申し訳ありません.
質問の内容がエクセル操作フォームExの改良にとって,
大切な内容でしたので,他の方にも内容を知っていただきたい,
というのが趣旨です.ご理解ください.

おかげで,他のバグもついでに見つかりました.
修正はいつになるかわかりませんが(笑)

不特定多数の方が見るような,掲示板に書き込みをするというのは,
だれでも躊躇(ちゅうちょ)すると思います.
私も,パソコン通信時代,Niftyの会議室に初めて発言する時は,
「これでいいのかな.間違っていないかな」と,[送信]ボタンを
クリックするまで,結構... でした.今となっては懐かしいですが.

# また一人,こちらに引き込んでしまいました.
# メールで切り出すのもタイミングが中々...


[3471] Windows7 + Excel2007での修正返信 削除
2010/6/17 (木) 23:28:34 Mr.XRAY
> 他の環境では全くテストしていません.

Windows 7 U64 + Delphi 2010 + Excel2007でテストしてみました.
以下の修正が必要です.

修正前
>     MyPanel.Update; //Updateする

修正後
    //Window 7 + Excel2007ではShowWindowが必要(Updateは不要)
    ShowWindow(DialogWnd, SW_SHOWNORMAL);
    //Windows XP + Excel2000ではUpdaeが必要(ShowWindowは不要)
    MyPanel.Update;


[3476] Re2:姑息な方法 修正版返信 削除
2010/6/18 (金) 19:17:04 Mr.XRAY
>     DialogWnd := FindWindow(nil, '印刷');
>     if DialogWnd = 0 then exit;


これダメですね.Windows 7 + Excel2007でやったら,
エクセル操作フォームExの[印刷]ボタンを検出してしまいました.
前の

    DialogWnd := Message.LParam;
    if GetWindowTextStr(DialogWnd) <> '印刷' then exit;

にしたらOKでした.当然か!?
単に,タイトルが[印刷]のウィンドウを探すのではなく,
アクティブになったウィンドウの[印刷]のウィンドウを探すのだから?


[3475] エクセル操作フォームExの印刷プレビュー返信 削除
2010/6/18 (金) 11:15:31 Mr.XRAY
ついてでですので,表題の件について.
エクセル操作フォームExとワード操作フォームExで印刷プレビューを
実行すると,動作不良となります.
これは,現在のところ,いや,今後も修正するつもりはありません.

特にエクセルの印刷プレビューはあてになりません.
ネットで検索すると,印刷プレビューではこうこう表示されているのに
印刷すると... という質問をよく見かけます.
目安には利用できますが.

Excel2007には,[ページレイアウト表示]というが追加されています.
これは結構正確なようです.

http://mrxray.on.coocan.jp/Delphi/plExcelEx/T_PageLayout.htm

ちなみに,Excel2010では,[印刷プレビュー]ボタンはなくなったそうです.


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82