C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: Treeviewでのチェックボックスについて


(過去ログ 135 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■79840 / inTopicNo.1)  Treeviewでのチェックボックスについて
  
□投稿者/ バイク (1回)-(2016/05/22(Sun) 15:55:55)

分類:[.NET 全般] 

2016/05/22(Sun) 15:58:24 編集(投稿者)

VB.NET treeviewでのチェックボックスについて

Win7で、vb.net2010を使っています

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

'チェックボックス
TreeView1.CheckBoxes = True
'Cドライブのみ
Dim root As String = "C:\"

Dim rootNode As New TreeNode(root)
TreeView1.Nodes.Add(rootNode)

For Each dir As String In Directory.GetDirectories(root)
rootNode.Nodes.Add(Path.GetFileName(dir))
Next

rootNode.Expand() ' ルート・ノードの展開(子ノードの表示)
End Sub

Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect

For Each dir As String In Directory.GetDirectories(e.Node.FullPath)
e.Node.Nodes.Add(Path.GetFileName(dir))
Next
End Sub

フォームにTreeviewを張り付けています
上記で、Cドライブのフォルダ一覧を
チェックボックス付で表示させています

現状、チェックボックスをクリックしたら、
親フォルダだけにしかチェックが入りません
親フォルダでチェックボックスをクリックしたら、
子フォルダや孫フォルダ等にチェックが入るようにしたいと
思っております

そして親フォルダのチェックを外した時、子フォルダや孫フォルダのチェックが外れる様にするにはどのようにすれば良いでしょうか?

例えばC:\ABC があるとします
ABCを親フォルダとします

ABCのチェックボックスをクリックしたら、ABCの配下の
全てのフォルダのチェックボックスにチェックが
入るようにしたいです

そして親フォルダのチェックボックスを外した時、
子フォルダ等のチェックボックスが外れる様にしたいのですが、
どのようにすれば良いでしょうか?


長文を最後まで読んで下さりありがとうございました
ご教授下さい


引用返信 編集キー/
■79841 / inTopicNo.2)  Re[1]: Treeviewでのチェックボックスについて
□投稿者/ 魔界の仮面弁士 (716回)-(2016/05/22(Sun) 22:43:57)
No79840 (バイク さん) に返信
> Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect

これだと、同じフォルダーを選択するたびに
子フォルダーが重複追加されてしまいますよ。


> 親フォルダでチェックボックスをクリックしたら、
> 子フォルダや孫フォルダ等にチェックが入るようにしたいと
> 思っております

AfterCheck イベントを使うとか。ダブルクリック時に注意。

Imports System.IO

Public Class Form1
    'ノードがチェックされたら、子をチェックする
    Private Sub TreeView1_AfterCheck(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterCheck
        Dim b As Boolean = e.Node.Checked
        For Each n As TreeNode In e.Node.Nodes
            'イベントの連鎖により、孫以降の子孫に対しても処理される
            n.Checked = b
        Next
    End Sub

    Private Sub SetChildren(baseNode As TreeNode)
        For Each subDir As String In Directory.GetDirectories(baseNode.FullPath)
            Dim n As TreeNode = baseNode.Nodes.Add(Path.GetFileName(subDir))
            n.Checked = baseNode.Checked
            Try
                If Directory.GetDirectories(subDir).Any() Then
                    n.Nodes.Add("NUL")  'サブフォルダがある場合に[+]を付与するためのダミー
                End If
            Catch ex As Exception
            End Try
        Next
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
        treeViewSubClass = New IgnoreDoubleClickSubClass()
        treeViewSubClass.AssignHandle(TreeView1.Handle)

        TreeView1.CheckBoxes = True

        Dim rootNode As TreeNode = TreeView1.Nodes.Add("C:", "C:\")
        SetChildren(rootNode)
        rootNode.Expand()
    End Sub

    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        treeViewSubClass.ReleaseHandle()
        treeViewSubClass = Nothing
    End Sub

    Private Sub TreeView1_BeforeExpand(sender As Object, e As TreeViewCancelEventArgs) Handles TreeView1.BeforeExpand
        If e.Node.Nodes(0).Text = "NUL" Then
            e.Node.Nodes.RemoveAt(0)
            SetChildren(e.Node)
        End If
    End Sub

#Region "ダブルクリック対策(KB2781622)"
    Private Class IgnoreDoubleClickSubClass
        Inherits NativeWindow
        Protected Overrides Sub WndProc(ByRef m As Message)
            Const WM_LBUTTONDBLCLK As Integer = &H203
            If m.Msg = WM_LBUTTONDBLCLK Then
                m.Result = IntPtr.Zero
            Else
                MyBase.WndProc(m)
            End If
        End Sub
    End Class

    Private treeViewSubClass As IgnoreDoubleClickSubClass
#End Region

End Class

引用返信 編集キー/
■79842 / inTopicNo.3)  Re[2]: Treeviewでのチェックボックスについて
□投稿者/ 魔界の仮面弁士 (717回)-(2016/05/23(Mon) 12:05:00)
No79841 (魔界の仮面弁士) に追記
> #Region "ダブルクリック対策(KB2781622)"

これだと、ダブルクリックでの展開/折り畳みが阻害されてしまうので、
チェックボックス以外のダブルクリックは通過させるように修正してみました。


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As EventArgs) Handles MyBase.Shown
  '==> 修正
  treeViewSubClass = New IgnoreDoubleClickSubClass(TreeView1)
  '<== 修正

  TreeView1.CheckBoxes = True

  Dim rootNode As TreeNode = TreeView1.Nodes.Add("C:", "C:\")
  SetChildren(rootNode)
  rootNode.Expand()
End Sub



#Region " No79841 のクラスを差し替え"
Private Class IgnoreDoubleClickSubClass
  Inherits NativeWindow

  Private tv As TreeView
  Public Sub New(ByVal tv As TreeView)
    Me.tv = tv
    MyBase.AssignHandle(tv.Handle)
  End Sub

  Protected Overrides Sub WndProc(ByRef m As Message)
    Const WM_LBUTTONDBLCLK As Integer = &H203
    If m.Msg = WM_LBUTTONDBLCLK Then
      Dim p = tv.PointToClient(Cursor.Position)
      Dim h = tv.HitTest(p)
      If h.Location = TreeViewHitTestLocations.StateImage Then
        m.Result = IntPtr.Zero
      Else
        MyBase.WndProc(m)
      End If
    Else
      MyBase.WndProc(m)
    End If
  End Sub
End Class
#End Region
引用返信 編集キー/
■79850 / inTopicNo.4)  Re[3]: Treeviewでのチェックボックスについて
□投稿者/ バイク (2回)-(2016/05/23(Mon) 17:55:27)
魔界の仮面弁士様

詳しい回答ありがとうございます

昨日提示いただいたコードで何も問題ございませんでしたが、変更したほうがよろしいでしょうか?

今しがた下記コードを変更をしたのですが、

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

End Sub の部分を回答いただいた通りにしました

#Region "ダブルクリック対策(KB2781622)"

#End Region の部分を回答いただいた通りにしました

treeViewSubClassは宣言されていません。アクセスできない保護レベルになっています。と表示されてしまいます。

どのようにしたら良いでしょうか?
ご教授頂けますと助かります。

引用返信 編集キー/
■79851 / inTopicNo.5)  Re[4]: Treeviewでのチェックボックスについて
□投稿者/ 魔界の仮面弁士 (720回)-(2016/05/23(Mon) 18:32:13)
No79850 (バイク さん) に返信
> treeViewSubClassは宣言されていません。

クラスだけでなく、

 Private treeViewSubClass As IgnoreDoubleClickSubClass

のフィールド変数宣言まで削ってしまったとか?


> 昨日提示いただいたコードで何も問題ございませんでしたが、変更したほうがよろしいでしょうか?

その判断はお任せします。

提示のコードをそのまま丸写しするわけではなく、各行を理解した上で
自身のアプリに組み入れるのであれば、どちらを選択して頂いても良いと思います。


No79841 の場合、一切のダブルクリック操作が無効になります

No79842 の場合、チェックボックス部のダブルクリックは無視しますが、
ラベル部のダブルクリックは有効です(サブフォルダーの展開/折り畳みになる)。




投稿ついでに、先の修正箇所の意図を説明:

>> 親フォルダでチェックボックスをクリックしたら、
>> 子フォルダや孫フォルダ等にチェックが入るようにしたいと
>> 思っております
>
> AfterCheck イベントを使うとか。ダブルクリック時に注意。

質問への回答としては、上記の一文だけで良かったのかとも思いますが、
ダブルクリックへの対策が必要であったため、今回はサンプルコードで
回答しました。(手抜き箇所もありますので、適宜修正しておいてください)

なお、この TreeView を複数個所で使う予定がある場合は、
私のサンプルのように NativeWindow を用いて対処するのではなく、
KB2781622 のように、TreeView 自体をカスタマイズした方が良いでしょう。
https://support.microsoft.com/ja-jp/kb/2781622



>> Dim root As String = "C:\"
>> Dim rootNode As New TreeNode(root)
>
> Dim rootNode As TreeNode = TreeView1.Nodes.Add("C:", "C:\")

各ノードは、既定で "\" で繋がれますが、No79840 にある当初のコードでは、
 C:\Program Files\Common Files
ではなく、
 C:\\Program Files\Common Files
のように、ルート部で "\\" となってしまうため、キーを "C:\" から "C:" に変更しています。



>> For Each dir As String In Directory.GetDirectories(root)
>
> For Each subDir As String In Directory.GetDirectories(baseNode.FullPath)

上記では、変数名を dir から subDir へと変更しています。
これは、VB の標準関数「Dir()」との混同を避けるためです。

…元の変数名でも間違いというわけでは無いのですけれどね。



>> Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect

先述したように、"AfterSelect" や "BeforeSelect" を使うと、
選択するたびに呼び出されてしまい、子フォルダが重複登録されてしまいます。

回避策としては:
 (案1) 子ノードを全削除し、あらためて再登録する
 (案2) 一度生成された子ノードは、再表示しないようにする
などがあります。

案1 の場合、TreeView 表示後に作成されたフォルダーも表示できるメリットがありますが、
そのかわり、CheckBox の on/off 状態を保持するのが面倒なため、今回は 案2 を選択しました。
(具体的には、NUL という名の子ノードがあるかどうかで判断させています)


この修正に伴い、サブフォルダーの探索タイミングを、
「選択時」イベントから「展開時」イベントに変更しています。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -