• ベストアンサー

DataGridのスクロールについて

はじめまして、papillon68と申します。 「Flash MX Professional 2004」を使っています。 その中のコンポーネント「DataGrid」についての質問です。 ◆困っていること DataGridで勝手に選択中のアイテムがスクロールする (htmlにobjectタグでswfファイルを読み込んでいます) ◆したいこと DataGridで勝手に選択中のアイテムがスクロールしないようにしたい ◆現象 1.グリッド中のアイテムを選択する 2.1でマウスの左クリックを押したままFlash(swf)   外にドラッグする 3.再びFlash(swf)内にマウスを持っていく 3のとき [マウス] ------- |     |↑ |グリッド|↑ |     |↑ ------- マウスがグリッドより上(X座標が大きい)に あればグリッド内が勝手に上にスクロール ------- |     |↓ |グリッド|↓ |     |↓ ------- [マウス] マウスがグリッドより下(X座標が小さい)に あればグリッド内が勝手に下にスクロール 実際にはselectedindexなどは変わっておらず、 見た目の選択中(緑のライン)が移動します。 分かりにくいかもしれませんが、解決策や情報を お持ちでしたらご教授お願いできませんでしょうか。 よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • DPE
  • ベストアンサー率85% (666/776)
回答No.3

#2です。 > Flashエリア外(HTML部分)までドラッグし、そこでマウスアップし、 > 再びFlashエリア内にマウスを持っていくとドラッグをしていないのに > 自動スクロールしてしまう ・・・というのは、DataGrid のというより Flash Player そのものの仕様が原因だと思います。 mouseDown と mouseUp 、rollOver と rollOut イベントは対になっています。 例えば mouseUp イベントは、mouseDown イベントが発生した後でなければ発生しません。 Flash がこれらのイベントを検出できるのは、Flash ムービーにフォーカスがある間だけです。 例えばあるムービークリップで、普段はフレーム1、mouseDown でフレーム2を表示し、mouseUp でフレーム1に戻るとします。 Flash 内でマウスのボタンを押して離した時は何の問題もないのですが、Flash 内でボタンを押して Flash の外で離すと、mouseUp イベントが検出されないためにフレーム1には戻りません。 再度 Flash にフォーカスが戻ってきた時は、前回の mouseDown イベントはクリアされてなくなっています。 ですから、一旦 Flash 内でクリックして mouseDown イベントを発生させてからでないと mouseUp イベントは発生しません。 このあたりの事情が原因で” mouseDown と、その対になる mouseUp ”というサイクルが狂い、その瞬間だけ妙な現象が起きるけれど何回かクリックしているうちにいつの間にか正常に戻っていたり、逆にクリックを繰り返したせいで余計におかしくなることがよくあります。 なお、rollOver と rollOut でも、同様の理由により同じ現象が起こります。 *************************** List コンポーネントの自動スクロールは、  ・リスト内でボタンが押されたら、dragScroll 関数を setInterval で一定間隔ごとに実行する  ・マウスのボタンが離されたら、タイマーを削除して自動スクロールを停止する という仕組みになっているようです。 マウスのボタンが離されたかどうかの判定には mouseUp イベントを利用しています。 リスト内で押したボタンを Flash の外で離した場合は mouseUp イベントが検出されず、従って自動スクロールを実現しているタイマーは削除されません。 そのため、スクロールの関数はボタンを離した後も一定時間ごとに呼び出され続けます。 つまり、自動スクロールのためのタイマーがセットされた後、Flash 外でマウスのボタンを離したために mouseUp イベントが検出されずタイマーが削除されなかった場合は、リスト内でクリックしていなくても、前回セットされたタイマーに従ってスクロール関数が一定時間ごとに実行されます。 Flash 外でボタンを離した後で戻ってくるとドラッグしていないのに勝手にスクロールするのは、このためと考えられます。 ----------------------------------------------------------------- Flash の領域外はもう別世界ですし、こればかりはスクリプトや何かでどうこうできる問題ではありません。 ましてコンポーネントが相手では、自分なりの工夫を施すことも困難です。 HTML ページの中では、Flash もページを構成する要素の1つに過ぎません。 マウスの入力情報やフォーカスは Flash だけが独占して管理できるものではないので、バグともどうにもできない仕様とも言い難い問題です。 あとは、Flash 内でクリックして Flash 外で離す・・・なんてひねくれたことをする人が少ないことを祈るくらいでしょうか。 グリッドの上下に隙間を設け、Flash 外でボタンが離される確率を減らすデザインにするのも1つの手だと思います。 *************************** Adobe Exchange という、旧 Macromedia 製品用のコンポーネント等を配布・販売しているページがあります。 このページでは、品物のリストを DataGrid のようなグリッドで表示しています。 こんな現象が起こることを知っていて無用のトラブルやクレームを未然に防ぐためか、Exchange のグリッドはドラッグによるスクロールができないように作られています。  ・Flash Exchange   http://www.adobe.com/cfusion/exchange/index.cfm#loc=en_us&view=sn110&viewName=Flash%20Exchange ↑このグリッドでは行をクリックしても何も起こりません(ハイライトのマーカーもなし)し、クリックしてドラッグアウトしてもスクロールしません。 スクロールはスクロールバーでのみ可能です。 行そのものが選択不可能になっている代わりに項目名が HTML タグ対応のテキストフィールドになっていて、特定の部分をクリックすると対応するコンテンツや制作者のホームページ等に移動します。 このグリッドは Exchange のために作られた特注品であって、Flash に付いている DataGrid コンポーネントとは全くの別物なのかもしれません。 それはさておき、「つまらないトラブルの原因になりかねない自動スクロール機能は、最初から実装しない」という選択肢もアリということなんでしょうね。 ちょっとずるい対策ですが ^^; ちなみに#2でご紹介した enabled を false にし HTML 対応のカスタムセルを作るという力技は、この設計をヒントにしたものです。

papillon68
質問者

お礼

DPE様、度々ご教授下さりありがとうございます。 とても丁寧で分かりやすくご教授頂けましたので よく分かりました。 確かにFlash側でFlash外(HTML部分など)でのことも 制御することは困難ですね^^; 今回の対応としては 自動スクロール機能は有効のままにして DataGridの上下に十分なエリアを用意しようと思います。 本当にありがとうございました。

その他の回答 (2)

  • DPE
  • ベストアンサー率85% (666/776)
回答No.2

バグではなく意図的に作られた機能、要するに仕様と思われます。 ちなみに、一旦 Flash の領域外にドラッグアウトして戻ってきた時に限らず Flash の領域内だけで操作した場合も、リスト内でクリックしてそのままドラッグアウトするとカーソルの位置に応じてリストが自動的にスクロールします。 DataGrid コンポーネントは List コンポーネントを拡張したものです。 グリッドの列は、複数の行を持つ1列のリストである List コンポーネントを必要な分だけ横に並べることで実現しています。 Flash をインストールしたフォルダの言語フォルダ(日本語版なら” ja ”)→ First Run → Classes に、いろいろなクラスの定義ファイルが並んでいます。 コンポーネントを制御するクラスの定義ファイルは” mx ”フォルダにあります。 List コンポーネントを制御する List クラス( List.as )の定義ファイルは、この中の” controls ”フォルダに格納されています。 開けてみますと、クラス宣言部分は次のように書かれています。  class mx.controls.List extends ScrollSelectList entends ScrollSelectList 、つまり ScrollSelectList クラスを継承し拡張したものが List クラスであることが分かります。 そこで、ScrollSelectList クラスの定義ファイル( ScrollSelectList.as )を覗いてみましょう。 List.as の import で指定されているパスの通り、mx → controls のサブフォルダ” listclasses ”にあります。 なお、アプリケーションのインストールフォルダ内のファイルを開いた時は、誤って書き換えたり削除したりしないようご注意ください。 予めコピーを取っておけば万全です。 ScrollSelectList.as の中で、次のような関数が定義されています。 (レイアウトは変更させていただきました)  // interval function that scrolls the list up or down if the mouse goes above or below the list  function dragScroll(Void) : Void  {   clearInterval(dragScrolling);   if (_ymouse<0)   {    setVPosition(__vPosition-1);    selectRow(0, false);    --中略--    dragScrolling = setInterval(this, "dragScroll", scrollInterval);    dispatchEvent({type:"scroll", direction:"vertical", position:__vPosition});   }   else if (_ymouse>__height)   {    var vPos = __vPosition;    setVPosition(__vPosition+1);     --中略--    dragScrolling = setInterval(this, "dragScroll", scrollInterval);    dispatchEvent({type:"scroll", direction:"vertical", position:__vPosition});   }   else   {    dragScrolling = setInterval(this, "dragScroll", 15);   }   updateAfterEvent();  } 1つ1つの細かい意味はさておき、_ymouse でマウスカーソルの位置を見ている点にだけご注目ください。 function の前に書かれているコメントの内容もポイントです。 この関数ではカーソルがリスト内にあるかないかを判断せず、単にカーソルの位置だけをもとにスクロールの処理を行っていると思われます。 List コンポーネントの基準点は左上で、この場合の _ymouse はコンポーネントの基準点を原点とする座標です。 従ってこの if 文は、マウスカーソルが  ・ _ymouse が 0 未満 → コンポーネントの上側にある  ・ _ymouse が __height より大きい → __height とはコンポーネントの高さのこと。つまり、コンポーネントの下側にある  ・それ以外 → コンポーネントの領域内にある と判断し、カーソルの位置に応じてスクロール処理を変えるとの意味になります。 リスト内の項目を選択中にリストの外にカーソルを出すと勝手にスクロールしてしまうのは、おそらくはこの関数の仕業でしょう。 この処理があえて組み込まれているということは、自動的にスクロールする仕組みは List コンポーネントの仕様と考えられます。 先述の通り、DataGrid コンポーネントは内部に複数の List コンポーネントを持っています。 List コンポーネントを制御する List クラスに自動スクロールが組み込まれているのなら、DataGrid コンポーネントにもその特徴が受け継がれます。 ------------------------------------------------------------------- Flash MX 2004 からは SWC ファイルという、配布用のクリップファイル形式が登場しました。 コンパイルが済んでいてそのまま再利用できるコンポーネントのことで、MX 2004 に付属のコンポーネントの多くは SWC ファイルで提供されています。 MX 2004 の先代にあたる Flash MX のコンポーネントはムービークリップシンボルを拡張したものにすぎず、コンポーネントの外観や制御用のスクリプトも、普通のムービークリップシンボルと同様にムービー内で編集できました。 しかし、SWC ファイルで配布されているコンポーネントは既に完成された1つのパッケージになっているので、ムービー内での編集は不可能です。 SWC ファイルはリンケージやスクリプトを利用して外観(スキン)を変更できるように設計されていますが、組み込まれたスクリプトはコンパイルのし直しが必要になるため、変更はできません。 Flash MX 2004 に付属のコンポーネントに関しては、SWC ファイルにする前の元のコンポーネントシンボルを集めた fla ファイル( StandardComponents.fla )が提供されています。 これを使ってコンポーネントを改造、もしくは付属のコンポーネントをもとにして別のコンポーネントを作ることもできます。 コンポーネントに組み込まれたスクリプトの編集も可能ではありますが、この話は複雑になりますのでここでは割愛させていただきます。 コンポーネントのスキンの入れ替えやカスタマイズの第一歩は、このあたりが参考になるかと思います。  ・ Flash デベロッパーセンター   Flash 8 コンポーネントのスキン操作   http://www.adobe.com/jp/devnet/flash/articles/skinning_fl8.html Flash 8 向けですが、MX 2004 でもおおむね同じです。 ********************************* DataGrid の enabled プロパティを false にすると、ドラッグではスクロールできなくなります。 (グリッドに付いているスクロールバーではスクロールできます) DataGrid が無効( enabled プロパティが false )の時は配色が変わりますが、この色は setStyle メソッドで変更可能で、単色の背景色なら何とか対応できます。 (よくある2色のストライプなどがご希望の場合は無理ですが) 問題はセルの選択で、enabled が false の時は選択が全く不能になります。 対策としては、HTML の <A> タグを リスト内のラベルに適用して選択を実現する方法があります。 <A> タグの asfunction オプションを利用すると ActionScript の関数を呼び出せますから、Flash 内のフレームの移動やスクリプトによるテキストフィールドへの出力等も可能です。 ただし、リスト系のコンポーネント( ComboBox ・ List ・ DataGrid など)の項目名に使われているテキストフィールドは、デフォルトでは HTML タグに対応していません。 これらのコンポーネントでは、セルの描画を担当するクラス( CellRenderer API )は外付けになっています。 CellRenderer API はある条件さえ満たしていればよく、自作して取り替えることができます。 つまりリストに表示される項目名は、デフォルトでは無理ですが HTML 対応の描画クラスを作ることでタグによる装飾も可能になるということです。 CellRenderer API はヘルプに一通り説明があるだけで資料があまり見当たらず難しいのですが、デフォルトではできない、いろいろと面白い表示を実現できます。 機会がありましたら研究してみてください。  ・ Flash ドキュメンテーション   コンポーネントリファレンスガイド > CellRenderer API   http://livedocs.macromedia.com/flash/8_jp/main/00003126.html こちらも Flash 8 のヘルプですが、MX 2004 のヘルプにも同様の記述があります。 表示に不都合がありましたら、ヘルプのコンポーネント辞書→ CellRenderer API の項目をご参照ください。 ものすごい力技ではありますけれど、とりあえずこんな方法もあるということで、ご参考までに。 ------------------------------------------------------------------- ご質問文のような現象は DataGrid (の元になっている List コンポーネント)の仕様と考えられるので、setStyle や DataGrid に用意されているプロパティを操作するといった一般的な方法ではまず変更できないものと思われます。 コンポーネントを改造するにしても、まあ・・・ CellRenderer API と HTML タグを駆使してごまかすにしても、資料が乏しく難しい話です。 どうしても何とかしなければならないほど深刻な状況でなければ、仕様ということで妥協するのが無難でしょう。 個人的には、ドラッグでリストがスクロールする機能は便利だと思います。 スクロールバーやスクロールバーの上下のボタンをずっとクリックまたはドラッグしていなければならない(ヒットエリアが小さいので疲れます)よりも、スクロールバーによらずカーソルの位置に応じて自動的に行送りしてくれる機能があった方が便利ですよ。 OSのスクロールバーは、スライダ上でボタンを押してドラッグすると、スライダからカーソルが離れていてもスライダが動いて対象がスクロールします。 スライダはスクロールの対象の大きさによっては小さくなってしまいますから、スライダの上でしか反応しないとなるととても不便です。 掲示板などのテキスト入力エリアでも、ドラッグしながらカーソルをエリア外に出すと自動的にスクロールし、同時に文字を選択範囲にする仕組みになっています。 この手の自動スクロール機能は他のアプリケーションでもよく採用されており、しばしば見かけるものです。 Flash のコンポーネントも、一般的なアプリケーションに倣って意図的にこのような機能を付けたのでしょうから、無理やり抑制する必要はないのかもしれません。

papillon68
質問者

お礼

DPE様、ご回答ありがとうございます。 これほど詳しくご教授くださり、大変感謝しています。 今回の現象はバグではなく、仕様ということが分かりよかったです。 現状で致命的なことが起きているわけではないので このままで使っていこうと思います。 今回の場合、 Grid上でドラッグしたままGrid外にマウスを出したとき(Flashエリア内) 自動スクロールする(ドラッグ中)のはよいのですが、 Flashエリア外(HTML部分)までドラッグし、そこでマウスアップし、 再びFlashエリア内にマウスを持っていくとドラッグをしていないのに 自動スクロールしてしまう という現象でしたのでバグなのではないか?と思ってしまいました。 (Flashエリア内やGrid内でいくらクリックしてもGrid外にマウスを移動させるとドラッグしていなくても自動スクロールします) これもDPE様にご教授頂いた仕様の延長だと思いますのでこのままでいこうと思います。 本当にありがとうございました。

  • suzuko
  • ベストアンサー率38% (1112/2922)
回答No.1

解決策ではありませんが、こんな情報があります。

参考URL:
http://www.adobe.com/jp/support/flash/ts/documents/fl0350.html
papillon68
質問者

お礼

suzuko様 貴重なお時間を割いて情報をご提供頂き、ありがとうございます。 現在は教えて頂いたURLのように選択した行データを テキスト(TextInput)など に表示させています。 コンポーネント自体のバグなのかもしれませんね。 処理にはそれほど影響を与えることではないので、 様子を見てみようと思います。 (Gridの選択中が勝手に移動して混乱を招く恐れや入力中にGrid中が移動していると重くなるといった問題はありますが^^;) 自分でももう少し調べてみようと思います。 恐れ入りますが、また情報がございましたらよろしくお願い致します。 suzuko様ありがとうございました。