QuickReportで枠内に入るように文字の大きさ調整

解決


ジュウザ  2007-12-21 01:26:37  No: 29005

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って昔に比べてバグが多いですがこれもバグなのでしょうか?


かず  2007-12-24 07:27:20  No: 29006

QRTextAdjustはDetailBeforePrintから呼んでいるのでしょうか?

QuickReportは以前よりバグが増えたと感じていません。むしろ便利になりました。


ofZ  2007-12-25 19:07:51  No: 29007

AutoSize = True になっていない?


ジュウザ  2007-12-25 22:08:22  No: 29008

かずさん、レスありがとうございます。
QRDBTextPrintから呼んでます。
DetailBeforePrintや他のイベントもいろいろ試したのですがうまくいったのはQRDBTextPrintだけでした。プレビューだけですが・・・
Delphi7くらいからのQuickReportではQRMemoのWordWrapをTrueにしても長い文が自動で改行されずに1行になってしまいます。
ここで聞いたらバグだと教えてもらいました。
他にもDelphi3のQuickReportから比べたら2バイト文字の処理がうまくいっていないバグがあると聞きました。

ofZさん、レスありがとうございます。
AutoSizeはTrueだったのでFalseにしてみました。
そしたら今度はプレビューまでダメになってしまいました。印刷もダメです。

うーむ、不思議です。


ofZ  2007-12-26 00:12:24  No: 29009

失礼しました。
AutoSize = True に、なっていないのではないかと勘違いしていました。

印刷中のフォントサイズ変更に反応しないバグなんだろうか?

TLabelを一個用意して(印刷対象にならないのでどこでも貼り付けOKのはず)、
それでサイズの計算してみたらどうでしょうか?
サイズの計算だけなら、大丈夫のような気がする未検証レス


beagle  2007-12-26 03:19:19  No: 29010

ジュウザさん
>不可解な現象が発生します。
>プレビューだと〜ちょうどいい大きさで印字されます。
>実際の印刷だと〜最初の値から全く変わらずに無限ループに入ります。
ええと、プレビューはともかく、実際の印刷については不可解ではない
ような気がします。
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.が一番現実的かなあ?


ofZ  2007-12-26 18:06:52  No: 29011

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;

・・・どっか単位違う気がする


beagle  2007-12-26 21:06:54  No: 29012

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;
これでうまくいく理由/サブルーチンだと無限ループに陥る理由は、だいたい
想像がつきますよね?


ジュウザ  2007-12-27 00:28:02  No: 29013

ofZさん、beagleさん、レスありがとうございます!

ようやくプレビューでも印刷でも実現できました!!!
QRBand1BeforePrintにベタで記述してやるといけました!
試しにOnPrintでベタ書きしてみましたがダメでした。
ベタ書きを再度サブルーチンにしたらやはり無限ループ・・・

正直なぜベタ書きならいけるのかは分かりません。
分かったのは私が知識不足という事だけです。

しかし、お二人のおかげで実現できたので作業を進める事ができます。
本当にありがとうございました。


ofZ  2007-12-27 01:03:19  No: 29014

> 正直なぜベタ書きならいけるのかは分かりません。
すんません、おいらもわかりません(^^ゞ

結局役立たずだったし・・・まさに、ofZ


ジュウザ  2007-12-27 19:30:27  No: 29015

> 結局役立たずだったし・・・まさに、ofZ
そんなことありませんよ。
私の説明足らずの部分を見事に私の言いたい事を見抜いて詳しく説明して頂いたのでbeagleさんにも状況がちゃんと伝わったと思います。

ありがとうございました!


beagle  2007-12-28 03:04:32  No: 29016

ジュウザさん 
お役に立てて重畳です。
>そんなこと〜(略)〜ちゃんと伝わったと思います。
私もそう思います。
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;
とした結果も確認してみて下さい。


ofZ  2007-12-28 20:47:10  No: 29017

改造済み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後に、変更されたサイズを利用しているように見えるから、
フォントを変えてはいけないとは思えない。

なんかバグくさい感じだけど、見るポイント違ってる?


beagle  2007-12-28 23:12:40  No: 29018

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の様子がアレなので、年明けまで持ち越しかな?


ofZ  2007-12-29 01:11:01  No: 29019

> すると、共有情報としては再利用が厳しいと思います。
それはわかっていますが、なんらかの修正をしたことで再現できないのであれば、「バグ」の線もあるかと思いました。
バージョンによって、ソースが変更されている可能性もあるので、
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クリーンインストールしてやってみますわ。
ソースに修正が入っているのはともかく、やっぱりおいらの考え方がおかしいの?


ofZ  2007-12-29 06:19:41  No: 29020

【テスト環境】
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作成 & 共有プリンタに出力 共に同じ結果。
無限ループ再現できず。


KHE00221  2007-12-29 18:55:58  No: 29021

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を変更しても呼ぶ場所によって印刷に反映されないと言うなら話なら分かるんだけどね・・・

関数にすると機能しないって意味不明


KHE00221  2007-12-29 18:56:52  No: 29022

やっぱ~~~~ずれたか・・・・【いつでも】の所の予定だったのに・・・


ofZ  2007-12-30 08:50:27  No: 29023

> D7に附属しているTQRDBTextで設計時にAutoSize := True でフォントサイズ変更しても(略)

D7のQRのバージョンは、いくつですか?
もし4.xなら、4以降のバージョンが臭いってことになるけど


KHE00221  2007-12-30 09:44:46  No: 29024

QuickRep のポップアップで表示されるのは version 3.09 なってますね


KHE00221  2007-12-30 09:51:36  No: 29025

原因が分かったような気が・・

QuickRepの上に乗ってないとAutoSize が有効にならないみたいですね

上に乗ってると Width だけサイズを調整してくれるみたいです


KHE00221  2007-12-30 10:28:59  No: 29026

上に乗ってないと調整してくれないって事は

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は適当)


ofZ  2007-12-30 21:10:38  No: 29027

>QuickRepの上に乗ってないとAutoSize が有効にならないみたいですね

QR2と3のソースをざざっと眺めたところ、以下の判定を行っています。
if AutoSize and HasParent then

HasParent は、関数ではありませんが、まさに「QRのコンポーネントの
親となるTQuickRepが存在するか?」です。
で、この判定がTrueになる場合のみ、結果としてWidthを変更しています。

設計時に、レポートの表示縮尺を変更できるので、そのときに全体のサイズを
変更するために、こんな判定になっているのではないかと。

親TQuickRepがないときは、縮尺100%で計算してくれればいいのに。


ジュウザ  2008-01-05 23:42:49  No: 29028

明けましておめでとうございます!

年末年始休みの間にレスがたくさん付いてて感謝感激です。
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  2008-01-07 17:36:45  No: 29029

> 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以降の不具合です。


ジュウザ  2008-01-07 18:59:13  No: 29030

> ここでテストしたQR3.09は、ソース修正のされていない、
> インストールされた直後のものをそのまま使っています。
失礼しました。修正バージョンではありませんでしたね。すいません。

QuickReportのバージョンによって動きが変わるのは困ったものですね。


beagle  2008-01-09 02:38:01  No: 29031

KHE00221さん、ofzさん、情報ありがとうございます。
QuickReportのバージョンによっては動作が異なるのでしょうか。
beagle 2007/12/27(木) 18:04:32はミスリードだったのかもしれません。
もう少し調べてみます。  あと、折角なので。
ジュウザさん
>徐々に長いデータにしました。
>BeforePrintで処理をするのがいい(後略)
結論を出すのはまだ早いかもしれません。なんとなれば
「それは仕様です」(‾ー‾)ニヤリ
冗談はともかく、以下のデータを「順序を変えずに」BeforePrint及びTextPrintで
ヒント2を試してもらえませんか?
小泉  英夫
東国原  純一郎
峰  豊
尾崎  竜太
要  旬
エリカ  サンタマリア
小栗  潤
沢尻  シャキーラ
浜崎  來未
倖田  あゆみ


ジュウザ  2008-01-09 22:09:58  No: 29032

beagleさん、テストしてみました。
左の数字が印刷した時のフォントサイズです。

<BeforePrint>
18 小泉  英夫
16 東国原  純一郎
 9 峰  豊
18 尾崎  竜太
16 要  旬
18 エリカ  サンタマリア
 6 小栗  潤
18 沢尻  シャキーラ
 6 浜崎  來未
16 倖田  あゆみ

短い「峰  豊」が小さいフォントになったり、
長い「エリカ  サンタマリア」がでかいフォントになったり何か変・・・

<TextPrint>
16 小泉  英夫
 6 東国原  純一郎
18 峰  豊
18 尾崎  竜太
 9 要  旬
 6 エリカ  サンタマリア
18 小栗  潤
18 沢尻  シャキーラ
 6 浜崎  來未
18 倖田  あゆみ

短い「要  旬」が小さいフォントになったり・・・うーむ。
QuickReportよ、なぜにそんな動きをするのだ?


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

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






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