tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルVB6 MSHFlexGridについて
記事No15089
投稿日: 2011/01/27(Thu) 00:57
投稿者Wanko
はじめて投稿させていただきます
よろしくお願いします

VB6 MSHFlexGridについてですが、階層を持たせるとデフォルトで展開した状態になると
思いますが、それをたたんだ状態にすることは可能でしょうか?
いろいろ調べてみたのですが見つかりませんでした


それと、DataEnvironmentを使えば楽に階層データをセットできますが、Recordsetで階層を持たせるにはどのようにコードを記述したらよいのでしょうか?
現在検討している使用方法は、

・1分後とにデータを更新する
・ボタンを押すごとにそのボタンに対応したFilterをかける

ここで、FilterをかけるのとRecordsetのWHERE句を変えて接続しなおすのとどちらが確実なのでしょうか。以前DataGridを使用した際データの更新がうまくいかなかったのでおそらくこのControlでも同じなのではないかと思うのですが。
確実な方法があれば特にコードを記述しなくてもいいですが、今後の知識のためにも
教えていただけるとありがたいです

お分かりになる方いらっしゃいましたらご教授のほど、よろしくお願いします

[ツリー表示へ]
タイトルRe: VB6 MSHFlexGridについて
記事No15090
投稿日: 2011/01/27(Thu) 11:44
投稿者魔界の仮面弁士
> VB6 MSHFlexGridについてですが、階層を持たせるとデフォルトで展開した状態になると
> 思いますが、それをたたんだ状態にすることは可能でしょうか?
一括で折りたたむなら CollapseAll メソッド、展開するときは ExpandAll メソッド、
個別に制御する場合は、RowExpanded プロパティです。


> それと、DataEnvironmentを使えば楽に階層データをセットできますが、
使わなくてもセットできます。使った方が楽ですけれどね。


> Recordsetで階層を持たせるにはどのようにコードを記述したらよいのでしょうか?
階層化には SHAPE コマンドを利用します。
DataEnvironment で階層構造のレコードセットを作った場合は、
内部でこれらの SHAPE コマンドが自動的に生成されています。

MDAC SDK より:
http://msdn.microsoft.com/ja-jp/library/cc408253.aspx

MSKB より:
http://support.microsoft.com/kb/189657/en-us
http://support.microsoft.com/kb/185425/
http://support.microsoft.com/kb/308045/ja

DataEnvironment を使った場合には集計元のデータベースが必要ですが、
これは DataEnvironment 側の制限です。
http://support.microsoft.com/kb/193347/ja

SHAPE コマンドを直接作りこんだ場合、データベース無しで階層化することもできます。
とはいえ通常は、データベースと DataEnvironment を使った方が楽ですけれどね。


なお下記では DB 無しで実行できるよう、自前でレコードセットを構築しています。

Option Explicit
Private WithEvents mrs As ADODB.Recordset

Private Sub Form_Load()
    Set mrs = CreateDummy()
    MSHFlexGrid1.AllowUserResizing = flexResizeColumns
    MSHFlexGrid1.BandDisplay = flexBandDisplayHorizontal
    Set MSHFlexGrid1.DataSource = mrs

    '第1バンド("所属"シェイプ)は表示しない
    MSHFlexGrid1.BandExpandable(1) = False
    MSHFlexGrid1.ColWidth(-1, 1) = 0
    
    '"所属名"列の幅を 150 ピクセルにする
    MSHFlexGrid1.ColWidth(2, 0) = 150 * Screen.TwipsPerPixelX
    
    
    '第0バンド(最上位階層)をすべて折りたたむ
    MSHFlexGrid1.CollapseAll 0

    '4行目、2行目のデータを開く
    MSHFlexGrid1.Row = 4
    MSHFlexGrid1.RowExpanded = True
    
    MSHFlexGrid1.Row = 2
    MSHFlexGrid1.RowExpanded = True
    
    '「展開・折り畳み」が行われると、その分だけ
    'Col/Row/ColSel/RowSelの指定がずれる点に注意。
End Sub

'Offline で階層Recordsetを作成
Private Function CreateDummy() As ADODB.Recordset
    Dim cn As ADODB.Connection
    Set cn = New ADODB.Connection
    cn.Provider = "MSDataShape"
    cn.Properties("Data Provider").Value = "none"
    cn.Open
    
    Dim rs1 As ADODB.Recordset
    Dim rs2 As ADODB.Recordset
    Dim rs3 As ADODB.Recordset
    
    Set rs1 = New ADODB.Recordset
    rs1.Open GetSampleQuery(), cn, adOpenStatic, adLockBatchOptimistic
    rs1.AddNew
    Set rs2 = rs1.Collect("所属")
    rs2.AddNew
    Set rs3 = rs2.Collect("社員")
    rs2.CancelUpdate
    rs1.CancelUpdate
    
    rs1.AddNew Array("部署ID", "部署名"), Array(3000, "総務部")
    rs1.AddNew Array("部署ID", "部署名"), Array(3100, "総務部庶務課")
    rs1.AddNew Array("部署ID", "部署名"), Array(3101, "総務部庶務課庶務係")
    rs1.AddNew Array("部署ID", "部署名"), Array(3102, "総務部庶務課広報係")
    rs1.AddNew Array("部署ID", "部署名"), Array(3200, "総務部経理課")
    rs1.AddNew Array("部署ID", "部署名"), Array(3201, "総務部経理課予算係")
    rs1.AddNew Array("部署ID", "部署名"), Array(3202, "総務部経理課会計係")
    rs1.AddNew Array("部署ID", "部署名"), Array(3203, "総務部経理課財務係")

    rs2.AddNew Array("部署ID", "社員ID"), Array(3100, 1000)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3101, 1000)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3101, 1001)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3101, 1002)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3101, 1003)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3102, 1000)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3102, 1004)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3102, 1005)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3102, 1006)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3102, 1007)
    rs2.AddNew Array("部署ID", "社員ID"), Array(3200, 1010)

    rs3.AddNew Array("社員ID", "社員名"), Array(1000, "円谷課長")
    rs3.AddNew Array("社員ID", "社員名"), Array(1001, "朝井係長")
    rs3.AddNew Array("社員ID", "社員名"), Array(1002, "亀井")
    rs3.AddNew Array("社員ID", "社員名"), Array(1003, "東野")
    rs3.AddNew Array("社員ID", "社員名"), Array(1004, "長野係長")
    rs3.AddNew Array("社員ID", "社員名"), Array(1005, "仲澤")
    rs3.AddNew Array("社員ID", "社員名"), Array(1006, "大道")
    rs3.AddNew Array("社員ID", "社員名"), Array(1007, "寺内")
    rs3.AddNew Array("社員ID", "社員名"), Array(1010, "星野課長")
    
    rs1.MoveFirst
    Set CreateDummy = rs1
End Function

Private Function GetSampleQuery() As String
    Dim S As String
    S = ""
    S = S & vbCrLf & "SHAPE APPEND"
    S = S & vbCrLf & "  New adInteger AS 部署ID,"
    S = S & vbCrLf & "  New adChar(25) AS 部署名,"
    S = S & vbCrLf & "  ("
    S = S & vbCrLf & "    (SHAPE APPEND"
    S = S & vbCrLf & "      NEW adInteger AS 部署ID,"
    S = S & vbCrLf & "      NEW adInteger AS 社員ID,"
    S = S & vbCrLf & "      ("
    S = S & vbCrLf & "        (SHAPE APPEND"
    S = S & vbCrLf & "          NEW adInteger AS 社員ID,"
    S = S & vbCrLf & "          NEW adChar(20) AS 社員名"
    S = S & vbCrLf & "        ) AS 社員 RELATE 社員ID TO 社員ID"
    S = S & vbCrLf & "      )"
    S = S & vbCrLf & "    ) AS 所属 RELATE 部署ID TO 部署ID"
    S = S & vbCrLf & "  ),"
    S = S & vbCrLf & "  COUNT(所属.社員ID) AS 配属人数"
    GetSampleQuery = S
End Function


> ここで、FilterをかけるのとRecordsetのWHERE句を変えて接続しなおすのとどちらが確実なのでしょうか。
他のユーザーによって元データが変更される可能性がある場合は、
再度問い合わせた方が良いでしょう。切断している場合は再接続も必要です。
http://support.microsoft.com/kb/213856/ja

データの変更が無い場合は、Filter によるクライアント側の処理だけでも十分ですが
Filter をかけなおす場合は、経験則的に
 『Filter解除 → 最上位階層をMoveFirst → Filter再設定』
という手順を踏んだ方が安全なようです。

# 多くの場合はそのままセットするだけで反映されるのですが、何故か MoveFirst
# してからでないと反映されない状況を経験しています。原因は不明ですが。


> 以前DataGridを使用した際データの更新がうまくいかなかったので
> おそらくこのControlでも同じなのではないかと思うのですが。
そもそも MS(H)FlexGrid は更新機能を備えていません。表示専用のコントロールです。

プログラムからセルの内容を書き換えたとしても 階層 Recodset の内容は変更しませんし、
バインド後に階層 Recodset の内容を書き換えても MSHFlexGrid の表示は変化しません。

Recodset の内容が変化した場合は、DataSource を再度セットする必要があります。
(構造が変化する場合は、ClearStructure の呼び出しも必要です)


> お分かりになる方いらっしゃいましたらご教授のほど、よろしくお願いします
http://www.tt.rim.or.jp/~rudyard/torii009.html

[ツリー表示へ]
タイトルご教示ありがとうございます^^
記事No15091
投稿日: 2011/01/28(Fri) 09:12
投稿者wanko
詳しく教えていただきありがとうございます
やはり更新は無理なのですね
ではRecordsetで作成しようと思います

以前DataGridで更新しようとして失敗したときの状況をもう少し詳しくお伝えしますと、
DataEnvironmentで作成したのですけれど、更新ができない(方法がよくわからなかった)ために一度接続を閉じ出から再接続というものを試みていました。しかしこれでも更新されるときとされないときがあったため、MoveLast→MoveFirstとして一度全Recordにアクセスしてみる、という方法も試しましたがやはり同様でした。
Microsoftで検索した結果、確か更新に弱い、というような内容のきさいがあったと記憶しています。それがDataGridのことだったかDataEnvironmentのことだったかは忘れてしまいましたが^^;
それ以後DataEnvironmentの使用を避けているという状況を考えるとおそらくこちらなのだと思います。
実際にはDataEnvironmentと更新という関係に何か問題があるのでしょうか?

[ツリー表示へ]
タイトルRe: ご教示ありがとうございます^^
記事No15093
投稿日: 2011/01/28(Fri) 13:11
投稿者魔界の仮面弁士
> Microsoftで検索した結果、確か更新に弱い、というような内容のきさいがあったと記憶しています。
是非、情報ソースを思い出して下さい。どの話の事か分からないので…。


> それがDataGridのことだったかDataEnvironmentのことだったかは忘れてしまいましたが^^;
その話と関係あるかどうかは分かりませんが:

・Microsoft.Jet.OLEDB.4.0 の場合、DataGrid に表示するためには
 クライアントカーソルモードを利用するか、もしくは、
 サーバーカーソルモードで IRowsetIdentity を有効にする必要がある。
 http://support.microsoft.com/kb/224192/ja

・MSDAORA を使って接続する場合、サーバーカーソルモードで接続すると
 ReadOnly カーソルで開かれてしまう。
 http://dobon.net/vb/bbs/log3-40/24416.html
 http://www.gizcollabo.jp/vbtomo/log/archive/vbdatabase_1138_0.html


> 実際にはDataEnvironmentと更新という関係に何か問題があるのでしょうか?
関係無いと思いますよ。
リードオンリーカーソルモードで開いていたとか、更新をサポートしないプロバイダで
処理しようとしていた…という事はありませんか?

DataEnvironment は Connnection/Command/Recordset を管理しやすくするための
ツールに過ぎず、利用できる機能は ADO のそれと基本的に変わらないはずです。

逆に言えば、ADO や OLEDB 側の制限はそのまま受けることになるでしょう。
# たとえば、Microsoft.JET.OLEDB.4.0 で CSV ファイルを取り扱うような場合、
# 読み取りや追記はできるが、データの更新はサポートされていないという話とか。

[ツリー表示へ]
タイトルソースの提示です
記事No15094
投稿日: 2011/01/28(Fri) 13:18
投稿者wanko
> > Microsoftで検索した結果、確か更新に弱い、というような内容のきさいがあったと記憶しています。
> 是非、情報ソースを思い出して下さい。どの話の事か分からないので…。

マイクロソフト サポートオンラインより:
http://support.microsoft.com/kb/191457/ja

僕の解釈の間違いでしたらすみません

[ツリー表示へ]
タイトルRe: ソースの提示です
記事No15096
投稿日: 2011/01/28(Fri) 15:01
投稿者魔界の仮面弁士
> http://support.microsoft.com/kb/191457/ja

ありがとうございます。
確かにこれでは、DataEnvironment の利用は避けた方が無難かも知れませんね。

使うとしても、デザイン時に MSHFlexGrid や DataGrid の設定を行うための
構造取得ツールとしてのみ利用するぐらいでしょうか。


> 僕の解釈の間違いでしたらすみません

私の方が、「更新」と聞いて「Recordset の編集内容を DB 側に書き戻す」の意味で
捕らえてしまったのですが、そうではなく「DB 側に Requery で問い合わせ直した場合」の
画面表示上の話だったのですね。


一応、Knowledge Base の内容に補足しておくと:

(1)
DataEnvironment 自体を DataSource にバインドしていた場合、
Recordset が更新されたことをコントロール側に伝える手段が無いため、
今回のような現象が発生します。
(ただし、Recordset の Requery メソッド自体は正常に動作しています)


(2)
その Knowledge Base 中では、DataEnvironment を使わずに
 Set DataGrid1.DataSource = DataEnvironment1.rsCustomers
で連結すれば、Requery したあとの再バインドが不要と書かれていますが、
先の投稿(15090) にも書いたように MSHFlexGrid が相手の場合はその限りではなく、
やはり再バインドしなおさないと画面表示に反映されません。
>> Recodset の内容が変化した場合は、DataSource を再度セットする必要があります。


(3)
手順通りに作成した場合、Customers のプロパティは
 DataEnvironment1.rsCustomers.CursorLocation = adUseClient
 DataEnvironment1.rsCustomers.LockType = adLockReadOnly
 DataEnvironment1.rsCustomers.CursorType = adOpenStatic
のように定義されることになります。
いわゆる「読み込み専用のクライアントカーソル」です。

そのため、cmdModifyData ではわざわざ UPDATE SQL を用いて
データを更新していますが、Customers タブで
 カーソルの位置 = クライアント側
 ロックの種類 = オプティミスティック
を指定しておけば、Recordset を直接変更する事も可能ですし、
TextBox や DataGrid を直接書き換えることもできます。

ただしこの場合、UPDATE 文で更新した後、DataSource を再セットせずに
TextBox を書き換えてしまうと、同時更新制御の関係から
 『行が見つからなかっため、更新できません。列の値は
  最後に読み込まれた後で変更された可能性があります。』
のエラーになってしまう可能性があります。

ただし同時更新制御の問題は、DataEnviroment を使わなかった場合にも起こりえます。
(ADO には同時更新制御のための機能も一応ありますが、ここでは触れずにおきます)

[ツリー表示へ]
タイトルRe^2: ソースの提示です
記事No15097
投稿日: 2011/01/29(Sat) 10:53
投稿者wanko
いえいえ、僕の表現が悪かったです

週明けにDBに接続するのが楽しみです
ありがとうございました

[ツリー表示へ]
タイトルDB利用時のShapeコマンドについて
記事No15092
投稿日: 2011/01/28(Fri) 12:58
投稿者wanko
前述サイトより
SQL=SHAPE  {select * from customers}
       APPEND ({select * from orders} AS rsOrders
           RELATE customerid TO customerid)

となっています
ここで質問なのですが、親と子のSQL文はConnectionが確定していません
これを  rs.open SQL としたとしてこのあとどのようにしてDBに接続されるのでしょうか?
実際使用する場合はそれぞれにRecordsetを当てるのでしょうか?
下に例を示します

'--------------------------------------------------------------------------
Public Function

    cnShape.Provider = "MSDataShape"
    cnShape.Properties("Data Provider").Value = "none"
    cnShape.Open

    rs1.Open GetShape(), cnShape, adOpenStatic, adLockBatchOptimistic

End Function
'--------------------------------------------------------------------------
Public Function GetShape()

    strSQL1 = "select * from ..."
    strSQL2 = "select * from ..."
    
    GetShape = "Shape (" & strSQL1 & ") " & _
               "Append((" & strSQL2 & ")  as AAA " & _
               "RELATE aaa = aaa"
End Function

*各変数の宣言は省略しています

'-----------------------------------------------------------------------

この例ではstrSQL1,2ともにConnectionが設定されていません
どちらのConnectionもDB1というDataBaseに接続するとして、上記よりrs1のConnectionはcnShapeです。そこにどうやってDB1をConnectするのでしょうか?

よろしくおねがいします

[ツリー表示へ]
タイトルDB利用時のShapeコマンドについて【解決】
記事No15095
投稿日: 2011/01/28(Fri) 13:45
投稿者wanko
こういうことだったのですね

Dim cnn As New ADODB.Connection
cnn.Provider = "MSDataShape"
cnn.Open "Data Provider=SQLOLEDB;User Id=sa;Password=;Database=Northwind"

http://msdn.microsoft.com/ja-jp/library/cc364060.aspx

とうことは同一DBの同一インスタンスでのみ使用可能ということですね
リンクサーバー、シノニムで対応すればよいわけですが・・・

いろいろありがとうございました

[ツリー表示へ]