質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

5794閲覧

【VC#】TreeNodeとFlowLayoutPanelを使用してWin7エクスプローラを再現したい

monchiken

総合スコア13

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

2クリップ

投稿2015/01/12 11:19

Javaを少しやってオブジェクト指向がわかりはじめた位の初心者です。

今回はMicrosoft Visual Studio Express 2013 for Windows Desktopを使用して
Windows 7 のエクスプローラーの再現をC#で試みています。

そこでTreeNodeの操作の仕方が良く分からず、早くから詰まってしまいました。
以下、再現出来なかったことをできるようにするためには、ソースのどの部分を直せばいいのでしょうか?

■今のところ再現したいこと
Windows7のフォルダツリーとアドレスバーの動作(と、選択フォルダ配下画像の表示)

■再現出来たこと
フォルダツリー表示(TreeNode)
アドレスバーの表示(FlowLayoutPanelにフォルダ名が表示されるButtonをAdd)
フォルダツリーのみでディレクトリ変更(上の階層に行く)、アドレスバー更新
画像の表示

■再現出来なかったこと(今回解決したいこと)
フォルダツリーでディレクトリ変えた後アドレスバーでディレクトリ変更(上の階層に行く)
→System.IndexOutOfRangeException発生
その前には以下のことをしています。Findしても検索結果がゼロになってしまいます。
◯押されたButtonのTextプロパティを取得
(アドレスバーにButtonを追加する時、Textプロパティにフルパスを入れておいた)
◯取得したフルパスをキーにフォルダツリーからNodeを検索
→ここで検索結果ゼロ
◯検索されたNodeをSelectedNodeに追加しようとするも、配列に何もないため例外発生
→TreeNodeのSelectedNodeプロパティにTreenodeを代入してもnullのまま
「folderTree.SelectedNode」で現在TreeNodeで選択されているNodeを取得し
上にさかのぼったりする処理をしたいのですが、
「folderTree.Nodes.Clear();」で「folderTree.SelectedNode」がnullになることに気づき、
以下処理を試してみましたが、folderTree.SelectedNodeは更新されずnullのままでした。

TreeNode tmp = folderTree.SelectedNode; //現在のSelectedNodeを一時保管 folderTree.Nodes.Clear(); //TreeNodeを初期化→folderTree.SelectedNodeがnull updateFolderTree(currentSelectedNode); //TreeNode追加 folderTree.SelectedNode = tmp; //一時保管していたNodeを再格納

■エラーが起きる具体例
①起動時のフォルダツリーの状態

  • C:\
  • D:\

②フォルダツリーで「C:\」「ProgramFiles」と選択

③アドレスバーは「[C:] [Program Files] [ProgramFiles配下のフォルダ]」と表示され
フォルダツリーが以下の状態になる

  • C:\
  • Program Files
  • ProgramFiles配下のフォルダ
  • C:\配下の他フォルダ
  • D:\

④アドレスバーの[C:] [Program Files] [TortoiseSVN]のいずれかを押す
→UpdateTreeViewイベントが発生
→System.IndexOutOfRangeExceptionが発生して処理中断

■ソース
※プロパティの名前
folderTree…フォルダツリー
addressBar…アドレスバー
picturePanel…サムネイル表示画面
processBar…プロセスバー

lang

1public partial class Form1 : Form 2{ 3 private String currentDirectoryPath; 4 private TreeNode folderTreeNode; 5 6 public Form1() 7 { 8 InitializeComponent(); 9 initialFolderTree(); 10 } 11 12 #region Event 13 private void folderTree_BeforeExpand(object sender, TreeViewCancelEventArgs e) 14 { 15 updateFolderTree(e.Node); 16 } 17 18 private void folderTree_AfterSelect(object sender, TreeViewEventArgs e) 19 { 20 updateFolderTree(e.Node); 21 } 22 private void update_formSize(object sender, EventArgs e) 23 { 24 Size size = Form1.ActiveForm.Size; 25 split_middle.Size = new Size(size.Width, size.Height - 80); 26 } 27 28 private void picturePanel_enterMouse(object sender, EventArgs e) 29 { 30 picturePanel.Focus(); 31 } 32 private void folderTree_enterMouse(object sender, EventArgs e) 33 { 34 folderTree.Focus(); 35 } 36 /* 37 * ツリービューの更新(アドレスバーのButtonを押下した際に発生) 38 */ 39 private void folderTree_Update(Object sender, EventArgs e) 40 { 41 TreeNode currentSelectedNode = null; 42 //アドレスバーを連続で操作するとSelectedNodeがnullになりNullReferenceExceptionが発生 43 if (folderTree.SelectedNode != null) 44 { 45 currentSelectedNode = folderTree.SelectedNode; 46 } 47 else 48 { 49 currentSelectedNode = folderTreeNode; 50 } 51 52 initialFolderTree(); 53 updateFolderTree(currentSelectedNode); 54 55 //以下処理をやってもSelectedNodeは変わらずnullになる 56 //TreeNode tmp = folderTree.SelectedNode; //現在のSelectedNodeを一時保管 57 //folderTree.Nodes.Clear(); //TreeNodeを初期化 58 //updateFolderTree(currentSelectedNode); //TreeNode追加 59 //folderTree.SelectedNode = tmp; //一時保管していたNodeを再格納 60 // 61 62 String key = currentDirectoryPath.ToString().Replace("\\", "\"); 63 //↓↓↓↓↓↓↓↓↓↓↓↓↓↓エラー発生場所↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 64 //TreeNode[] nextSelectedNode = folderTree.Nodes.Find(key, true); だとnameプロパティで探す→検索結果はゼロ 65 //※以下サイトを参考にTextプロパティで探せるようにしても検索結果はゼロ 66 //「Is there a method for searching for TreeNode.Text field in TreeView.Nodes collection?」 67 //(http://stackoverflow.com/questions/12388249/is-there-a-method-for-searching-for-treenode-text-field-in-treeview-nodes-collec) 68 TreeNode[] nextSelectedNode = folderTreeNode.Nodes.Cast<TreeNode>().Where(r => r.Text == key).ToArray(); 69 folderTree.SelectedNode = nextSelectedNode[0]; 70 //↑↑↑↑↑↑↑↑↑↑↑↑↑↑エラー発生場所↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 71 72 String beforePath = currentDirectoryPath.ToString().Replace("\\", "\"); 73 Button clickedButton = sender as Button; 74 String afterPath = clickedButton.Name.ToString().Replace("\\", "\"); 75 76 updateAddressBar(afterPath); 77 78 if (beforePath != null) 79 { 80 81 String diff = beforePath.Replace(afterPath, ""); 82 int depth = diff.Split('\').Count(); 83 for (int i = 0; i < depth; i++) 84 { 85 if (folderTree.SelectedNode == null) 86 { 87 folderTree.SelectedNode = currentSelectedNode; 88 } 89 folderTree.SelectedNode = folderTree.SelectedNode.Parent; 90 } 91 folderTree.Focus(); 92 } 93 } 94 #endregion 95 96 97 /* 98 *フォルダツリーの初期化(ドライブ一覧) 99 */ 100 private void initialFolderTree() 101 { 102 folderTree.Nodes.Clear();//SelectedNodeがクリアされる 103 104 foreach (String driveName in Environment.GetLogicalDrives()) 105 { 106 folderTreeNode = new TreeNode(driveName, 0, 0); 107 folderTreeNode.Name = driveName; 108 folderTree.Nodes.Add(folderTreeNode); 109 folderTreeNode.Nodes.Add("..."); 110 } 111 folderTree.Sorted = true; //文字列順に自動Sort 112 } 113 114 115 /* 116 *選択されたノードに応じてフォルダツリーを更新 117 */ 118 private void updateFolderTree(TreeNode currentNode) 119 { 120 121 //folderTreeNode = currentNode; 122 String nodePath = null; 123 try 124 { 125 nodePath = currentNode.FullPath; 126 currentDirectoryPath = nodePath; 127 } 128 catch(InvalidOperationException e) 129 { 130 nodePath = currentDirectoryPath; 131 } 132 currentNode.Nodes.Clear(); 133 134 if (System.IO.Directory.Exists(nodePath)) 135 { 136 DirectoryInfo directoryInfo = new DirectoryInfo(nodePath); 137 138 try 139 { 140 DirectoryInfo[] directoryList = directoryInfo.GetDirectories(); 141 if (directoryList.Count() != 0) 142 { 143 DirectoryInfo[] directoryInfoList = directoryInfo.GetDirectories(); 144 String root = currentDirectoryPath.ToString().Substring(0, 1); 145 foreach (DirectoryInfo childDirectoryInfo in directoryInfoList) 146 { 147 folderTreeNode = new TreeNode(childDirectoryInfo.Name); 148 folderTreeNode.Name = childDirectoryInfo.FullName; 149 currentNode.Nodes.Add(folderTreeNode); 150 folderTreeNode.Nodes.Add("..."); 151 } 152 } 153 folderTreeNode = currentNode; 154 155 updatePicturePanel(directoryInfo); 156 updateAddressBar(directoryInfo.FullName); 157 } 158 catch (UnauthorizedAccessException){} 159 } 160 } 161 162 /* 163 * アドレスバーの更新 164 */ 165 private void updateAddressBar(String fullPath) 166 { 167 String[] arraypath = fullPath.Replace("\\", "\").Split('\'); 168 addressBar.Controls.Clear(); 169 currentDirectoryPath = arraypath[0] + '\'; 170 foreach (String path in arraypath) 171 { 172 if (currentDirectoryPath != path + '\') 173 { 174 currentDirectoryPath += ('\' + path); 175 } 176 Button button = new Button(); 177 button.Text = path; //後でフルパスが取得できるようにしておく 178 button.Click += new EventHandler(folderTree_Update); 179 button.MinimumSize = new Size(10, 23); 180 button.MaximumSize = new Size(50, 23); 181 button.Name = currentDirectoryPath; 182 addressBar.Controls.Add(button); 183 } 184 progressText.Text = fullPath; 185 186 } 187}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自分でも整理がついていないので申し訳ございませんが、
以下のように書きなおした所動くようになりました。
もしかしたらバグ等あるかもしれませんが
厳密にテストした場合エラーが出るかもしれませんが、
他の方の少しでも参考になればと思い、以下、フォルダツリーとアドレスバーに関係ある部分を抜き出しました。

lang

1 private String currentDirectoryPath; 2 private TreeNode folderTreeNode; 3 public Form1() 4 { 5 intializeizeComponent(); 6 intializeFolderTree(); 7 } 8 private void folderTree_Update(Object sender, EventArgs e) 9 { 10 Button clickedButton = sender as Button; 11 TreeNode currentSelectedNode = new TreeNode(clickedButton.Name); 12 13 String beforePath = currentDirectoryPath.ToString().Replace("\\", "\"); 14 String afterPath = clickedButton.Name.ToString().Replace("\\", "\"); 15 16 if (afterPath.Split('\').Count() == 2) //ルートの場合 17 { 18 while (folderTree.SelectedNode.Parent != null) { 19 folderTree.SelectedNode = folderTree.SelectedNode.Parent; 20 } 21 } 22 else if(beforePath != null && beforePath != afterPath) 23 { 24 String diff = beforePath.Replace(afterPath, ""); 25 int depth = diff.Split('\').Count() -1; 26 for (int i = 0; i < depth; i++) 27 { 28 if (folderTree.SelectedNode == null) 29 folderTree.SelectedNode = currentSelectedNode; 30 folderTree.SelectedNode = folderTree.SelectedNode.Parent; 31 } 32 } 33 TreeNode tmp = folderTree.SelectedNode; 34 updateFolderTree(currentSelectedNode); 35 folderTree.SelectedNode = tmp; 36 folderTree.Focus(); 37 } 38 private void intializeFolderTree() 39 { 40 folderTree.Nodes.Clear(); 41 foreach (String driveName in Environment.GetLogicalDrives()) 42 { 43 folderTreeNode = new TreeNode(driveName, 0, 0); 44 folderTreeNode.Name = driveName; 45 folderTree.Nodes.Add(folderTreeNode); 46 folderTreeNode.Nodes.Add("..."); 47 } 48 folderTree.Sorted = true; 49 } 50 private void updateFolderTree(TreeNode currentNode) 51 { 52 TreeNode resetTreeNode = currentNode; 53 resetTreeNode.Nodes.Clear(); 54 String nodePath = null; 55 try 56 { 57 nodePath = currentNode.FullPath; 58 currentDirectoryPath = nodePath; 59 } 60 catch(InvalidOperationException e) 61 { 62 nodePath = currentDirectoryPath; 63 } 64 65 if (System.IO.Directory.Exists(nodePath)) 66 { 67 DirectoryInfo directoryInfo = new DirectoryInfo(nodePath); 68 try 69 { 70 DirectoryInfo[] subDirectoryInfoList = directoryInfo.GetDirectories(); 71 if (subDirectoryInfoList.Count() != 0) 72 { 73 foreach (DirectoryInfo subDirectoryInfo in subDirectoryInfoList) 74 { 75 folderTreeNode = new TreeNode(subDirectoryInfo.Name); 76 folderTreeNode.Name = subDirectoryInfo.FullName; 77 resetTreeNode.Nodes.Add(folderTreeNode); 78 folderTreeNode.Nodes.Add("..."); 79 } 80 } 81 folderTreeNode = currentNode; 82 folderTree.SelectedNode = currentNode; 83 updatePicturePanel(directoryInfo); 84 updateAddressBar(directoryInfo.FullName); 85 } 86 catch (UnauthorizedAccessException){} 87 } 88 } 89 private void updateAddressBar(String fullPath) 90 { 91 String[] arraypath = fullPath.Replace("\\", "\").Split('\'); 92 addressBar.Controls.Clear(); 93 currentDirectoryPath = arraypath[0] + '\'; 94 foreach (String path in arraypath) 95 { 96 if (currentDirectoryPath != path + '\') 97 currentDirectoryPath += ('\' + path); 98 if (path == "") 99 continue; 100 Button button = new Button(); 101 button.Text = path; 102 button.Click += new EventHandler(folderTree_Update); 103 button.MinimumSize = new Size(10, 23); 104 button.MaximumSize = new Size(100, 23); 105 button.AutoSize = true; 106 button.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; 107 button.Name = currentDirectoryPath; 108 addressBar.Controls.Add(button); 109 } 110 progressText.Text = fullPath; 111 } 112 private void folderTree_BeforeExpand(object sender, TreeViewCancelEventArgs e) 113 { 114 updateFolderTree(e.Node); 115 } 116 private void folderTree_AfterSelect(object sender, TreeViewEventArgs e) 117 { 118 updateFolderTree(e.Node); 119 }

投稿2015/01/19 15:11

monchiken

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

正確に読んでいないままの回答で申し訳ありませんが、
Keyとして使っている(String key = currentDirectoryPath.ToString().Replace("\", "");)currentDirectoryPath にはTreeNode のFullPathを使っているにも関わらず、(updateFolderTree内)Nodeを作成するときのNameプロパティにはDirectoryInfoのFullNameを使っているため不一致になっているのでは?

そこを合わせば、Nameプロパティで検索してもFindで引っかかると思いますよ。
検証はしていませんので悪しからず。

投稿2015/01/13 06:10

torakichi

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

monchiken

2015/01/13 16:21

ご回答ありがとうございます。 ご指摘の通りFullNameにしないとフルパスが格納出来ず 検索出来ないと気づきましたので以下のとおり修正しました。 updateFolderTree(TreeNode)のforeach内 [修正前] folderTreeNode.Name = childDirectoryInfo.Name; [修正後] folderTreeNode.Name = childDirectoryInfo.FullName; しかし、相変わらず結果がゼロ件で同じIndexOutOfRangeExceptionになります。 デバッグで例外発生時の変数を確認してみたところ、以下のとおりになっていました。 key        →"C:\Program Files" folderTreeNode  .Parent     →Name="C:\", Text="C:\"  .Nodes[0]    →Name="C:\Program Files", Text="Program Files"   .Nodes[0]   →Name="C:\Program Files\Adobe", Text="Adobe" ※Nodesは他のフォルダ情報も同様に取得出来ています。 これなら結果が返ってきてもいいと思うのですが、Findした結果はゼロです。 そもそもこういった形になっていたら取得出来ないのでしょうか? AfterSelect(object sender, TreeViewEventArgs e) BeforeExpand(object sender, TreeViewCancelEventArgs e) で取得したTreeNodeの扱いがマズイのでしょうか? お手間とらせてしまい申し訳ございませんが、 もしよろしければ、引き続きご確認いただけると助かります。 以上、よろしくお願いします。
torakichi

2015/01/14 05:16

とりあえず簡単にですが検証してみました。 結論としてTreeNodeのNameプロパティとKeyとが一致していれば確かにFindで見つかります。 で、monchikenさんのコードをこちらで書いてみましたが、 folderTree_Updateの頭でinitialFolderTree()を呼び出してTreeを作り直していますが、 この部分をコメントアウトしてみると、とりあえず今回の箇所のIndexOutOfRangeExceptionはなくなりました。おそらく作り直すときに思い通りにTreeが作成できていないのでしょう。 ただ上記の修正だけではそのあとの動作が不安定でした。ボタンを押すと固まるなど、いろいろエラーが出ました。(こちらの移植ミスかもしれませんが…) 上の文章を読んでる限り、ご自身の中でも、「folderTreeNode」と「folderTree.Nodes」の扱いがごっちゃになっていませんか?笑 でもあとは想定通りの動きになるようにデバッグを頑張るしかありませんね。 頑張ってください。
monchiken

2015/01/19 15:03

ご親切に検証していただきありがとうございます。 いっその事一から書きなおしてみればと思い、torakichiさんの仰るところを気をつけながら記述してみたところ、私が操作テストした限りで動くようになりました。 実はTreeNodeの扱いがよく分からずじまいなのですが、今後動かしていく中で学んでいこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問