カスタム書式/要素

このページでは、以下の帳票を作成します。

この帳票では2つの点でRapidReportの機能を拡張しています。

まず、「カスタム書式のサンプル」と書かれた場所では、 郵便番号データの3桁目の後にハイフン(-)を入れて表示しています。 このような書式の制御は、標準のフォーマッタでは行うことができないため、 独自のフォーマッタを作成して実現します。

次に、「カスタム要素のサンプル」と書かれた場所では、 チェックボックスを描画しています。 やはり標準ではチェックボックスを描画する要素は用意されていないので、 こちらも独自の要素レンダラを作成して実現します。

カスタム書式とカスタム要素のサンプル
サンプルについて
完成したサンプルが example フォルダ内に以下の名前で含まれています。 帳票定義ファイル: example_extention.rrpt ソースコード: ExampleExtention.cs、ExampleExtention.vb、ExampleExtention.java

標準では用意されていない機能を必要とする帳票を作成する場合、 レポートデザイナの実行ファイルと同じ場所にある[setting.json]というファイルに設定を追加することで、 任意のフォーマッタや要素を作成できるようになります。

ここでは、サンプル帳票に合わせて[setting.json]の設定例を示しますが、 「レポートデザイナの設定」には設定方法の完全なドキュメントがあります。

カスタム書式

郵便番号を表示する[フィールド]要素では、[書式] プロパティに "yubin" という値を設定しています。

デフォルトでは[書式]プロパティの選択肢には、"default"という値しか現れません。 そこで、 [setting.json] に以下の内容を書いた上でレポートデザイナを起動することで、 "yubin"という値を選択できるようになります。

{
  ...
  formatter: [
    {type:"yubin"}
  ]
  ...
}

[書式]プロパティの "yubin" という値は、 この[フィールド]に表示するデータの書式を制御するフォーマッタを選択するためのキーとして利用されます。

実際に書式の制御を行う処理は、帳票出力を行うプログラム内でフォーマッタクラスを作成して定義します。 フォーマッタクラスはITextFormatterインターフェースを実装する必要があります。 郵便番号の書式制御を行うクラス[YubinTextFormatter]の定義を以下に示します。

  // C#

  // 郵便番号フォーマッタ
  public class YubinTextFormatter : 
    jp.co.systembase.report.textformatter.ITextFormatter
  {
    public string Format(object v, ElementDesign design)
    {
      if (v == null)
      {
        return null;
      }
      String _v = v.ToString();
      if (_v.Length > 3)
      {
        return _v.Substring(0, 3) + "-" + _v.Substring(3);
      }
        else
      {
        return _v;
      }
    }
  }
  ' VisualBasic

  ' 郵便番号フォーマッタ
  Public Class YubinTextFormatter
    Implements ITextFormatter
    Public Function Format( _
        v As Object, _
        design As ElementDesign) As String Implements ITextFormatter.Format
      If v Is Nothing Then
        Return Nothing
      End If
      Dim _v As String = v.ToString
      If _v.Length > 3 Then
        Return _v.Substring(0, 3) & "-" & _v.Substring(3)
      Else
        Return _v
      End If
    End Function
  End Class
  // Java

  // 郵便番号フォーマッタ
  public static class YubinTextFormatter implements ITextFormatter 
  {
    public String format(Object v, ElementDesign design)
    {
      if (v == null)
      {
        return null;
      }
      String _v = v.toString();
      if (_v.length() > 3)
      {
        return _v.substring(0, 3) + "-" + _v.substring(3);
      }
        else
      {
        return _v;
      }
    }
  }

以下のように書くことで、YubinTextFormatterを "yubin" というキーで登録することができます。

  // C#

  // 郵便番号フォーマッタが設定されたSettingオブジェクトを用意します
  ReportSetting setting = new ReportSetting();
  setting.TextFormatterMap.Add("yubin", new YubinTextFormatter());

  Report report = new Report(Json.Read("report\\example_extention.rrpt"), setting);
  report.Fill(new ReportDataSource(getDataTable()));
  ReportPages pages = report.GetPages();
  ' VisualBasic

  ' 郵便番号フォーマッタが設定されたSettingオブジェクトを用意します
  Dim setting As New ReportSetting
  setting.TextFormatterMap.Add("yubin", New YubinTextFormatter)

  Dim report As New Report(Json.Read("report\example_extention.rrpt"), setting)
  report.Fill(New ReportDataSource(getDataTable))
  Dim pages As ReportPages = report.GetPages()
  // Java

  // 郵便番号フォーマッタが設定されたSettingオブジェクトを用意します
  ReportSetting setting = new ReportSetting();
  setting.textFormatterMap.put("yubin", new YubinTextFormatter());

  Report report = new Report(ReadUtil.readJson("report\\example_extention.rrpt"), setting);
  report.fill(new ReportDataSource(getDataTable()));
  ReportPages pages = report.getPages();

カスタム要素

チェックボックスを描画する要素の[type(種類)]は "checkbox(チェックボックス)" となっています。 さらに、この要素は[式]という要素を持っており、 チェック状態を表す式を定義できるようになっています。

標準ではこのような要素をレポートデザイナで作成することはできません。 そこで、[setting.json]に以下の内容を書いた上でデザイナを起動することで、 [type]が "checkbox" で、なおかつ[式]というプロパティを持った要素を作成することができるようになります。

{
  ...
  element: [
    {
      type:"checkbox",
      ja:"チェックボックス",
      properties: [
        {key:"exp", type:"expression", ja:"式"}
      ]
    }
  ]
  ...
}

チェックボックスの要素レンダラを作成するために、 IElementRendererというインターフェースを実装したクラスを作成します。 IElementRendererインターフェースは各レンダラ(PDF/XLS/XLSX/プレビュー・直接印刷)毎に用意されているので、 利用するレンダラに応じたクラスを作成する必要があります。

ここでは、.NET(C#/VisualBasic)についてはプレビュー・直接印刷、 JavaについてはPDF出力を行う際に利用可能なクラスの定義を示しますが、 exampleディレクトリ以下のサンプルには、全ての組み合わせのコードが含まれています。

  // C#

  // チェックボックスを描く要素レンダラ(プレビュー・直接印刷)
  public class GdiCheckBoxRenderer :
    jp.co.systembase.report.renderer.gdi.elementrenderer.IElementRenderer
  {
    public void Render(
        RenderingEnv env, 
        ReportDesign reportDesign, 
        Region region, 
        ElementDesign design, 
        object data)
    {
      Region r = region.ToPointScale(reportDesign);
      Single x = r.Left + r.GetWidth() / 2;
      Single y = r.Top + r.GetHeight() / 2;
      Single w = 12;
      env.Graphics.DrawRectangle(Pens.Black, x - w / 2, y - w / 2, w, w);
      if ((bool)data)
      {
        Point[] p = {
          new Point((int)(x - w / 2), (int)(y - w / 4)),
          new Point((int)(x - w / 4), (int)(y + w / 2)),
          new Point((int)(x + w / 2), (int)(y - w / 2)),
          new Point((int)(x - w / 4), (int)(y))};
        env.Graphics.FillPolygon(Brushes.SteelBlue, p);
      }
    }
  }
  ' VisualBasic

  ' チェックボックスを描く要素レンダラ(プレビュー・直接印刷)
  Public Class GdiCheckBoxRenderer
    Implements gdi.elementrenderer.IElementRenderer
    Public Sub Render( _
        env As gdi.RenderingEnv, _
        reportDesign As ReportDesign, _
        region As Region, _
        design As ElementDesign, _
        data As Object) Implements gdi.elementrenderer.IElementRenderer.Render
      Dim r As Region = region.ToPointScale(reportDesign)
      Dim x As Single = r.Left + r.GetWidth / 2
      Dim y As Single = r.Top + r.GetHeight / 2
      Dim w As Single = 12
      env.Graphics.DrawRectangle(Pens.Black, x - w / 2, y - w / 2, w, w)
      If data Then
        Dim p As Point() = { _
          New Point(x - w / 2, y - w / 4), _
          New Point(x - w / 4, y + w / 2), _
          New Point(x + w / 2, y - w / 2), _
          New Point(x - w / 4, y)}
        env.Graphics.FillPolygon(Brushes.SteelBlue, p)
      End If
    End Sub
  End Class
  // Java

  // チェックボックスを描く要素レンダラ(PDF)
  public static class PdfCheckBoxRenderer
    implements jp.co.systembase.report.renderer.pdf.elementrenderer.IElementRenderer
  {
    public void render(
        PdfRenderer renderer, 
        ReportDesign reportDesign, 
        Region region, 
        ElementDesign design, 
        Object data)
    {
      Region r = region.toPointScale(reportDesign);
      PdfContentByte cb = renderer.writer.getDirectContent();
      float x = r.left + r.getWidth() / 2;
      float y = r.top + r.getHeight() / 2;
      float w = 12;
      cb.saveState();
      cb.rectangle(renderer.trans.x(x - w / 2), renderer.trans.y(y - w / 2), w, -w);
      cb.stroke();
      if (ReportUtil.condition(data)){
        cb.setColorFill(RenderUtil.getColor("steelblue"));
        cb.moveTo(renderer.trans.x(x - w / 2), renderer.trans.y(y - w / 4));
        cb.lineTo(renderer.trans.x(x - w / 4), renderer.trans.y(y + w / 2));
        cb.lineTo(renderer.trans.x(x + w / 2), renderer.trans.y(y - w / 2));
        cb.lineTo(renderer.trans.x(x - w / 4), renderer.trans.y(y));
        cb.fill();
      }
      cb.restoreState();
    }
  }  

以下のように書くことで、作成したチェックボックスの要素レンダラを"checkbox"というキーで登録することができます。

  // C#

  // プレビュー
  {
    // チェックボックスレンダラが設定されたSettingオブジェクトを用意します
    GdiRendererSetting gdiSetting = new GdiRendererSetting();
    gdiSetting.ElementRendererMap.Add("checkbox", new GdiCheckBoxRenderer());

    FmPrintPreview preview = new FmPrintPreview(new Printer(pages, gdiSetting));
    preview.StartUpZoomFit = true;
    preview.ShowDialog();
  }
  ' VisualBasic

  ' プレビュー
  With Nothing
    ' チェックボックスレンダラが設定されたSettingオブジェクトを用意します
    Dim gdiSetting As New GdiRendererSetting
    gdiSetting.ElementRendererMap.Add("checkbox", New GdiCheckBoxRenderer)

    Dim preview As New FmPrintPreview(New Printer(pages, gdiSetting))
    preview.StartUpZoomFit = True
    preview.ShowDialog()
  End With
  // Java

  // PDF出力
  {
    // チェックボックスレンダラが設定されたSettingオブジェクトを用意します
    PdfRendererSetting pdfSetting = new PdfRendererSetting();
    pdfSetting.elementRendererMap.put("checkbox", new PdfCheckBoxRenderer());

    FileOutputStream fos = new FileOutputStream("output\\example_extention.pdf");
    try {
      PdfRenderer renderer = new PdfRenderer(fos, pdfSetting);
      pages.render(renderer);
    } finally {
      fos.close();
    }
  }