SPREAD

ユースケースデモの[実績確認]画面を使ってデータベースのデータを表示させる際に、どのように表現するとユーザーエクスペリエンスの向上につながるのかを中心に取り上げます。


プロジェクトをダウンロードする

ClickOnceデモで動作を見る


[実績確認]画面について

[実績確認]画面は、メインメニューの[実績確認]ボタンをクリックすると呼び出され、売り上げ分析システムに取り込んだ販売実績データ(T02)をもとに年度ごとの販売実績を月別でSPREAD上に表示します。

フローチャート
画像「フローチャート」拡大して見る
実績確認画面
画像「実績確認画面」拡大して見る

「当年度分の各製品の販売金額を一覧形式で確認できるようにしたい」というユーザーの要求を想定し、次のような機能を実装しています。

  • 製品別、カテゴリ別の2つのシートで販売金額を表示
  • 製品名あるいは、カテゴリ名から過去3年分の月別販売金額と月平均売上額を階層表示
  • 金額が表示されたセルのダブルクリックで明細画面がポップアップし、取引案件ごとの販売金額を表示
  • 表示されたデータの月別合計金額を列フッタで動的に集計
  • 対象年度で指定したデータの印刷、PDF生成、Excelシート出力機能
    複数形式エクスポートを見る

[実績確認]画面で使われている
SPREADの機能

この画面で使われているSPREADの設定について、ユーザーインタフェース構築の目線で説明します。

データの階層表示で隠れニーズに応える

よくある要件のひとつとして、「当年度の販売実績を確認する画面」があります。開発者はこれを受けて、入力された対象年度のデータを月別で表示するような画面を作るのですが、エンドユーザーは過去のデータを参照したくなることがあります。その際、現状の当年度のデータをクリアして、再度過去データ検索するのはとても面倒です。そこで、要件にはなくとも今見ているデータをクリアすることなく過去データがさくっと表示される画面にしておくと「使いやすい」「気が利いている」と評価されることがあります。

SPREADでは、データテーブル間にリレーションが設定してあるデータセットをDataSourceプロパティに指定すると自動的に階層形式で表示できます。ユースケースデモではこの機能を利用して過去3年分の実績データをリレーションで紐づけて階層的に表示させています。このような処理は、エンドユーザーの「ちょっと過去のデータをみたいな」という隠れニーズに応えています。

具体的には、[実績取込・登録]画面で生成された実績データベース(T02)から、「当年度」、「前年度」、「一昨年度」、「過去3年の平均」の4つのテーブルを生成し、当年度の実績を親、残りの3つを子とするリレーションを設定したデータセットを作成します。詳細なコードはサンプルプロジェクトを参照してください。このデータセットをSPREADのDataSourceプロパティにセットするだけで画面のような階層表示が可能になります。階層の開閉を行う「+」「-」アイコンも自動表示されます。

1:3のリレーションを設定
画像「1:3のリレーションを設定」拡大して見る

また、リレーションの設定方法により、SPREADの表示形式も異なります。たとえば、3つのデータテーブルを親・子・孫のように1:1:1でリレーションすると下図のような階層表示になります。

1:1:1のリレーションを設定したデータソースをSPREADで表示
画像「1:1:1のリレーションを設定したデータソースをSPREADで表示」拡大して見る

さらに、デモ画面のような1:Nのリレーションを設定した場合、子のデータはSPREADの内部でそれぞれのシートとして生成されるため、SPREAD上にヘッダを表示することもできます。

階層表示の注意点

階層表示の利用でひとつ注意したい点は、これは「当年度のデータを見ることが主目的」で、過去データは必要な時だけ参照する場合に有効だということです。階層表示のユーザーインタフェースは子階層にあるデータを「閉じておける」ことが利点です。膨大なデータが画面いっぱいに広がっていては逆にわかりにくいですし、すべてのデータを展開させておくとレスポンスにも影響します。SPREADでは、リレーションを設定したデータセットをSPREADに接続すると子階層のデータを表示するための別シートを作成します。このシートを作成するタイミングは階層が展開されたときです。そのため、初期表示ですべてのシートを展開するように設定してしまうと、レコード数が多い場合にはレスポンスが悪化することもあります。

したがって、このユーザーインタフェースを使うときは、初期表示で最も見たい子階層データだけを展開させておき、残りは閉じておくように設定するとスマートです。また、過去数年分の実績を常に表示させたい場合にはデータを階層化せず別シートに表示したり、別のSPREADコントロールに表示させたりする画面を設計したほうがよいでしょう。

また、子階層の初期表示を閉じておいた場合でもレスポンスの低下がみられる場合があります。例えばロジック上、子階層のシートにある値などを取得して何らかの動作を実装することはよくありますが、その場合SPREADではGetChildViewというメソッドで対応できます。ただし、このメソッドを実行すると、そのタイミングで子階層が作成され、ChildViewCreated イベントが発生します。

メンバ名 定義
GetChildView メソッド 子階層のシートを作成し、取得します
ChildViewCreated イベント 子階層のシートが作成されたときに発生します

指定のデータを強調表示

過去年度のデータがただ見られるだけではなく、ある条件で強調表示されるとさらにエンドユーザーに対して「気の利いた」UIを提供できます。ユースケースデモでは、子階層である前年度のデータを参照して販売金額が下がった値は赤字で表示するよう実装しています。

前年割れデータを赤字で表示
画像「前年割れデータを赤字で表示」拡大して見る

ただし、前項で注意点として挙げたように、この部分をGetChildViewメソッドで実装してしまうと、レコード数が多い場合には応答性が悪くなるでしょう。これを回避するため、デモではGetChildViewメソッドを使用せずに、連結しているデータソースの内容を直接参照しています。「検索」ボタンが押されると、呼び出されるsetdsメソッドにて、次のような実装を行っています。

コード(C#)
// このコードで使用されている列定義変数
fprivate int _SPR_Hgkey = 0;
private int _SPR_m4 = 3;

// 前年割れの月は文字色変更
// (このタイミングでSPREADの階層データをGetChildView等を使用して取得すると、
// ChildViewCreatedイベントが全ての行に対して発生してしまうため、データテーブルを参照)
DataRow[] rd;
int itemidx;
for (int i = 0; i < fpSpread1.ActiveSheet.RowCount; i++)
{
    rd = ds.Tables[1].Select("GKEY = '" + fpSpread1.ActiveSheet.GetValue(i, _SPR_Hgkey).ToString()
    + "'");
    if (rd.Length > 0)
    {
        for (int m = 0; m < 13; m++)
        {
            itemidx = m + _SPR_m4;
            if (Convert.ToDecimal(rd[0].ItemArray[itemidx]) >
            Convert.ToDecimal(fpSpread1.ActiveSheet.GetValue(i, itemidx)))
            {
                fpSpread1.ActiveSheet.Cells[i, itemidx].ForeColor = Color.Red;
            }
        }
    }
}
コード(VB)
‘ このコードで使用されている列定義変数
Private _SPR_Hgkey As Integer = 0
private _SPR_m4 As Integer = 3

'  前年割れの月は文字色変更
'  (このタイミングでSPREADの階層データをGetChildView等を使用して取得すると、
'  ChildViewCreatedイベントが全ての行に対して発生してしまうため、データテーブルを参照)
Dim rd As DataRow()
Dim itemidx As Integer
For i As Integer = 0 To fpSpread1.ActiveSheet.RowCount - 1
    rd = ds.Tables(1).[Select]("GKEY = '" & fpSpread1.ActiveSheet.GetValue(i, _SPR_Hgkey).ToString() 
   & "'")
    If rd.Length > 0 Then
        For m As Integer = 0 To 12
            itemidx = m + _SPR_m4
            If Convert.ToDecimal(rd(0).ItemArray(itemidx)) >
            Convert.ToDecimal(fpSpread1. ActiveSheet.GetValue(i, itemidx)) Then
               fpSpread1.ActiveSheet.Cells(i, itemidx).ForeColor = Color.Red
            End If
        Next
    End If
Next

列フッタを活用して動的な集計行を作る

列データの合計や平均値などをデータグリッドの一番下に表示させたいというのは非常に多いニーズです。しかし、表示行数が多く1画面にレコードが収まりきらない時に合計行を確認するために画面を一番下までスクロールするのは、エンドユーザーは面倒に感じます。そういう時に実装してあると喜ばれるのが列フッタの集計機能です。列フッタは常にSPREADコントロールの一番下に表示されるので、レコード数が多くても合計をすぐに確認できます。

数式はColumnFooterクラスSetAggregationTypeメソッドで設定できます。この機能を利用して、ユースケースデモでは列を動的に集計して合計を出力しています。フッタは明細行とは異なり、独立したフッタ用のクラスで定義されているため、論理フッタとしてコード上から最終行を判定して実装するという処理はしなくてもよいので、とても簡単に集計ができます。利用できる数式はAggregationType列挙体において下表のように定義されます。

メンバ 解説
None 数式を指定しない
Custom カスタム集約
Avg 範囲内のセルの平均を返します
AvgIgnoreHidden 範囲内のセルの平均を返します(非表示の値を無視します)
Count 範囲内のセルのうち数値を含むセルの数を数えます
CountA 範囲内のセルのうち空でないセルの数を数えます
CountAIgnoreHidden 範囲内のセルのうち空でないセルの数を数えます(非表示の値は無視します)
CountIgnoreHidden 範囲内のセルのうち数値を含むセルの数を数えます(非表示の値は無視します)
Max 範囲内のセルの最大値を返します
MaxIgnoreHidden 範囲内のセルの最大値を返します(非表示の値は無視します)
Min 範囲内のセルの最小値を返します
MinIgnoreHidden 範囲内のセルの最小値を返します(非表示の値は無視します)
Product 範囲内のすべてのセルを乗算し、その積を返します
ProductIgnoreHidden 範囲内のすべてのセルを乗算し、その積を返します(非表示の値は無視します)
StDev 範囲内のセルの集合の標準偏差を返します
StDevIgnoreHidden 範囲内のセルの集合の標準偏差を返します(非表示の値は無視します)
StDevP 範囲内のセルとして与えられた母集団全体に基づいて標準偏差を計算します
StDevPIgnoreHidden 範囲内のセルとして与えられた母集団全体に基づいて標準偏差を計算します(非表示の値は無視します)
Sum 範囲内のセルの値を合計します
SumIgnoreHidden 範囲内のセルの値を合計します(非表示の値は無視します)
Var 母集団のサンプルに基づいて分散を計算します
VarIgnoreHidden 母集団のサンプルに基づいて分散を計算します(非表示の値は無視します)
VarP 母集団全体に基づいて分散を計算します
VarPIgnoreHidden 母集団全体に基づいて分散を計算します(非表示の値は無視します)
コード(C#)
// このコードで使用されている列定義変数
private int _SPR_m4 = 3;
private int _SPR_mTotal = 15;

// フッタ表示
fpSpread1.ActiveSheet.ColumnFooter.Visible = true;
fpSpread1.ActiveSheet.ColumnFooter.DefaultStyle.HorizontalAlignment =
CellHorizontalAlignment.Right;
// 先頭2列はタイトル列にします。
fpSpread1.ActiveSheet.AddColumnFooterSpanCell(0, 1, 1, 2);
fpSpread1.ActiveSheet.ColumnFooter.Cells[0, _SPR_product].Value =
"総合計";
fpSpread1.ActiveSheet.ColumnFooter.Cells[0, _SPR_product].HorizontalAlignment =
CellHorizontalAlignment.Center;
for (int i = _SPR_m4; i <= _SPR_mTotal; i++)
{
    fpSpread1.ActiveSheet.ColumnFooter.SetAggregationType
    (0, i, FarPoint.Win.Spread.Model. AggregationType.Sum);
    fpSpread1.ActiveSheet.ColumnFooter.SetAggregationFormat(0, i, "{0:#,##0}");
}
コード(VB)
' このコードで使用されている列定義変数
Private _SPR_m4 As Integer = 3
Private _SPR_mTotal As Integer = 15

' フッタ表示
fpSpread1.ActiveSheet.ColumnFooter.Visible = True
fpSpread1.ActiveSheet.ColumnFooter.DefaultStyle.HorizontalAlignment = CellHorizontalAlignment.Right
‘ 先頭2列はタイトル列にします。
fpSpread1.ActiveSheet.AddColumnFooterSpanCell(0, 1, 1, 2)
fpSpread1.ActiveSheet.ColumnFooter.Cells(0, _SPR_product).Value = "総合計"
fpSpread1.ActiveSheet.ColumnFooter.Cells(0, _SPR_product).HorizontalAlignment =
CellHorizontalAlignment.Center
For i As Integer = _SPR_m4 To _SPR_mTotal
    fpSpread1.ActiveSheet.ColumnFooter.SetAggregationType
    (0, i, FarPoint.Win.Spread.Model.AggregationType.Sum)
    fpSpread1.ActiveSheet.ColumnFooter.SetAggregationFormat(0, i, "{0:#,##0}")
Next


かんたん・多機能・安心のサポート
SPREADで楽々アプリケーション開発

まずは評価版ダウンロードから

今すぐ評価版を無料で入手する


製品・サービスに関する
ご質問・ご相談など、
お気軽にお問合せください。

電話でお問合せ

048-222-3001

(平日 9:00~12:00、13:00~17:30)