VB.NET|フォルダパス一覧のツリー構造への変換

 多言語度を上げる為にVB.NETに書き換えました。ついでに一番乗りです。

'http://ja.doukaku.org/
'http://ja.doukaku.org/102/投稿用
Imports System
Imports System.Windows.Forms
NameSpace どう書く_orgフォルダパス一覧のツリー構造への変換
Class Program
<STAThread> _
Shared Sub Main(byval args() As String)
Application.Run(new Form1())
End Sub
End Class
class Form1:Inherits Form
'treeView1
Dim treeView1 As TreeView = New TreeView()
'起動時引数でパス一覧のファイルを指定
Dim pathListFilePath As String = System.Environment.GetCommandLineArgs()(1)
Public Sub New()
'treeView1
treeView1.Parent = Me
treeView1.Dock = DockStyle.Fill
End Sub
Private Sub Form1_Load(byval sender As object, byval e As EventArgs)handles Me.Load
'ROOTNode
Dim rootNode As TreeNode = New TreeNode("ROOT")
treeView1.Nodes.Add(rootNode)
For Each fullPath As String In System.IO.File.ReadAllLines(pathListFilePath)
Dim addNode As TreeNode = rootNode
For Each path As String In fullPath.Split(New char(){"\"c})
Dim flag As Boolean = True
For Each node As TreeNode in addNode.Nodes
If node.Text = path Then
addNode = node
flag = False
End If
Next
if flag Then
Dim newnode As TreeNode = New TreeNode(path)
addNode.Nodes.Add(newnode)
addNode = newnode
End If
Next
Next
rootNode.ExpandAll()
End Sub
End Class
End NameSpace

C#|フォルダパス一覧のツリー構造への変換

 どう書く?orgのトピックフォルダパス一覧のツリー構造への変換への投稿用に書きました。

//http://ja.doukaku.org/
//http://ja.doukaku.org/102/投稿用
using System;
using System.Windows.Forms;
namespace どう書く_orgフォルダパス一覧のツリー構造への変換 {
  class Program {
    [STAThread]
    static void Main(string[] args) {
      Application.Run(new Form1());
    }
  }
  class Form1:Form {
    //treeView1
    TreeView treeView1 = new TreeView();
    //起動時引数でパス一覧のファイルを指定
    string pathListFilePath = System.Environment.GetCommandLineArgs()[1];
    public Form1() {
      //Form1
      this.Load += new EventHandler(Form1_Load);
      //treeView1
      treeView1.Parent = this;
      treeView1.Dock = DockStyle.Fill;
    }
    void Form1_Load(object sender, EventArgs e) {
      //ROOTNode
      TreeNode rootNode = new TreeNode("ROOT");
      treeView1.Nodes.Add(rootNode);
      foreach(string fullPath in System.IO.File.ReadAllLines(pathListFilePath)) {
        TreeNode addNode = rootNode;
        foreach(string path in fullPath.Split(new char[] { '\\' })) {
          bool flag = true;
          foreach(TreeNode node in addNode.Nodes) {
            if(node.Text == path) {
              addNode = node;
              flag = false;
            }
            
          }
          if(flag) {
            TreeNode newnode = new TreeNode(path);
            addNode.Nodes.Add(newnode);
            addNode = newnode;
          }
        }
      }
      rootNode.ExpandAll();
    }
  }
}

C#|TabControlのタブをドラッグ&ドロップで並び替え

 C#|TabControlでクリックされたタブが判らないのコードを手直ししました。デザイナー上でタブを切り替えると怒られるというどうしようもない失敗です。原因が良くわからなかったのでtry-catchで無理やり直しました。(こんなんでいいのか?)

 ついでにClickイベントだけじゃ物足りないと思ったのでコピペ&力技でイベントを増設しました。偉い人はもっとスマートに書けるのでしょうか?

 そして本題です。ついでにタブのD&Dに対応しちゃえ!って思ったのです。それ自体は簡単に出来ました。しかし、そこから苦労しました。と言うのも、タブが切り替わるタイミングがボタンを押して離した時ではなくて、ボタンを押し下げた瞬間なんです。つまり、ドラッグするとそのタブが選択されてしまうのです。そしてそのままドロップすると、移動したタブではなくて一番左のタブが選択されているのです。

 僕が望んだ仕様は、選択されていないタブを選択しないまま並び替えられるというものです。せめてドラッグしたときはそのタブが選択されても、ドロップが終わったときには元のタブに戻るようにしようと思いました。そこで選択されたタブの履歴を取って、そこから戻すようにしてみました。でも、選択されているタブをD&Dしたら全く関係ないタブが選択されています。

 色々試しましたが、制御仕切れなかったので諦めました。D&Dしたタブを選択するようにしました。

 ちょっと長いけど晒します。どなたか添削してくれると嬉すぃです…。

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Anis.Controls {
  /// <summary>TabMouseClickイベントを処理するメソッドを表します。</summary>
  public delegate void TabMouseEventHandler(object sender, TabMouseEventArgs e);
  /// <summary>タブ部分がクリックされた際に、
  /// クリックされたタブを取得出来るTabMouseClickイベントを備えたTabControl</summary>
  public class AnisTabControl: TabControl {
    #region//各種TabMouseEvent定義
    /// <summary>クリックされたタブが取得可能なMouseDownイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseDown;
    /// <summary>クリックされたタブが取得可能なMouseClickイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseClick;
    /// <summary>クリックされたタブが取得可能なMouseUpイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseUp;
    /// <summary>クリックされたタブが取得可能なMouseDoubleClickイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをダブルクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseDoubleClick;
    /// <summary>クリックされたタブが取得可能なMouseWheelイベント</summary>
    [Category("アクション"),
    Description("マウスホイールがタブ上で動かされた時に発生します。")]
    public event TabMouseEventHandler TabMouseWheel;
    /// <summary>クリックされたタブが取得可能なMouseMoveイベント</summary>
    [Category("アクション"),
    Description("マウスポインタがコントロール上を移動すると発生します。")]
    public event TabMouseEventHandler TabMouseMove;
    #endregion
    /// <summary>XMLコメントが無いって警告うざい</summary>
    public AnisTabControl() {
      #region//TabMouseEvent関連イベント登録
      this.MouseDown += new MouseEventHandler(AnisTabControl_MouseDown);
      this.MouseClick += new MouseEventHandler(AnisTabControl_MouseClick);
      this.MouseUp += new MouseEventHandler(AnisTabControl_MouseUp);
      this.MouseDoubleClick += new MouseEventHandler(AnisTabControl_MouseDoubleClick);
      this.MouseWheel += new MouseEventHandler(AnisTabControl_MouseWheel);
      this.MouseMove += new MouseEventHandler(AnisTabControl_MouseMove);
      #endregion
    }
    /// <summary>Point上のタブコントロールの
    ///タブ部分に対応したTabPageのインデックスを取得</summary>
    /// <param name="point">インデックスを取得するPoint</param>
    /// <returns>Point上にタブが無ければ-1が返ります。。</returns>
    private int TabIndexFromPoint(Point point) {
      for(int i = 0; i <= this.TabPages.Count - 1; i++) {
        if(this.GetTabRect(i).Contains(point)) {
          return i;
        }
      }
      return -1;
    }
    #region//Tabマウスイベント
    void AnisTabControl_MouseDown(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseDown(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseClick(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseClick(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseUp(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseUp(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseDoubleClick(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseDoubleClick(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseWheel(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseWheel(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseMove(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseMove(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    #endregion
    #region//ドラッグ&ドロップ
    Point mouseDownPoint = Point.Empty;
    bool sortTabDragDrop;
    /// <summary>trueでドラッグ&ドロップによるタブの
    ///並び替えを可能にします。</summary>
    [Category("動作"),
    Description("trueでドラッグ&ドロップによるタブの並び替えを可能にします。")]
    public bool SortTabDragDrop {
      set {
        sortTabDragDrop = value;
        if(value) {
          this.MouseDown += new MouseEventHandler(AnisTabControl_MouseDown1);
          this.MouseUp += new MouseEventHandler(AnisTabControl_MouseUp1);
          this.TabMouseMove += new TabMouseEventHandler(AnisTabControl_TabMouseMove);
          this.DragEnter += new DragEventHandler(AnisTabControl_DragEnter);
          this.DragOver += new DragEventHandler(AnisTabControl_DragOver);
          this.DragDrop += new DragEventHandler(AnisTabControl_DragDrop);
        } else {
          this.MouseDown -= new MouseEventHandler(AnisTabControl_MouseDown1);
          this.MouseUp -= new MouseEventHandler(AnisTabControl_MouseUp1);
          this.TabMouseMove -= new TabMouseEventHandler(AnisTabControl_TabMouseMove);
          this.DragEnter -= new DragEventHandler(AnisTabControl_DragEnter);
          this.DragOver -= new DragEventHandler(AnisTabControl_DragOver);
          this.DragDrop -= new DragEventHandler(AnisTabControl_DragDrop);
        }
      }
      get {
        return sortTabDragDrop;
      }
    }
    void AnisTabControl_MouseDown1(object sender, MouseEventArgs e) {
      if(e.Button == MouseButtons.Left) {
        mouseDownPoint = e.Location;
      } else {
        mouseDownPoint = Point.Empty;
      }
    }
    void AnisTabControl_MouseUp1(object sender, MouseEventArgs e) {
      mouseDownPoint = Point.Empty;
    }
    void AnisTabControl_TabMouseMove(object sender, TabMouseEventArgs e) {
      if(mouseDownPoint != Point.Empty) {
        Rectangle mouseMoveRectangle = new Rectangle(
          mouseDownPoint.X - 5, mouseDownPoint.Y - 5,
          10, 10);
        if(!mouseMoveRectangle.Contains(e.Location)){
          this.DoDragDrop(this.TabPages[e.TabIndex], DragDropEffects.Move);
        }
      }
    }
    void AnisTabControl_DragOver(object sender, DragEventArgs e) {
      mouseDownPoint = Point.Empty;
    }
    void AnisTabControl_DragEnter(object sender, DragEventArgs e) {
      if(e.Data.GetDataPresent(typeof(TabPage)) &&
        this.TabPages.Contains((TabPage)(e.Data.GetData(typeof(TabPage)))) &&
        this.TabIndexFromPoint(this.PointToClient(new Point(e.X,e.Y))) != -1){
        e.Effect = DragDropEffects.Move;
      } else {
        e.Effect = DragDropEffects.None;
      }
    }
    void AnisTabControl_DragDrop(object sender, DragEventArgs e) {
      int index = TabIndexFromPoint(this.PointToClient(new Point(e.X,e.Y)));
      TabPage tabPage = (TabPage)(e.Data.GetData(typeof(TabPage)));
      this.TabPages.Remove(tabPage);
      this.TabPages.Insert(index, tabPage);
      this.SelectTab(index);
    }
    #endregion
  }
  /// <summary>TabMouseClickイベントのデータ</summary>
  public class TabMouseEventArgs:MouseEventArgs {
    private int tabIndex_;
    /// <param name="tabIndex">クリックされたタブに対応したタブのインデックス</param>
    public TabMouseEventArgs(
    	int tabIndex,MouseButtons button,int clicks, int x, int y ,int delta):base(
    		button,clicks,x,y,delta) {
      tabIndex_ = tabIndex;
    }
    /// <summary>クリックされたタブに対応したタブページ</summary>
    public int TabIndex {
      get {
        return tabIndex_;
      }
    }
  }
}

C#|TabControlでクリックされたタブが判らない

 TabControlのMouseClickイベントでどのタブがクリックされたかが判らないのがとても不満です。.NETは面白いけど、

「なんでこんなことも出来ないの?ていうか出来るようにしてくんないの?」

と思うことが時々あります。

 てことで、TabMouseClickEventArgsとかでっち上げてクリックされたタブを取得出来るようにしてみました。その名もTabMouseClickイベントです。ネーミングセンス悪くてすみません。変数とかメソッドとかクラスとか、ネーミングに非常に悩みます。

using System.Windows.Forms;

using System.Drawing;

namespace Anis.Controls {

  /// <summary>TabMouseClickイベントを処理するメソッドを表します。</summary>

  public delegate void TabMouseClickEventHandler(object sender, TabMouseClickEventArgs e);

  /// <summary>タブ部分がクリックされた際に、

  /// クリックされたタブを取得出来るTabMouseClickイベントを備えたTabControl</summary>

  public class AnisTabControl: TabControl {

    /// <summary>クリックされたタブが取得可能なMouseClickイベント/// </summary>

    public event TabMouseClickEventHandler TabMouseClick;

    /// <summary>XMLコメントが無いって警告うざい</summary>

    public AnisTabControl(){

    this.MouseClick += new MouseEventHandler(Class1_MouseClick);

    }

    void Class1_MouseClick(object sender, MouseEventArgs e) {

      for(int i = 0; i <= this.TabPages.Count - 1; i++) { //

        if(this.GetTabRect(i).Contains(e.X,e.Y)){    //この2行がキモでし。

          TabMouseClickEventArgs E = new TabMouseClickEventArgs(

            this.TabPages[i],e.Button,e.Clicks,e.X,e.Y,e.Delta);

          this.TabMouseClick(sender, E);

        }

      }

    }

  }

  /// <summary>TabMouseClickイベントのデータ</summary>

  public class TabMouseClickEventArgs:MouseEventArgs {

    private TabPage tabpage_;

    /// <param name="tabPage">クリックされたタブに対応したタブページ</param>

    public TabMouseClickEventArgs(

      TabPage tabPage,MouseButtons button,int clicks, int x, int y ,int delta):base(

        button,clicks,x,y,delta) {

      tabpage_ = tabPage;

    }

    /// <summary>クリックされたタブに対応したタブページ</summary>

    public TabPage TabPage {

      get {

        return tabpage_;

      }

    }

  }

}

アップしたらXMLコメントのタグが外れてスッキリしてます。まるでただのコメントのようです。

C#|フォルダのパスかファイルのパスか調べる

 ファイルには拡張子があって、フォルダには拡張子が無いので

if(System.IO.Path.GetExtension(“hoge”) == “”) {

//フォルダだお

} else {

//ファイルだお

}

と言うのは間違い。”hoge.moge”がフォルダ名でも”.moge”が拡張子として認識されてしまいます。フォルダ名に”.”を使えるってのは盲点でした。

if(System.IO.Directory.Exists(“hoge”)) {

//フォルダだお

} else {

//ファイルだお

}

これで上手くいきました。

if(System.IO.File.Exists(“hoge”)) {

//フォルダだお

} else {

//ファイルだお

}

は”hoge”がフォルダでもtrueが返されるのでNGでした。

以上、失敗談でした。

もっとスマートで良い方法があったら教えて下さい。

VC#2005EEでエクスプローラー風のツリービューを実装

 NetBeensとVisualC++2005EEをアンインストールして空いたスペースにVisualC#2005EEをインストールしました。VC#をインストールして最初に書いたのは、フォルダの階層を表示出来るツリービューのDLLです。

 aniscapeのお気に入りツリーをVB.NETで作ったときにちょっと大変だったので、C#で書いてDLLとして残しておこうと思いました。

 再帰処理でフォルダ階層を奥まで読んでゴリゴリとノードを追加していけば簡単なのですが、そうすると全てのノードを追加し終わるまで暫く時間が掛かります。とても実用になりません。

 それなら、ノードを開くときにその下だけ読めばもっと簡単だし、最初の待ち時間もありません。でも、それにも問題があります。ノードの頭についている+-のマークが表示されないので、フォルダの下にファイルやフォルダがあるかどうかが分かりません。

 それではどうするのかと言うと、ノードを開く度に、2階層下まで読み込みます。

 ファイルを表示するのですから、アイコンも表示させた方がいいと思います。

Icon icon = Icon.ExtractAssociatedIcon(“FileName”);

でそのファイルのアイコンを取得出来ます。これを

TreeView.ImageList.Images.Add(“FileName”, icon);

でイメージリストに追加して

TreeNode.ImageKey = “FileName”;

TreeNode.SelectedImageKey = “FileName”;

でノードにアイコンを設定します。

 ここで問題発生です。この一連の処理がとても重いのです。ノードをクリックしてから開くまでに数秒から十数秒掛かります。使い物になりません。

 そこでもう少し改造します。+-マークを表示させる為には2階層下まで読む必要がありますが、2階層下のノードについてはアイコンが無くても問題ありません。そこで、ノードは2階層下まで追加するが、アイコンは1階層下のみ追加する仕様にしました。

 これで、軽快とはいきませんが、使えるレベルまでレスポンスが良くなりました。後はもっとレスポンスが必要な場合の為に、ファイルごとにアイコンを取得しないようにするプロパティでも実装しておけば幅広く使える様になるでしょう。

以上、メモでした。

ソースコード(C#, .NET2.0)

AnisTreeView.cs

バイナリ

AnisTreeView.zip

 大量にノードを開いた時のレスポンスを改善しました。

バイナリ

AnisTreeView1_1_0_0.zip

ソースコード(C#, .NET2.0)

AnisTreeView1_1_0_0.cs

機動戦士ガンダムOO 6

 丁度今、GyaO『機動戦士ガンダムOO』の第六話を観終わったところです。

内容は、

「ソレスタルビーイングの新装備凄いんだお!」

今後も、各回お決まりのパターンで紛争に介入しながら、少しずつソレスタルビーイング云々な謎に迫るって感じの進行になるでしょう。

気になった点

・ルイスが出てこなかった。

ルイスのいないOOに価値はありません。

Java終わりました。

 と言ってもゴリゴリ書けるようになったわけじゃありません。実は気まぐれでC#触ったんです。思いの外面白くてJavaそっちのけです。VBよりも書きやすいんですね。

 ネット上の資料はVB.NETの方が多いように思いますが、テキストエディタなんか見てると、C#対応でVB.NETに対応してないのが結構あったり、C#の方が風当たりがいい感じですね。世の中、VB.NET使いよりもC#使いに有利なように出来ているようです。

 でも、VBの便利な機能のいくつかが見当たらないのは不満です。VBはWithEventsで宣言してhandlesでイベント拾えたから、プロシージャがどのイベントに対応してるか見通せたのに、C#では出来ないようです。

 With~EndWithとかも良く使ってたのですが、C#にはないのでしょうか。

 ただ、VBではOptionStrict ONでいちいち型をキャストするとゴチャゴチャとして読みにくいソースになったけど、C#だとキャストの記述が超スッキリで、これはかなりいいです。

 VB.NETはメソッドの引数のOptional指定とかが便利でしたが、まぁ…、これは無くてもそんなに変わりませんね。そうそう、VB.NETだとメソッドの引数を

[パラメータ名] : パラメータ

で指定出来て快適だったけど、C#ではどうなんでしょう。試してみようと思います。似てるけど結構違うんですね。

 実はマイPCはCドライブの容量が切迫しているのです。Dドライブは腐るほど余ってるのにです。マイドキュメントをDドライブに移したり、手動でインストールするソフトはDドライブに入れたりしているのですが、それでもデフラグするときに『容量が足りません』って怒られるくらいに余りが少ないです。面倒なくパーティションを切りなおすツールは結構高いみたいだし…、困ってます。

 そんなわけで、VB2005 EE、VC++2005 EEに加えてC#2005 EEを入れる余裕は無いわけです。NetBeansなんかも入れちゃった(使いにくいですね)ので尚更です。そこで、.NET Framework SDK + テキストエディタです。C#の予約語をググってTeraPadのC/C++モードの予約語リストにコピペでぶち込みました。拡張子も.c,.cpに加えて.csを追加設定しました。これとMSDNがあれば大抵のことは何とかなるでしょう。TeraPadの外部ツールにもcscを登録しました。こんなんでも意外と快適なもんです。

 と、ここ最近自転車ネタが全く無い本物のサボり日記になっていてすみません。だって、自転車は乗る程にお金が掛かるけど、プログラムはいくら書いてもタダなんです。こんないいおもちゃは無いですよ~。

 はぁ…、春が来て、すっと春だったらいいのに…。

java始めました

 そして終わりそうです。面白くないです。ときめかないというか、萌えません。言語にエレガントさが足りないのだと思いました、どこがとは具体的に示せませんが。

 JDK+TeraPadでやってみたのですが、IDEの威力を思い知りました。というか、インテリセンスの威力です。VB.NETの時はすらすら書けたコードも、javaだとドキュメントと睨めっこしながら、それでもいやんなっちゃうって感じです。VB.NETはインテリセンスがドキュメントの代わりみたいなところがあるから楽です。

 じゃあ、IDEに頼ってちゃ駄目じゃん?って思います。でも考えてみると、VB.NETをSDK+TeraPadで書くのは不便さは感じますがそんなに抵抗がありません。僕にとっては、強力なIDEは習得の助けになるようです。

 javaのIDEについて調べてみようと思います。VS並みの強力な機能は期待できるのでしょうか。