Top > OOoBasic > Dialog > GridControl33
* グリッドコントロール (3.3) [#wad52bf4]
OpenOffice.org 3.3 の頃のグリッドコントロール。Apache OpenOffice 3.4 以降ではメソッドなどが変更されていますので、[[グリッドコントロール>../GridControl]]を参照してください。

#contents
** モデルプロパティ [#e23af7a8]
- [[ヘルプテキストとヘルプ URL>../Common#he87424b]]
- [[位置>../Common#g02345ee]]

|プロパティ|型|説明|h
|GridDataModel|.awt.grid.XGridDataModel|データ|
|ColumnModel|.awt.grid.XGridColumnModel|カラムデータ|
|RowBackgroundColor|long|背景色|
|EvenRowBackgroundColor|long|偶数行の背景色|
|ShowColumnHeader|boolean|列ヘッダの表示|
|HeaderBackgroundColor|long|ヘッダの背景色|
|SelectionModel|.view.SelectionType|選択形式|
|HScroll|boolean|水平スクロールバーの表示|
|VScroll|boolean|垂直スクロールバーの表示|
|LineColor|long|線の色|
|TextColor|long|テキストの色|


いまのところ表示するフォントと文字のサイズを変更できません。

3.3 の IDL では DataModel となっていますが、3.4 で GridDataModel に修正予定。プロパティ名の定義なので特にコードを書くときには問題ありません。

*** コントローラ [#z9185ffc]
コントローラからからは選択範囲の操作などが行えます。選択モードの設定はモデルのプロパティで行います。モードによっては各メソッドから取得できる選択範囲のインデックスに注意が必要です。

css.awt.grid.XGridControl インターフェース

3.3
- long getItemIndexAtPoint( [in] long x, [in] long y )
-- 指定した x および y の位置に表示されている行のインデックスを取得します。
- void setToolTip( [in] string[] text, [in] long[] column_index )
-- 行のツールチップを設定します。
--- 引数を両方とも空にすると各セルごとに表示されている値がツールチップとして表示されます。それ以外のときには行ごとにツールチップが設定されます。このとき、各セルの値は改行してツールチップに表示されます。
--- 4 列あるときに ["", "", "", ""]、[0, 1, 2, 3] を指定するとツールチップにはセルの内容が順に表示されます。
--- ["1: ", "2: ", "3: ", "4: "]、[0, 1, 2, 3] とすると各セルの値の前にテキストが表示されます。
--- ["hoge", "", "", ""]、[-1, 1, 2, 3] とすると最初のセルの部分にはセルの値が表示されません。

css.awt.grid.XGridSelection ベースインターフェース

- void selectAllRows()
-- 全ての行を選択します。
- void selectRows( [in] long[] rows )
-- 指定した行を選択します。
- void deselectAllRows()
-- 全てのセルの選択を解除します。
- void deselectRows( [in] long[] rows )
-- 指定した行の選択を解除します。
- long[] getSelection()
-- 選択されている行のインデックスを取得します。
- boolean isSelectionEmpty()
-- 行が選択されているかどうか調べます。
- boolean isSelectedIndex( [in] long index )
-- 指定した行が選択されているかどうか調べます。
- void selectRow( [in] long index )
-- 指定した行を選択します。
- void addSelectionListener( [in] css.awt.grid.XGridSelectionListener listener )
-- 選択変更リスナーを追加します。
- void removeSelectionListener( [in] css.awt.grid.XGridSelectionListener listener )
-- 選択変更リスナーを削除します。
- long getMinSelectionIndex()
-- 選択されている行の最小のインデックスを返します。
- long getMaxSelectionIndex()
-- 選択されている行の最大のインデックスを返します。

** 作成 [#ya8cb30c]
一般的なダイアログコントロールを動的に作成する時と同じように com.sun.star.awt.grid.UnoControlGridModel サービスをダイアログモデルからインスタンス化します。

  DialogLibraries.loadLibrary("Standard")
  oDialog = CreateUnoDialog( _
    DialogLibraries.getByName("Standard").getByName("Dialog1"))
  oDialogModel = oDialog.getModel()
 
  oGridModel = oDialogModel.createInstance( _
      "com.sun.star.awt.grid.UnoControlGridModel")
 
   with oGridModel
    .PositionX = 10
    .PositionY = 10
    .Width = 190
    .Height = 100
    .Name = "Grid"
    ' adds ColumnModel and GridDataModel
  end with
 
  oDialogModel.insertByName("Grid1", oGridModel)
  oDialog.execute()

ColumnModel および GridDataModel プロパティを正しく設定する前にダイアログにコントロールを追加しようとするとクラッシュします。列および行については下記参照。


** 列 [#ud2cf12c]

3.3では、グリッドコントロールの列を指定するにはコントロールモデルの ColumnModel プロパティに com.sun.star.awt.grid.DefaultGridColumnModel サービスで指定します。また、各列は com.sun.star.awt.grid.GridColumn サービスで指定します。

  oGridCol1 = CreateUnoService("com.sun.star.awt.grid.GridColumn")
  'oGridCol1.setTitle("Col 1")
  oGridCol1.Title = "Col 1"
  
  oGridCol2 = CreateUnoService("com.sun.star.awt.grid.GridColumn")
  'oGridCol2.setTitle("Col 2")
  oGridCol2.Title = "Col 2"
  
  oColModel = CreateUnoService("com.sun.star.awt.grid.DefaultGridColumnModel")
  oColModel.addColumn(oGridCol1)
  oColModel.addColumn(oGridCol2)
 
  oGridModel.ColumnModel = oColModel

列のプロパティ
|プロパティ|型|説明|h
|Title|string|列タイトル|
|ColumnWidth|long|列幅|
|Identifier|any|列識別子|
|PreferredWidth|long|推奨幅|
|MinWidth|long|最小幅|
|MaxWidth|long|最大幅|
|Resizeable|boolean|列幅手動調整可能|
|HorizontalAlign|.style.HorizontalAlignment|水平方向配置|


css.awt.grid.XGridColumnModel

- long getColumnCount()
-- 列数を取得します
- long addColumn( [in] css.awt.grid.XGridColumn column )
-- 列を追加します
-  []css.awt.grid.XGridColumn getColumns()
-- すべての列を取得します
- css.awt.grid.XGridColumn getColumn( [in] long index )
-- 指定したインデックスの列を取得します。
- void setDefaultColumns( [in] long elements )
-- デフォルトの列数を設定します
- css.awt.grid.XGridColumn copyColumn( [in] css.awt.grid.XGridColumn column )
-- 列をコピーします
- long ColumnHeaderHeight
-- attribute. カラムヘッダ高さ

** 行データ [#k7f9a6a5]

 oDataModel = oGridModel.GridDataModel


3.3 では行データは com.sun.star.awt.grid.DefaultGridDataModel サービスに各行をラベル、[]string で追加して各行を表示します。
  oDataModel = CreateUnoService("com.sun.star.awt.grid.DefaultGridDataModel")
  oDataModel.addRow("1", Array("1_1", "1_2"))
  oDataModel.addRow("2", Array("2_1", "2_2"))
 
  oGridModel.GridDataModel = oDataModel

|プロパティ|型|説明|h
|Data|[][]any|表示データ|
|RowHeaderWidth|long|行ヘッダ幅|
|RowHeaders|[]string|行ヘッダデータ|
|RowHeight|long|行高さ|

3.3
css.awt.grid.XGridDataModel インターフェース
- long getRowCount
-- データ行数を取得します。
- void addRow([in] string header, [in] seq<any> data)
-- 行を最後に追加します。
- void removeRow([in] long index)
-- 指定行を削除します。
- void removeAll()
-- 全てのデータ行を削除します。
- void updateCell( [in] long row, [in] long column, [in] any value)
-- 指定したセルのデータを更新します。
- void updateRow([in] long row, [in] seq<long> columns, [in] seq<any> values )
-- 行中の指定した列のデータを更新します。
- void addDataListener([in] css.grid.XGridDataListener listener)
-- リスナーを追加します。
- void removeDataListener([in] css.grid.XGridDataListener listener)
-- リスナーを削除します。

** GridDataModel (3.3) [#f11133ca]
3.3 用です。3.4 では修正されていますし、インターフェースのメソッドが変更されているので利用できません。

独自のデータモデルを利用すると表示するデータとは別にデータ用の値を管理できます。データモデルを作成するには UNO コンポーネントを作成する必要があります。OOo Basic のみではできません。

たとえば、[[ウォッチウィンドウ>OOobbs2/195]] のグリッドデータモデルは独自のもので、内部では行データとしてセルを保持したクラスのインスタンスを管理しています。

以下は PyUNO で基本的なデータモデルを実装したものです。二点ほど問題を回避してあります。

グリッドをダイアログなどに作成するとき、グリッドコントロールのモデルにデータモデルを設定しておき、そこにデータを追加しておきます。その後にグリッドコントロールをダイアログに追加します。そうすると、追加されたときに Data attribute からグリッドに表示するデータを一度に取得されます。API の呼び出し回数が少なくて済みます。

ダイアログにグリッドコントロールが追加されたときに addDataListener メソッドからリスナーが渡されます。その後のグリッドのデータの更新はこのリスナーに broadcast しなければ表示が更新されません。

PyUNO からこのリスナーのメソッドを呼び出そうとすると、メソッドが見えません。下記のコードでは CoreReflection を介して呼び出しています。Java で実装するのであれば問題なく行えます。
また、RowUpdate のときに列インデックスを []long 型を指定して渡さないと []byte などになりうまく動作しません。

#code(python){{
# -*- coding: utf-8 -*-
import uno, unohelper

from com.sun.star.awt.grid import XGridDataModel, GridDataEvent


class GridDataModelBase(unohelper.Base, XGridDataModel, object):
    """ base class for custom data model for grid control."""
    
    RowAdded = 0x1
    RowRemoved = 0x10
    DataChanged = 0x100
    
    def __init__(self, ctx):
        """ corereflection is used to call method of the listeners."""
        self.ctx = ctx
        self.listeners = []
        self._reflection = self.ctx.getServiceManager().createInstanceWithContext(
            'com.sun.star.reflection.CoreReflection', self.ctx)
    
    def _broadcast_added(self, index, header, data):
        """ broadcast about addition. """
        ev = GridDataEvent(self, '', None, None, index, header, data)
        self._broadcast(self.RowAdded, ev)
    
    def _broadcast_removed(self, index):
        """ broadcast removement. """
        ev = GridDataEvent()
        ev.index = index
        self._broadcast(self.RowRemoved, ev)
    
    def _broadcast_changed(self, name, index, old_value, new_value):
        """ broadcast some changes. """
        if name == 'RowUpdated':
            old_value = uno.Any('[]long', old_value)
        ev = GridDataEvent(self, name, old_value, new_value, index, '', ())
        self._broadcast(self.DataChanged, ev)
    
    def _broadcast(self, update_type, ev):
        """ broadcasting """
        method_name = ''
        if update_type == self.RowAdded:
            method_name = 'rowAdded'
        elif update_type == self.RowRemoved:
            method_name = 'rowRemoved'
        elif update_type == self.DataChanged:
            method_name = 'dataChanged'
        else:
            return
        for listener in self.listeners:
            idl_method = self._reflection.getType(listener).getMethod(method_name)
            if idl_method:
                try:
                    idl_method.invoke(listener, (ev,))
                except Exception as e:
                    print(e)
    
    def removeDataListener(self, listener):
        for k, v in enumerate(self.listeners):
            if listener == v:
                del self.listener[k]
    
    def addDataListener(self, listener):
        self.listeners.append(listener)



class CustomGridDataModel(GridDataModelBase):
    """ Customizable data mode. """
    
    def __init__(self, ctx):
        GridDataModelBase.__init__(self, ctx)
        self.RowHeight = 10
        self.RowHeaderWidth = 20
        self._headers = []
        self._rows = []
    
    @property
    def Data(self):
        """ ondemand created data. """
        return tuple([tuple(row) for row in self._rows])
    
    @property
    def RowHeaders(self):
        """ headers """
        return tuple(self._headers)
    
    @RowHeaders.setter
    def RowHeaders(self, value):
        pass
    
    # XGridDataModel
    def getRowCount(self):
        """ number of rows. """
        return len(self._rows)
    
    def addRow(self, header, row):
        """ new row. """
        if isinstance(header, basestring) and isinstance(row, tuple):
            self._headers.append(header)
            self._rows.append(row)
            self._broadcast_added(len(self._rows) - 1, header, row)
    
    def removeRow(self, index):
        """ remove specified row."""
        if 0 <= index < len(self._rows):
            del self._headers[index]
            del self._rows[index]
            self._broadcast_removed(index)
    
    def removeAll(self):
        """ all rows are removed. """
        self._headers = []
        self._rows = []
        self._broadcast_removed(-1)
    
    def updateCell(self, index, column_index, value):
        """ specific individual cell is updated."""
        if 0 <= index < len(self._rows):
            row = list(self._rows[index])
            if 0 <= column_index < len(row):
                row[column_index] = value
                self._rows[index] = row
                self._broadcast_changed('CellUpdated', index, column_index, value)
    
    def updateRow(self, index, columns, values):
        """ a few cells are update in the same row. """
        if isinstance(columns, tuple) and isinstance(values, tuple) and \
            len(columns) == len(values):
            if 0 <= index < len(self._rows):
                row = list(self._rows[index])
                for i, v in zip(columns, values):
                    row[i] = v
                self._rows[index] = tuple(row)
                self._broadcast_changed('RowUpdated', index, columns, values)



def grid_custom_data_model_test(*args):
    """ test case for custom grid data model."""
    ctx = XSCRIPTCONTEXT.getComponentContext()
    smgr = ctx.getServiceManager()
    dp = smgr.createInstanceWithContext(
        'com.sun.star.awt.DialogProvider', ctx)
    
    dlg = dp.createDialog('vnd.sun.star.script:Standard.Dialog1?location=application')
    dlg_model = dlg.getModel()
    
    grid_model = dlg_model.createInstance(
        'com.sun.star.awt.grid.UnoControlGridModel')
    grid_model.setPropertyValues(
        ('Height', 'PositionX', 'PositionY', 'Width'), 
        (100, 3, 3, 100))
    grid_model.ShowColumnHeader = True
    
    # add columns
    oGridCol1 = smgr.createInstanceWithContext(
        "com.sun.star.awt.grid.GridColumn", ctx)
    oGridCol1.Title = "Col 1"
    oGridCol2 = smgr.createInstanceWithContext(
        "com.sun.star.awt.grid.GridColumn", ctx)
    oGridCol2.Title = "Col 2"
    
    oColModel = smgr.createInstanceWithContext(
        "com.sun.star.awt.grid.DefaultGridColumnModel", ctx)
    oColModel.addColumn(oGridCol1)
    oColModel.addColumn(oGridCol2)
    grid_model.ColumnModel = oColModel
    
    
    # create grid data model
    use_default = False
    if use_default:
        # with default grid data model
        dataModel = smgr.createInstanceWithContext(
            "com.sun.star.awt.grid.DefaultGridDataModel", ctx)
    else:
        # using custom one
        #print("CustomGridDataModel is used.")
        dataModel = CustomGridDataModel(ctx)
    
    grid_model.GridDataModel = dataModel
    
    dataModel.addRow("1", ("getByName", "1_2"))
    dataModel.addRow("2", ("2_1", "2_2"))
    
    dlg_model.insertByName('Grid1', grid_model)
    
    # if broadcasting about row addition is correctly sended, 3rd row is shown
    dataModel.addRow("3", ("...", "1_2"))
    
    #dataModel.updateCell(0, 0, 'get?')
    dataModel.updateRow(1, (0, ), ("updated>", ))
    
    dlg.execute()
}}

Reload   New Lower page making Edit Freeze Diff Upload Copy Rename   Front page List of pages Search Recent changes Backup   Help   RSS of recent changes