カラム固定機能
業務システムを作っていると、テーブルに多くの項目を表示するケースがあります。そうすると画面に表示しきれずにスクロールさせることになります。この際に大抵出てくるのが「Excelのウインドウ枠の固定のように先頭の数カラムを固定し、残りもカラムのみ横スクロールさせたい」といった要望です。この場合、固定部ヘッダテーブル、スクロール部ヘッダテーブル、固定部データテーブル、スクロール部データテーブルの4つのテーブルを用意し、スクロール位置を同期させるスクリプトを作っていました。しかし、別のテーブルのカラム幅を合わせる必要が出てくるため面倒な実装になります。
しかし最近、CSS3の"position: sticky;"が実装されたブラウザが出てきました。これを使えば1つのテーブルでカラム固定テーブルを実装することができます。
そこで、HtmlTableクラスにsetFixedColumnsというメソッドを用意しました。以下のBlockScrollTableForm.javaの太字部分で左から4カラムを固定する設定を行っています。
package pagesample.page;
import dataforms.controller.Form;
import dataforms.field.base.FieldList;
import dataforms.field.base.TextField;
import dataforms.field.sqltype.IntegerField;
import dataforms.field.sqltype.NumericField;
import dataforms.htmltable.EditableHtmlTable;
/**
* ブロックスクロールテーブルを配置したフォーム。
*
*/
public class BlockScrollTableForm extends Form {
/**
* コンストラクタ。
*/
public BlockScrollTableForm() {
super(null);
FieldList flist = new FieldList();
flist.addField(new TextField("text1")).setComment("テキスト1");
flist.addField(new TextField("text2")).setComment("テキスト2");
flist.addField(new TextField("text3")).setComment("テキスト3");
flist.addField(new TextField("text4")).setComment("テキスト4");
flist.addField(new TextField("text5")).setComment("テキスト5");
flist.addField(new TextField("text6")).setComment("テキスト6");
flist.addField(new TextField("text7")).setComment("テキスト7");
flist.addField(new TextField("text8")).setComment("テキスト8");
flist.addField(new TextField("text9")).setComment("テキスト9");
flist.addField(new TextField("text10")).setComment("テキスト10");
flist.addField(new IntegerField("integer1")).setComment("整数");
flist.addField(new NumericField("numeric1", 10, 2)).setComment("数値");
EditableHtmlTable table = new EditableHtmlTable("simpleTable", flist);
table.setFixedColumns(4);
this.addHtmlTable(table);
}
}
BlockScrollTableFormを配置したページを以下のように作成します。
package pagesample.page;
import dataforms.app.page.base.BasePage;
import dataforms.dao.Dao;
import dataforms.dao.Table;
/**
* ページクラス。
*/
public class BlockScrollTablePage extends BasePage {
/**
* コンストラクタ。
*/
public BlockScrollTablePage() {
this.addForm(new BlockScrollTableForm());
}
/**
* Pageが配置されるパスを返します。
*
* @return Pageが配置されるパス。
*/
public String getFunctionPath() {
return "/pagesample";
}
・・・ 中略 ・・・
}
このページクラスからBlockScrollTablePage.htmlを自動生成します。固定カラム数が指定されたテーブルを生成した場合、各カラムの幅が自動的に設定されます。ただし、テーブルの高さの指定は行われないため、縦スクロールを使用する場合は以下の太字部分のようにテーブルの高さを指定します。カラムの幅はカラム名の文字数などから適当に決定するので、レイアウトに問題がある場合はhtmlを直接修正してください。固定カラム数を指定した場合、各カラムの幅の指定は必須になります。既にhtmlを生成した後固定カラム数を指定した場合、テーブル中のtdの幅を全て設定する必要があります。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="mainDiv">
<form id="blockScrollTableForm">
<div class="formHeader">xxx</div>
<table class="responsive">
<tbody>
</tbody>
</table>
<div class="hScrollDiv">
<table id="simpleTable" class="editableTable" style="height: 300px;">
<thead>
<tr>
<th colspan="2" nowrap>
</th>
<th nowrap>
No.
</th>
<th>
テキスト1
</th>
<th>
テキスト2
</th>
<th>
テキスト3
</th>
<th>
テキスト4
</th>
<th>
テキスト5
</th>
<th>
テキスト6
</th>
<th>
テキスト7
</th>
<th>
テキスト8
</th>
<th>
テキスト9
</th>
<th>
テキスト10
</th>
<th>
整数
</th>
<th>
数値
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="buttonColumn">
<input type="button" id="simpleTable[0].addButton" value="+"/>
</td>
<td class="buttonColumn">
<input type="button" id="simpleTable[0].deleteButton" value="-"/>
</td>
<td style="text-align: right;" class="rowno">
<span id="simpleTable[0].no"></span>
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text1" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text2" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text3" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text4" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text5" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text6" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text7" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text8" />
</td>
<td style="width: 98px;">
<input type="text" id="simpleTable[0].text9" />
</td>
<td style="width: 112px;">
<input type="text" id="simpleTable[0].text10" />
</td>
<td style="width: 56px;">
<input type="text" id="simpleTable[0].integer1" />
</td>
<td style="width: 56px;">
<input type="text" id="simpleTable[0].numeric1" />
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th class="buttonColumn">
<input type="button" id="simpleTable.addButton" value="+"/>
</th>
<th colspan="14">
</th>
</tr>
</tfoot>
</table>
</div>
</form>
</div>
</body>
</html>
このページを表示し情報を入力してスクロールさせたのが下図になります。
この機能はChromeやSafari、Firefoxの場合"position: sticky;"を利用するためスムーズに動作します。Microsoft Edgeは"position: sticky;"は実装されているのですが、ChromeやFirefoxと微妙に動作が異なるため、縦スクロール時のヘッダ位置の調整はJavaScriptで行っています。そのため縦スクロールの終了のタイミングで、ヘッダの位置が調整されます。IEは"position: sticky;"がサポートされていないので、全てスクリプトで各セルの位置調整を行っています。そのためスクロール終了のタイミングで各セルの位置調整が行われます。
さいごに
今までの記事で、dataforms.jarの特徴であるJavaとJavaScriptクラスの連携について解説してきました。これらのクラスの構造を理解すると、開発ツールで作成したとりあえず動作するプログラムに対し、わずかな変更でさまざまな機能を追加することができます。
これからのdataforms.jarの開発の予定ですが、Apache FOPを使用したPDFレポート機能の追加や、開発ツールの充実を予定しています。ぜひ試してみてください。
