Delphi2007とQuickReportで印刷してるんですが不可解な現象が発生します。
OSはWindowsXPです。
QRDBTextに文字列を印字するのですが文字数が多いと自動的に枠内で収まるようにフォントサイズを小さくしていくルーチンを作りました。
//==========================================================================
// 印刷文字の大きさ調整
// I: Sender オブジェクト
// dat 印字内容
// dfsize デフォルトフォントサイズ
// maxwidth 最大テキスト幅
//==========================================================================
procedure QRTextAdjust(Sender:TObject; dat:string; dfsize:word; maxwidth:integer);
TQRDBText(Sender).Font.Size:=dfsize;
TQRDBText(Sender).Caption:=dat;
while (TQRDBText(Sender).Width > maxwidth) do begin
TQRDBText(Sender).Font.Size:=TQRDBText(Sender).Font.Size - 1;
end;
end;
で、プレビューだと長い文字列くるとwhile分のTQRDBText(Sender).Widthがフォントサイズマイナス1する毎に小さくなってちょうどいい大きさで印字されます。
ところが実際の印刷だとフォントサイズマイナス1していってもTQRDBText(Sender).Widthの値が最初の値から全く変わらずに無限ループに入ります。
無限ループはサイズ6以下になったらbreakとか回避は出来るのですが、それだとちょうどいいサイズに印刷の時だけなりません。
QuickReportって昔に比べてバグが多いですがこれもバグなのでしょうか?
QRTextAdjustはDetailBeforePrintから呼んでいるのでしょうか?
QuickReportは以前よりバグが増えたと感じていません。むしろ便利になりました。
AutoSize = True になっていない?
かずさん、レスありがとうございます。
QRDBTextPrintから呼んでます。
DetailBeforePrintや他のイベントもいろいろ試したのですがうまくいったのはQRDBTextPrintだけでした。プレビューだけですが・・・
Delphi7くらいからのQuickReportではQRMemoのWordWrapをTrueにしても長い文が自動で改行されずに1行になってしまいます。
ここで聞いたらバグだと教えてもらいました。
他にもDelphi3のQuickReportから比べたら2バイト文字の処理がうまくいっていないバグがあると聞きました。
ofZさん、レスありがとうございます。
AutoSizeはTrueだったのでFalseにしてみました。
そしたら今度はプレビューまでダメになってしまいました。印刷もダメです。
うーむ、不思議です。
失礼しました。
AutoSize = True に、なっていないのではないかと勘違いしていました。
印刷中のフォントサイズ変更に反応しないバグなんだろうか?
TLabelを一個用意して(印刷対象にならないのでどこでも貼り付けOKのはず)、
それでサイズの計算してみたらどうでしょうか?
サイズの計算だけなら、大丈夫のような気がする未検証レス
ジュウザさん
>不可解な現象が発生します。
>プレビューだと〜ちょうどいい大きさで印字されます。
>実際の印刷だと〜最初の値から全く変わらずに無限ループに入ります。
ええと、プレビューはともかく、実際の印刷については不可解ではない
ような気がします。
ofZさん
>印刷中のフォントサイズ変更に反応しないバグなんだろうか?
正確には「印刷直前にwidthを取得、これを変更してTQRDBTextを再生成」
ではないでしょうか?
プレビューであれば(画面上で何度でも再描画できるんじゃないかな?
人間の目にその過程が見えるかどうかは不明ですが)、
1.Text生成→2.width取得→3.Phontsize変更→4.Text再生成(?)
→2.に戻る(以下ループ)
以上をやってから、 .Preview できると思います。
でも、プリンタに物理的に印刷出力する直前に上記1.をやるわけですよね。
で、まさに .Print する瞬間に上記2.ができたとして、そこで印刷出力
する動作にWaitをかけ、ループしてから印刷出力を解放するという処理が
必要だと思います。
そんな制御ができるのでしょうか?
文字列の数は、予め取得する事ができますよね。
でも、TQRDBText(Sender).Width は、生成されて初めて取得できる値では
ないでしょうか?
私なら
A.ダミーのQuickReportにTQRDBTextを用意し、そちらで上記ループで .Width
を計算し、結果を実QuickReportに代入する。
B.Preview画面まではジュウザさんのコードで実現できているから、Preview
したQuickReportを一旦 .qrp形式Fileに保存してから、この .qrpを呼び出して、
Print する。
C.等幅フォントを使用して、文字数から最適なフォントサイズを割り出す。
のいずれかを考えます。
A.は想像のレベルです。
B.は過去に似たようなことをやったので多分できるはず。(今Delphi環境が
ないので) QuickReportの保存〜呼び出しについては、必要なら実働
ソースを貼りますよ。
C.が一番現実的かなあ?
beagleさん
「再生成」やら「生成」の単語の意味が、ちょっと理解しかねますが・・・
TQRDBText には、印刷直前(印刷はもちろんプレビュー時も)文字列を描画する
直前に発生するOnPrintイベントがあります。
このとき、メソッドの第二引数に 「var Text: String」があり、印刷(描画)
すべき文字列を取得できます。
このとき、好きなだけ幅調整、文字列変更できます。
使用経験があるのでしたら、ご存知のハズ。
ジュウザさんが最初に提示したメソッド(QRTextAdjust)は、おそらくこの
OnPrintで実行していると思ったわけですが、QRDBTextは、AutoSize=trueで
あれば、テキストの変更、フォントの変更で、内部の文字列を再生成し
(内部的には TStringListで保持しているため)自身の幅も変更します。
したがって、QRTextAdjust の処理中に、幅が変わらないのはおかしい話
ということなんでしょう。
もし、プレビューではなく印刷処理中は、幅変更されない仕様(バグ?)に
なっているのであれば、おそらくPDFで出力しても同じでしょう。
ですが、PDF出力において、解像度を72dpi、96dpi等の通常の画面と同じ
程度で印刷したとき、正常動作するのであれば、QRDBText.Widthが、
印刷中は印刷対象の解像度によってWidthが変更になる、変なプロパティ
なのかもしれません。
そのときは、解像度に影響されない通常のTLabelでサイズを計算するか、
beagleさんの
> C.等幅フォントを使用して、文字数から最適なフォントサイズを割り出す。
が、問題回避方法になると思います。
QR2,QR3のソースを見る限り、印刷時にのみ怪しい動作になるようには見えませんが。
実際にフォント幅取得して計算すべきなんかな?
procedure QRTextAdjust(Sender:TObject; dat:string; dfsize:word; maxwidth:integer);
QRPrinter.Canvas.Font.Assign(TQRDBText(Sender).Font)
textWidth := QRPrinter.Canvas.TextWidth(dat)
while (textWidth > QRPrinter.XSize(maxwidth)) do begin
QRPrinter.Canvas.Font.Size := QRPrinter.Canvas.Font.Size - 1;
textWidth := QRPrinter.Canvas.TextWidth(dat);
end;
・・・どっか単位違う気がする
ofZさん
>(略)〜使用経験があるのでしたら、ご存知のハズ。
あ、おっしゃるとおりですね。失礼しました(汗)
さっきDelphi環境を作りました。
ジュウザさん
以下が貴方の望む解決策かどうかわかりませんが、とりあえず。
>(〜略)ルーチンを作りました。
>procedure QRTextAdjust(略〜)
>無限ループに(〜略)
これですが、サブルーチン/関数ではなく、『ベタに書いて』ください。
こちらで動作確認したテストコード(DetailBeforePrint)です。
procedure TQuickReport1.QRBand1BeforePrint(Sender: TQRCustomBand;
var PrintBand: Boolean);
const
maxwidth = 60 ;
begin
(略)
while (QRDBText1.Width > maxwidth) do begin
QRDBText1.Font.Size:=QRDBText1.Font.Size - 1;
end;
end;
これでうまくいく理由/サブルーチンだと無限ループに陥る理由は、だいたい
想像がつきますよね?
ofZさん、beagleさん、レスありがとうございます!
ようやくプレビューでも印刷でも実現できました!!!
QRBand1BeforePrintにベタで記述してやるといけました!
試しにOnPrintでベタ書きしてみましたがダメでした。
ベタ書きを再度サブルーチンにしたらやはり無限ループ・・・
正直なぜベタ書きならいけるのかは分かりません。
分かったのは私が知識不足という事だけです。
しかし、お二人のおかげで実現できたので作業を進める事ができます。
本当にありがとうございました。
> 正直なぜベタ書きならいけるのかは分かりません。
すんません、おいらもわかりません(^^ゞ
結局役立たずだったし・・・まさに、ofZ
> 結局役立たずだったし・・・まさに、ofZ
そんなことありませんよ。
私の説明足らずの部分を見事に私の言いたい事を見抜いて詳しく説明して頂いたのでbeagleさんにも状況がちゃんと伝わったと思います。
ありがとうございました!
ジュウザさん
お役に立てて重畳です。
>そんなこと〜(略)〜ちゃんと伝わったと思います。
私もそう思います。
ofzさん
>QR2,QR3のソースを見る限り
ソース持っているんですよね。(私は持ってません)
…密かにofzさんが解説してくれるのを期待していたのに・・・l||li _|‾|○ il||li
中堅クラスのDelphi使いには、この理由をわかってほしいと思います。
できれば自力で思考して、自分なりの考えにたどり着いてほしいので
ヒントだけ。
ヒント1.
ジュウザ 2007/12/20(木) 16:26:37から引用
>実際の印刷だと(中略)【Widthの値が最初の値から全く変わらずに】無限ループ
ヒント2.
procedure TQuickReport1.QRTextAdjust(Sender: TObject);
//-----(A)
const
minFontSize = 6 ;
smallFontSize = 9 ;
NormalFontSize = 12 ;
largeFontSize = 16 ;
maxFontSize = 18 ;
//-----(B)
begin
//-----(C)
QRDBText1.Font.Size := maxFontSize;
if QRDBText1.Width > 50
then QRDBText1.Font.Size := largeFontSize;
if QRDBText1.Width > 60
then QRDBText1.Font.Size := NormalFontSize;
if QRDBText1.Width > 70
then QRDBText1.Font.Size := smallFontSize;
if QRDBText1.Width > 80
then QRDBText1.Font.Size := minFontSize;
//-----(D)
end;
として、これを
procedure TQuickReport1.QRDBText1Print(sender: TObject;
var Value: String);
begin
(略)
QRTextAdjust(QRDBText1);// ・・・(1)
end;
として結果を確認して下さい。
ついでに、上記の(1)を削除して、
procedure TQuickReport1.QRBand1BeforePrint(Sender: TQRCustomBand;
var PrintBand: Boolean);
begin
(略)
QRTextAdjust(QRDBText1);// ・・・(2)
end;
とした結果も確認してみて下さい。
改造済みQR2.0でテスト
(1)(2)共に同じ結果
PDFに出力するのも、印刷するのも一緒のはずだから、紙には出していない。
また、最初の質問で提示されたジュウザさんコード(QRTextAdjust)で試したが、
こちらは、PDF、紙共に、正常出力。
無限ループせず。
TQRDBText(Sender).Font.Size:=TQRDBText(Sender).Font.Size - 1;
↓
フォント変更→Perform(CM_FONTCHANGED, 0, 0);
↓
CMFontChanged で応答
↓
TQRDBTextのメソッド FormatLines で整形→幅・高さ変更
↓
SetWidth 内で SetBounds
↓
SetBounds で、Sizeプロパティ変更(枠線書くためのもの)
フォント変更で、これだけ流れるはずなんで、まったくWidthが変わらない理由がわからない。
OnPrint後に、変更されたサイズを利用しているように見えるから、
フォントを変えてはいけないとは思えない。
なんかバグくさい感じだけど、見るポイント違ってる?
ofzさん
>改造済みQR2.0でテスト
これは...そうですね。
私を含め、この掲示板を見ている人の何割かはボーランド社純正のQRを使用
して、しかもその何割かはQR2,QR3のソースを持っていないと思います。
ofzさんオリジナルの改造が入っているQR2.0の環境下でテストした結果だと
すると、共有情報としては再利用が厳しいと思います。
いかがでしょう?
以下、ボーランド社純正のQRで確認する事を前提に書き込みます。
>(1)(2)共に同じ結果
どんなデータを使用されましたか?
たとえば、QRDBText1.Width が80,40,60,90,70となるような複数レコードで
試して「印・刷・し・て・」比べて見てください。
>また、最初の質問で提示されたジュウザさんコード(QRTextAdjust)で試したが、
>こちらは、PDF、紙共に、正常出力。
>無限ループせず。
すみません。
procedure QRTextAdjust(Sender:TObject; dat:string; dfsize:word; maxwidth:integer);
をどこから呼び出したのか等々、もう少し詳しい状況を教えてもらえませんか。
それと、まさかとは思いますが、「PDF出力したものを紙に印刷」したのでは
ないですよね?それだと少々話しが違ってくるかもしれません。
今、エレガントな説明を考えていますが、スレ主であるジュウザさんからのレス
を待って、次のフォローを入れます。
こちらのPCの様子がアレなので、年明けまで持ち越しかな?
> すると、共有情報としては再利用が厳しいと思います。
それはわかっていますが、なんらかの修正をしたことで再現できないのであれば、「バグ」の線もあるかと思いました。
バージョンによって、ソースが変更されている可能性もあるので、
Delphi2007 = QR4.0(だよね?)と、こちらの環境とバージョンも異なるため
参考程度にと、レポートしました。
なお、先のテストは、PDF化することで確認しました。
PDF出力したものを紙に印刷ではありません。
通常使うプリンタのdpiが600なので、PDF出力でも、600dpiを使用しました。
そのため、実際に印刷しなくてもいいだろうということです。
> QRDBText1.Width が80,40,60,90,70となるような複数レコードで
これは、テストしていませんが
> ジュウザさんのQRTextAdjust をどこから呼び出したのか
これを、QRDBText1Print と QRBand1BeforePrint のそれぞれ、いずれか一方でのみ使用しました。
これだけです。
begin
QRTextAdjust(QRDBText1, Value, 12, 50);
end;
ここでは、文字列の長さが、6〜18くらいになるものを用意し、
あまり広くない範囲を制限にして、PDFではなく、直接紙に印刷。
フォントサイズが12〜5(目視ですが)くらいまで、大きさが変わって、無限ループせず。
> PDF出力したものを紙に印刷
これは、さすがに素人すぎるボケでしょう。
やっていません(笑)
beagleさんが提示したコードで、
> QRDBText1.Width が80,40,60,90,70となるような複数レコード
ができるデータを用意して試してみますが、レポートは後日ということで。
時間あれば、Delphi6クリーンインストールしてやってみますわ。
ソースに修正が入っているのはともかく、やっぱりおいらの考え方がおかしいの?
【テスト環境】
OS:Windows XP SP2 on VirtualPC
Delphi: 6(Update2 + RTLアップデート済み) + QR3.09
プリンタ:瞬簡PDF ZERO 2 & ホスト Epson PX-V600 共有
フォームにTQuickRepを貼り付け、Detailバンド作成
Detailバンドに QRDBEdit + QRLabel を配置
(QRLabelにフォントサイズを表示したいので、Edit -> Label で配置)
プレビュー開始用にTButton配置
ソースコードは以下の通りで、ジュウザさんの無限ループに陥るコードそのものと思います。
初期フォントサイズ「12」で、幅が「40」未満になるまで、フォントサイズを小さくしています。
procedure TForm1.Button1Click(Sender: TObject);
begin
//プレビュー開始用
QuickRep1.Preview;
end;
procedure QRTextAdjust(Sender:TObject; dat:string; dfsize:word; maxwidth:integer);
begin
TQRDBText(Sender).Font.Size:=dfsize;
TQRDBText(Sender).Caption:=dat;
while (TQRDBText(Sender).Width > maxwidth) and
//念のため、サイズチェックしておく
(TQRDBText(Sender).Font.Size > 0) do begin
TQRDBText(Sender).Font.Size:=TQRDBText(Sender).Font.Size - 1;
end;
end;
procedure TForm1.QRDBText1Print(sender: TObject; var Value: String);
begin
QRTextAdjust(sender, Value, 12, 40);
//フォントサイズ表示用
QRLabel1.Caption := IntToStr(QRDBText1.Font.Size);
end;
【テスト結果】
文字数 QRLabelに表示されたフォントサイズ
5 9
2 12
4 12
10 4
15 3
7 7
PDF作成 & 共有プリンタに出力 共に同じ結果。
無限ループ再現できず。
TQRDBText(Sender).Width はコンポーネントのサイズであり
TQRDBText(Sender).Font.Size でフォントサイズを設定し、
AutoSize := True でサイズがいつでも自動調整されるのならば
~~~~~~~~
どこで呼ぼうともコンポーネントのサイズ(TQRDBText(Sender).Width
)は変わると思うんだけどね
ただしTQRDBTextが印刷中かどうかを判定してたりしたら話は別なんだけど
ただ、うちだと
D7に附属しているTQRDBTextで設計時にAutoSize := True でフォントサイズ変更してもTQRDBText(Sender).Width(コンポーネントのサイズ)が変わらないんだよね・・・・何故だろう?
ソースあれば追っかけるんだけどね・・・・
BDS2006 は Forms とか書き換えてるか・・・使えないw
TQRDBText(Sender).Font.Sizeを変更しても呼ぶ場所によって印刷に反映されないと言うなら話なら分かるんだけどね・・・
関数にすると機能しないって意味不明
やっぱ~~~~ずれたか・・・・【いつでも】の所の予定だったのに・・・
> D7に附属しているTQRDBTextで設計時にAutoSize := True でフォントサイズ変更しても(略)
D7のQRのバージョンは、いくつですか?
もし4.xなら、4以降のバージョンが臭いってことになるけど
QuickRep のポップアップで表示されるのは version 3.09 なってますね
原因が分かったような気が・・
QuickRepの上に乗ってないとAutoSize が有効にならないみたいですね
上に乗ってると Width だけサイズを調整してくれるみたいです
上に乗ってないと調整してくれないって事は
if (FAutoSize = True) and (Parent is TQuickRep) then
begin
end;
こんな事をしているんだろうけど・・・
QuickRep の上に乗っている事を条件にする必要があるって事は
TQuickRep(Parent).なんかのプロパティ
を読む必要があるのではないかと・・・・・
たとえば
if (FAutoSize = True) and (Parent is TQuickRep) then
begin
if TQucikRep(Parent).isPrint = Fasle then
begin
//サイズ(Width)を調整する
end;
end;
な感じになっているのでは無いかと予想は出来るんだけど・・・
(isPrintは適当)
>QuickRepの上に乗ってないとAutoSize が有効にならないみたいですね
QR2と3のソースをざざっと眺めたところ、以下の判定を行っています。
if AutoSize and HasParent then
HasParent は、関数ではありませんが、まさに「QRのコンポーネントの
親となるTQuickRepが存在するか?」です。
で、この判定がTrueになる場合のみ、結果としてWidthを変更しています。
設計時に、レポートの表示縮尺を変更できるので、そのときに全体のサイズを
変更するために、こんな判定になっているのではないかと。
親TQuickRepがないときは、縮尺100%で計算してくれればいいのに。
明けましておめでとうございます!
年末年始休みの間にレスがたくさん付いてて感謝感激です。
beagleさんのヒント2をテストプログラムで印刷してみました。
WindowsXP SP2 + Delphi2007 + QuickReport Standard 4.06です。
用意したデータは、
----------------
あいうえ
あいうえお
あいうえおか
あいうえおかき
あいうえおかきく
----------------
と徐々に長いデータにしました。
<結果>
BeforePrintで処理した場合
フォントサイズ、18,18,16,12,9、の順で変化。
TextPrintで処理した場合
フォントサイズ、18,18,6,16,6、の順で変化。
なぜかTextPrintだといきなり6になってまた大きくなってと意味不明な動きをします。
ofZさんの結果は同じという事なのでやはりQRに修正がされてる分、正しい動きをするのかなと思われます。
最初の関数にすると無限ループになるのは未だに原因が想像できません。
今回のテストでBeforePrintで処理をするのがいいというのは分かったような・・・
うーむ、頭がこんがらかってきました。
> ofZさんの結果は同じという事なのでやはりQRに修正がされてる分、正しい動きをするのかなと思われます。
「ofZ 2007/12/28(金) 21:19:41」
ここでテストしたQR3.09は、ソース修正のされていない、
インストールされた直後のものをそのまま使っています。
beagle 2007/12/28(金) 14:12:40
> ofzさんオリジナルの改造が入っているQR2.0の環境下でテストした結果だと
> すると、共有情報としては再利用が厳しいと思います。
この意見を受けての3.09でのテストですので、毎回修正済みQRを使用しているのではありません。
当方のテストで、ソース修正のない3.09では、無限ループしないことを
報告したものですのです。
誤解を与えるかもしれませんので、訂正します。
なお、私の見解は、QR4.0以降の不具合です。
> ここでテストしたQR3.09は、ソース修正のされていない、
> インストールされた直後のものをそのまま使っています。
失礼しました。修正バージョンではありませんでしたね。すいません。
QuickReportのバージョンによって動きが変わるのは困ったものですね。
KHE00221さん、ofzさん、情報ありがとうございます。
QuickReportのバージョンによっては動作が異なるのでしょうか。
beagle 2007/12/27(木) 18:04:32はミスリードだったのかもしれません。
もう少し調べてみます。 あと、折角なので。
ジュウザさん
>徐々に長いデータにしました。
>BeforePrintで処理をするのがいい(後略)
結論を出すのはまだ早いかもしれません。なんとなれば
「それは仕様です」(‾ー‾)ニヤリ
冗談はともかく、以下のデータを「順序を変えずに」BeforePrint及びTextPrintで
ヒント2を試してもらえませんか?
小泉 英夫
東国原 純一郎
峰 豊
尾崎 竜太
要 旬
エリカ サンタマリア
小栗 潤
沢尻 シャキーラ
浜崎 來未
倖田 あゆみ
beagleさん、テストしてみました。
左の数字が印刷した時のフォントサイズです。
<BeforePrint>
18 小泉 英夫
16 東国原 純一郎
9 峰 豊
18 尾崎 竜太
16 要 旬
18 エリカ サンタマリア
6 小栗 潤
18 沢尻 シャキーラ
6 浜崎 來未
16 倖田 あゆみ
短い「峰 豊」が小さいフォントになったり、
長い「エリカ サンタマリア」がでかいフォントになったり何か変・・・
<TextPrint>
16 小泉 英夫
6 東国原 純一郎
18 峰 豊
18 尾崎 竜太
9 要 旬
6 エリカ サンタマリア
18 小栗 潤
18 沢尻 シャキーラ
6 浜崎 來未
18 倖田 あゆみ
短い「要 旬」が小さいフォントになったり・・・うーむ。
QuickReportよ、なぜにそんな動きをするのだ?
ツイート | ![]() |