喫茶XRAYトップページ

[スレッド全体
]

[9521] プリンタドライバの情報をDEVMODE構造体から取得返信 削除
2016/1/8 (金) 15:38:29 taki
マスター お世話になります。
サンプルプログラム集
「011_プリンタドライバの情報をDEVMODE構造体から取得」での質問です。

やりたい事はPrinterSetupDialogを表示して「用紙サイズ」(種類)を変更したり
「印刷の向き」を変更することで変更された用紙の大きさ(縦・横の長さ)を
得て印刷データの行数を決めたいのです。

dmOrientation,dmPaperSize,dmPaperLength,dmPaperWidthの情報がそれらに
該当するのですが、
サンプルに同梱されている「DEVMODE_Structure.exe」で試したところ

A4縦 → portrait,A4,2970,2100(初期値)
A4横 → landscape,A4,2970,2100
再度 A4横 → landscape,A4,2970,2100
A4縦 → portrait,A4,2970,2100
となります。縦と横の長さが入れ替わるかなと予想したのですが、
そうではないようです。

次に用紙のサイズ(種類)を変更したところ
B5縦 → portrait,B5,2970,2100 (A4用紙の長さが残る?)
再度 B5縦 → portrait,B5,2570,1820 (B5に直った)
となりました。

A4縦 → portrait,A4,2570,1820 (B5用紙の長さが残る?)
再度 A4縦 → portrait,A4,2970,2100 (A4に直った)

どうやらdmPaperLength,dmPaperWidthの情報は直ちには反映されない
ようなのですが、これは仕様?なのでしょうか。
それとも私のPCもしくはプリンタードライバーだけの現象なのでしょうか。

環境 Windows7 Pro,Delphi XE4 Starter,Canon MG5430


[9534] Re:プリンタドライバの情報をDEVMODE構造体から取得返信 削除
2016/1/11 (月) 09:29:48 Mr.XRAY
> やりたい事はPrinterSetupDialogを表示して「用紙サイズ」(種類)を変更したり
> 「印刷の向き」を変更することで変更された用紙の大きさ(縦・横の長さ)を
> 得て印刷データの行数を決めたいのです。


今読み直してみたんですが,
実は [011] のサンプルは,DEVMODE 構造体から取得可能な値をリストするものです.

dmPaperLength, dmPaperWidth はユーザ定義サイズの値です.
dmPaperLength は,縦向きの時の用紙の長さ,
dmPaperWidth は,縦向きの時の用紙の幅です.

で,印刷の時の用紙のサイズの取得は,

[012_プリンタの解像度と用紙サイズ等の取得]
http://mrxray.on.coocan.jp/Delphi/plSamples/012_PrintResolution.htm

を参考にしてくださいませ.
意味が違っていたらゴメンなさいです.


[9535] Re2:プリンタドライバの情報をDEVMODE構造体から取得返信 削除
2016/1/11 (月) 19:19:50 taki
▼ Mr.XRAYさん
 
> 今読み直してみたんですが,
> 実は [011] のサンプルは,DEVMODE 構造体から取得可能な値をリストするものです.
>


> で,印刷の時の用紙のサイズの取得は,
>
> [012_プリンタの解像度と用紙サイズ等の取得]
> http://mrxray.on.coocan.jp/Delphi/plSamples/012_PrintResolution.htm
>
> を参考にしてくださいませ.
> 意味が違っていたらゴメンなさいです.


マスター 誠にすみません。
マスターのご指摘のように
GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);で
常に正しい情報を得ることができました。

それと、私がしくじった原因も報告します。

以下のコードで試しました。

uses Printers;

procedure TForm1.GetNagasa;
var
  TempInt,YDPI: Integer;
  TempDouble  : Double;
begin
  YDPI  := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
  TempInt    := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);
  TempDouble := TempInt * 25.4 / YDPI;
  label2.Caption := Format('%8.1f [mm]', [TempDouble]);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
//  Printer.PrinterIndex := -1;  // ←間違った使い方1
  if PrinterSetupDialog1.Execute then begin
  // OKで閉じるまでに用紙の種類を変更する
    GetNagasa;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//  Printer.PrinterIndex := -1;  // ←間違った使い方2
  GetNagasa;
end;

確実にデフォルトのプリンターを使おうとしてPrinterIndex := -1;を
コーディングしたのが間違いでした。

色々試した結果、PrinterIndex := -1;とすると、デフォルトの
プリンターが選ばれるだけでなく、デフォルトの状態も設定されるようです。
つまり私の環境の場合、
プリンター名 「Canon MG5400 series Printer」
用紙サイズ 「A4」
印刷の向き 「縦」
に戻ってしまうようです。

それぞれの間違った使い方のコードが有効な状態で試すと
Button1をClickすると、PrinterSetupDialogを開くたびにA4・縦になる。
しかし、用紙の縦の長さは変化する。(変更した正しい長さになる。)
Button2をClickすると、常にA4用紙の縦の長さ297mmに戻ってしまう。

それぞれのコードをコメントアウトすると
Button1をClickすると、PrinterSetupDialogは以前の状態が保持されている。
変更した用紙の紙の長さも正常に表示される。
Button2をClickしても、用紙の紙の長さは変わらない。

出入り禁止にはしないでください。m(__)m


[9536] Re3:プリンタドライバの情報をDEVMODE構造体から取得返信 削除
2016/1/11 (月) 20:50:28 Mr.XRAY
▼ takiさん

> 色々試した結果、PrinterIndex := -1;とすると、デフォルトの
> プリンターが選ばれるだけでなく、デフォルトの状態も設定されるようです。


今後使用する状況があるかどうか分かりせんが,以下のようになっています.
これは,実は,問題になることがあるんです.
今回のこととは直接関係ありませんが,プリンタ関係を扱う場合の参考として.

  //現在のプリンタを指定したプリンタにする
  //-1 を代入した場合は,-1 になるのではなく,デフォルトのプリンタの番号
  //が代入される
  Printer.PrinterIndex := プリンタ番号(整数値);

  //ここで取得するADeviceModeには,変更前のプリンタの情報が格納されている
  //その他の値は現在(変更後)のプリンタの情報となっている
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
  //ADeviceMode初期化
  Printer.SetPrinter(ADevice, ADriver, APort, 0);
  //ADeviceModeが新しいプリンタドライバの値(デフォルトのプロパティ値)となる
  Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);

プリンタを変更して,DEVMODE 構造体で設定する場合は,上のコードの後に書きます.
上の 3 行を実行しないと,正常に設定されないことがあります.
(昔は,この手の質問がいっぱいあったんですよね --- 遠い目)
 

> 出入り禁止にはしないでください。m(__)m

え ? 何か悪いことしました ??


[9537] Re4:プリンタドライバの情報をDEVMODE構造体から取得返信 削除
2016/1/12 (火) 10:56:59 taki
▼ Mr.XRAYさん
 
> (昔は,この手の質問がいっぱいあったんですよね --- 遠い目)

マスター もう少しお付き合いください。

プリンタ関係のサンプルプログラムの記事を読み直してみて、分かったことも
多くあるのですが、色々と混乱して分からなくなってしまいました。

具体的な例にしての質問です。

パソコンに2台のプリンタが接続されています。
インクジェットと連続帳票専用プリンタです。

「通常使うプリンタ」(デフォルトのプリンタ) は、OSに登録(定義)されている
プリンタで、色々なアプリ(メモ帳、Word、Execl等)で印刷する時に自動で
選択されているプリンタですね。
インクジェットプリンタでプリンタ番号を2としてください。
プロパティはA4用紙・縦です。

連続帳票印刷アプリは連続帳票専用のプリンタを使います。
専用プリンタのプリンタ番号を3としてください。プロパティは連続用紙(かな?)
連続帳票印刷アプリを起動直後は、OSの「通常使うプリンタ」のままではダメ
(無駄紙大量発生)なので、帳票印刷する前に使用するプリンタの変更が
必要になります。

そのプリンタの変更を人間ができる場合は、「PrinterSetupDialog」でプリンタを
連続帳票専用プリンタに変更すれば、プロパティも連続用紙に変わってくれる?
(多分)ので、後は印刷すれば良い事になります。

でも、通常は「無駄紙大量発生」を防ぐため、使用するプリンタの変更をアプリの
コードで行いますよね。

そのコードが

Printer.PrinterIndex := 3;
// または
//Printer.PrinterIndex := Printer.Printers.indexof('OKI XXXX');
// OKI XXXX は帳票プリンタの名前(仮称)

Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
Printer.SetPrinter(ADevice, ADriver, APort, 0);
Printer.GetPrinter(ADevice, ADriver, APort, ADeviceMode);
// これで連続帳票専用プリンタ(仮称 OKI XXXX)に変更できたのでしょうか?
この時に、プロパティも連続用紙に変わっているのでしょうか?

無事に連続帳票の印刷が済んでアプリを終了したら、「通常使うプリンタ」は
インクジェットに戻っているのでしょうか?(上記コードはアプリ内だけ有効?)

自分で試せばいいのですが、プリンタが1台しかないもので…。


[9538] 通常使用するプリンタ返信 削除
2016/1/12 (火) 11:55:14 Mr.XRAY
▼ takiさん

> マスター もう少しお付き合いください。

やだ !! ハハハッ
 
> // これで連続帳票専用プリンタ(仮称 OKI XXXX)に変更できたのでしょうか?
> この時に、プロパティも連続用紙に変わっているのでしょうか?


なりません.プリンタの設定ダイアログで設定した場合はなります.
上のコードのように,DEVMODE 構造で設定する場合は,設定のコードが必要です.

> 無事に連続帳票の印刷が済んでアプリを終了したら、「通常使うプリンタ」は
> インクジェットに戻っているのでしょうか?(上記コードはアプリ内だけ有効?)


戻っています.
Delphi の Printer オブジェクトで操作した内容は,そのアプリだけで
有効です.ただし,Windows 10 では様子がかわったようです.

[ Windows10 通常使うプリンターが・・・]
http://mrxray.on.coocan.jp/bbs/DelphiBBS/mrxray_delphifan_coffe.cgi?tree=s9486#9486
 
> 自分で試せばいいのですが、プリンタが1台しかないもので…。

プリンタドライバをインストールすればテストできます.
しかし,物理的にプリンタが接続されていません.そこで「一時停止」にして
テストします.
結果は,印刷スプールにあります.
これは,DEKO さんとこにあるやつを利用すると確認できます.
ん ? 何というやつだったかな ? 調べてみます.

# 当サイトにもサンプルを掲載していたのですが,
# 削除しました.わざわざ自分で作成する必要はないと思って... (^^;

また,富士ゼロックス社の DocuWorks(ドキュワークス)も便利です.
DocuWorks はここのお客さんに教わったものです.



[9540] プリンタ,印刷の設定返信 削除
2016/1/12 (火) 12:10:25 Mr.XRAY
> なりません.プリンタの設定ダイアログで設定した場合はなります.
> 上のコードのように,DEVMODE 構造で設定する場合は,設定のコードが必要です.


プリンタの設定ダイアログ,あるいは印刷ダイアログを表示して設定させない,
コードで,自動で設定したい場合に,DEVMODE 構造体で設定する,
ということになります.

どちらの方法にするかは,開発するアプリによります.
ダイアログを表示すると,使用者によっては,余計な操作をしてしまう
可能性があります.DEVMODE 構造体で設定すれば確実ということになります.
ただし,コーディングは面倒ということになります.


[9543] Re:プリンタ,印刷の設定返信 削除
2016/1/12 (火) 14:15:03 taki
▼ Mr.XRAYさん
> > なりません.プリンタの設定ダイアログで設定した場合はなります.
> > 上のコードのように,DEVMODE 構造で設定する場合は,設定のコードが必要です.
>
> プリンタの設定ダイアログ,あるいは印刷ダイアログを表示して設定させない,
> コードで,自動で設定したい場合に,DEVMODE 構造体で設定する,
> ということになります.
>
> どちらの方法にするかは,開発するアプリによります.
> ダイアログを表示すると,使用者によっては,余計な操作をしてしまう
> 可能性があります.DEVMODE 構造体で設定すれば確実ということになります.
> ただし,コーディングは面倒ということになります.


なるほど。
この3行は呪文みたいなものですか。このコードに続いてプロパティを変更する
コードを書く必要があるのですね。
「013_プリンタのプロパティ設定」の「03_コードでプロパティを設定」のように。

Printer.SetPrinter(ADevice, ADriver, APort, 0);でプロパティの内容を初期化しないと
プリンターのプロパティの内容は個々のプリンターで違うので、DocumentProperties関数で
うまく書き込めないのでしょうね。
確かに面倒です。
そういう意味ではPrinterSetupDialogはすごいですね。プリンターの一覧作成からプロパティの
獲得、変更までやってくれるのだから。


スプールファイル変換ツール「splconv」は面白そうですね。早速ダウンロードしました。
readme.txtにメタファイルで出力とあるのでその辺は…。

富士ゼロックス社の DocuWorks(ドキュワークス)は以前インストールしていたかもしれません。
認知症が進んでるみたいで、物忘れが激しい。


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