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

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

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

3回答

7682閲覧

VBAにて空白を含むRangeの並び替え

khr0404

総合スコア43

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2018/07/25 06:19

編集2018/07/25 06:45

前提・実現したいこと

エクセルのマクロでTreeViewにて表示したい内容があるのですが、
ノードの順番を入れ替えるのにつまづいています。

イメージ説明

添付画像の左側がDBよりRecordsetで取得してきた情報をシートに反映したものなのですが、
この状態のまま、上の行より読み込んでいくと、
2行目のParentID=A900の親ノードがまだ存在していないため、エラーとなります。

なので、添付画像の右側のように並び替える必要があります。
並び替えの優先順位としては
①ParentIDがnullのものはルートノードとなるので一番先頭に移動したい
②NodeIDがParentIDに存在しているものは下に移動したい
③NodeIDがParentIDに存在しないものは一番下に移動したい

上記の中でも①だけでもできれば幸いです。
Range.Sort メソッドだとあくまで昇順、降順しか選択できないのでしょうか?
昇順、降順だとKeyに指定したセルに空白がある行は下に移動してしまうのですが、上に表示する方法があれば知りたいです。

If Cells(i , 3).Value="" Then
先頭に移動
Else
のようなことが書ければよいのですが・・・

どうかご教示お願いいたします。

補足情報(FW/ツールのバージョンなど)

Office2013

追加

①であれば

If Cells(i , 3).Value="" Then Cells(i , 3).Value="0"

にすれば昇順でいけました。

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

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

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

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

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

guest

回答3

0

階層の浅い順に並べたいということですよね。

まずは使用していない列(例えばD列)に階層を出力してみてはどうでしょうか。
手順としては、
①ルートノード(C列が空)を階層1としてセット
②階層1の各ID(A列の値)が親ノード(C列の値)に指定されているものを階層2としてセット
③階層2の各ID(A列の値)が親ノード(C列の値)に指定されているものを階層3としてセット
④同様の処理で1件もセットされなくなるまで階層を掘り下げていく。

これで親子関係にあるものは階層の深度を取ることができると思います。

以下、D列に階層を書き込むサンプルです。

Sub Make_Sortkey() Dim iCnt As Integer '処理件数 Dim iLevel As Integer '階層 iLevel = 0 Do iCnt = Make_NodeLevel(iLevel) '階層の書き込み処理 If iCnt = 0 Then Exit Do '処理されなくなったらループ終了 iLevel = iLevel + 1 '階層を1つ深くする Loop End Sub Function Make_NodeLevel(viLevel As Integer) As Integer Dim iCnt As Integer '検出カウンタ Dim sParent As String '検索する親ノードID iCnt = 0 Dim PRow As Integer '親ノード検索のループ行 Dim CRow As Integer '子ノード検索のループ行 For PRow = 2 To 11 If viLevel = 0 Then 'ルートノード検索 If Cells(PRow, "C").Value = "" Then Cells(PRow, "D").Value = viLevel + 1 iCnt = iCnt + 1 End If ElseIf Cells(PRow, "D").Value = viLevel Then '親ノード検索 sParent = Cells(PRow, "A").Value For CRow = 2 To 11 '子ノード検索 If Cells(CRow, "C").Value = sParent Then Cells(CRow, "D").Value = viLevel + 1 iCnt = iCnt + 1 End If Next End If Next Make_NodeLevel = iCnt End Function

こうして作成したD列でソートしてみてはどうでしょうか?

投稿2018/07/26 04:19

編集2018/07/26 04:31
jawa

総合スコア3013

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

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

0

例示のデータでは、親、子、孫 の3階層までですが、階層を限定しないとすると、並べ替えるといっても条件が難しそうです。

単純に先頭からループで登録を試みて、親ノードが見つからないエラーがなくなるまで、繰り返すという発想でコーディングしてみました。

vba

1Private Sub CommandButton1_Click() 2 Dim TV As TreeView, ND As Node 3 Set TV = Me.TreeView1 4 With Worksheets(1) 5 Dim LastRow As Long 6 LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row 7 8 Dim i As Long 9 'ルートノードの登録 10 If .Cells(i, 3).Value = "" Then 11 Set ND = TV.Nodes.Add(, , .Cells(i, 1).Value, .Cells(i, 2).Value) 12 ND.Expanded = True 13 End If 14 Next 15 16 Do 17 Dim retry As Boolean 18 retry = False 19 On Error Resume Next 20 '子ノードの登録をトライ 21 For i = 2 To LastRow 22 If .Cells(i, 3).Value <> "" Then 23 Set ND = TV.Nodes.Add(.Cells(i, 3).Value, tvwChild, _ 24 .Cells(i, 1).Value, .Cells(i, 2).Value) 25 If Err = 35601 Then '"Element not found" Error 26 Err.Clear 27 retry = True 28 ElseIf Err = 0 Then 29 ND.Expanded = True 30 End If 31 End If 32 Next 33 On Error GoTo 0 34 Loop Until retry = False 35 End With 36End Sub

階層数分、For Next を繰り返すので無駄が多いですが、ロジックはシンプルになります。

投稿2018/07/25 23:30

hatena19

総合スコア33699

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

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

0

上から順番に、

ParentIDがnullのもの
NodeIDがParentIDに存在しているもの、
NodeIDがParentIDに存在しないもの、

を登録していけばいいだけ、ですね。

#その、だけ、がむずかしい

投稿2018/07/25 06:47

y_waiwai

総合スコア87749

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

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

khr0404

2018/07/25 06:57 編集

y-waiwai様 回答ありがとうございます。 確かに だけ が難しいですね・・・ 下記はツリービューのコードなのですが ```TreeView For i = 2 To .Cells(.Rows.Count, 1).End(xlUp).Row If .Cells(i, 3).Value = 0 Then 'ParentID が 0 (ルートノードの場合の処理) Rltiv = Null Rltsp = tvwFirst Else 'ParentID が 0 以外 (ルートノード以外の処理) Rltiv = "A" & .Cells(i, 3) Rltsp = tvwChild End If '分岐処理終わり TV.Nodes.Add Relative:=Rltiv, Relationship:=Rltsp, Key:="A" & .Cells(i, 1), text:=.Cells(i, 2) TV.Nodes(i - 1).Expanded = True Next i ``` If文をもっと工夫すればなんとかいけそうですかね・・・
y_waiwai

2018/07/25 07:02

ParentIDがNullのデータが登録されてる、という場面から、 2番めの実現方法。 まず先頭の登録データのNodeIDを読み出し、それと合致するParentIDを持つものを抽出して登録、 それが済んだら、登録データの次のNodeIDを読み、それと合致するものを抽出、登録、 と、登録データが尽きるまで繰り返す、という考え方でしょうか。 これが済んだらあとは未登録のものばかりが残るので、それを登録、という運びとなります
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問