AIと戦って、あなたの人生のリスク診断 >>

C# TreeViewについて質問させてください。
ノード(子ノード含む)を数万件以上登録する際に、効率の良い方法を教えて頂けないでしょうか?

実際のコードとは異なりますが、大まかに以下のような処理をメインスレッドで行っています。
class MyTreeNode : TreeNode{
  void AddNode(){
    BeginUpdate();
    SuspendLayout();
    foreach( var 親ノード情報 in 親ノード情報リスト ){
      TreeNode parentNode = new TreeNode( 親ノード名 );
      foreach( var 子ノード情報 in 子ノード情報リスト ){
        TreeNode childNode = new TreeNode( 子ノード名);
        parentNode.Nodes.Add( childNode );
      }
      this.Nodes.Add( parentNode );
    }
    ResumeLayout();
    EndUpdate();
  }
}
この方法ですと、かなり時間がかかってしまい、UIが固まったようになってしまいます。

(TreeViewに、子ノードの一斉展開機能が必要なので、親ノード展開時のイベントを拾って
 子ノードを追加する方法は上記と同じく遅くなってしまうのではと思っていますがどうなんでしょうか?)

このQ&Aに関連する最新のQ&A

A 回答 (1件)

今試せる環境がないので半分くらい無責任発言なんですが、一応案として、何かの参考になれば。



・効率が良くなるかもしれない方法
 TreeNodeを配列化してAddRangeする(Addを使わず配列で渡す)
 ※配列はListではなくTreeNode[]でnew

・追加時間を短縮する方法
 System.Threading.Tasks.Parallelを使って並列実行する
 ぱっと見、1つの「親ノード情報」に対する子は予め決まってそうなので、「親ノード情報」単位で並列化が可能にみえます。ノード間で何かしら依存する場合はたぶん無理です。

・ノード追加処理を非同期化させるか、メッセージ処理をはさむ
 UIが固まるのは、処理が重いからというより、ウインドウが長時間メッセージを処理できなくなるからです。
 なので、たとえば何階層か展開する毎にメッセージ処理を挟めばUIが止まることはなくなります(処理中にウインドウが操作を受け付けるようになるので別の問題起き得ます)。
    • good
    • 0
この回答へのお礼

回答、ありがとうございます。
色々とバタバタして返信が遅くなってしまいました、すいません。

> TreeNodeを配列化してAddRangeする
この手法にて、約10万件追加されるときの時間が1秒以上改善されました。
大変たすかりました、ありがとうございます。

また、調査の結果、一番のネックになっているところが見つかりました。
(指摘頂いたコードを抜粋して質問させていただきましたが、そのあとの処理で親子ノード1個追加される度に、毎回Sortを実行していたので...)
試しに上記サンプルとSortを外して実行してみると、大きなストレスなく動作させることができました。

要望として、親ノードのソートはしたいですが、子ノードまでソートする必要はないと思われるので、ソート部分を自作して乗り切ろうと思います。

結局、質問した際のコードとは別のところが一番の原因で、大変申し訳ございません。
次はもう少し気をつけて質問します。

> System.Threading.Tasks.Parallelを使って並列実行する
> ノード追加処理を非同期化させるか、メッセージ処理をはさむ

上記2点についての案もありがとうございます。
私の今の力量では、期間内に両方検証し比較することができないので、後日時間があるときに、確認してみたいと思います。
(特にSystem.Threading.Tasks.Parallelは機能を確認してみると、できるとすごく便利そうです。)

複数の案とともに、処理改善もでき、一番の原因も判明いたしましたので、duke_kimuraさんをベストアンサーにさせていただき、この問題は解決済みにさせていただきたいと思います。
本当にありがとうございました。

お礼日時:2014/12/08 22:24

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QC#でtreeviewの指定ノードを選択する

C#にて、
treeviewでの選択ノードを記憶しておき、
treeviewを一度更新(削除し作成)し、
記憶してあるノードを再び選択する。という動きをしたいです。

TreeNode tn = new TreeNode();
tn = treeView1.SelectedNode;

//ここでDB再読み込み→treeView再作成

treeView1.Focus();
treeView1.SelectedNode = tn;

としているのですが、TopNode選択状態になってしまい、
最初に選択していたNodeを選択してくれません。


どなたかご教授願います。
よろしくお願いいたします。

Aベストアンサー

TreeViewを再作成した時点で、ノードのインスタンスがすべて新しく作り変えられているので、再作成前のノードで選択させることはできません。

再作成前に選択ノードのフルパスを記憶しておいて、作成後にフルパスを辿って選択させることならできます。フルパスを辿るのは自力になるかと。記憶したフルパスをPathSeparatorでSplitしてルートから順に子ノードを探していく方法くらいしか思いつきませんが・・・。
ただ、同じ階層に同じテキストのノードがあると破たんします。

Qフルパスから最後のディレクトリ名を取得したい。

vb.netなのですが、例えば
c:\aaa\bbb\ccc\ddd\eee\fff.exe
というフルパスがあったとして、
eeeというディレクトリ名を取得したいのですが、
何か良い方法はないでしょうか。
それぞれのディレクトリ名の文字数や階層数は
決まっていないのですが、オススメの方法が
ありましたら、教えて頂けると助かります。

Aベストアンサー

MessageBox.Show(IO.Path.GetFileName(IO.Path.GetDirectoryName(myPath)))

IO.Path の GetDirectoryName でフォルダのフルパスを取得して、さらに IO.Path の GetFileName で最終フォルダ(またはファイル)の名前を取得。

QC#にて別クラスの関数を使いたい

C#にて、別クラスの関数を使用する方法を教えてほしいです。

下記のような、構造体を受け取るメソッドを作りました。

*****************************
private struct MyPoint
{
public int x;
public int y;
}

private void proc1(MyPoint pt)
{
MessageBox.Show("座標:" ; pt.x + "," + pt.y + "実行結果");
}

private void button1_Click(object sender ,System.EventArgs e)
{

MyPoint pt;
pt.x = 10;
pt.y = 20;
proc(pt);
}
*****************************

別のフォームのクラスから、proc1を呼び出したいのですが、やり方がわかりません。
どうか、教えてください。

Aベストアンサー

同じ定義をしたとしても別の名前空間に書いた構造体は同一とはみなされません。

呼び出し先クラスでの構造体を private では無く、public で宣言して下さい。

呼び出し元では、

MyClass.MyPoint pt;

のようにして実体を作ります。

QTreeViewを反転表示したままTextBoxにカーソル

VB2005 Expressで開発をしています。

TreeViewでノードを選択して、その値をTextBoxに表示しようと
思っています。
そこで、選択したノードを反転表示したままTextBoxにカーソル
をセットすることは可能なのでしょうか。

フォーカスを当てた上体で反転されるので無理な気はするのですが、
ご存知の方がいらっしゃいましたら教えて下さい。

よろしくお願いします。

Aベストアンサー

TreeViewのHideSelectionをfalseに設定すれば フォーカスが外れても選択状態のままの表示になりますよ

Qツリービューで、エクスプローラー風にフォルダを辿る

ツリービューで、エクスプローラー風にフォルダをたどるプログラムサンプル例を知りたいのですが、ご存知のかたはいらっしゃいませんでしょうか。
Visual Basic 2010 Express Edition を利用しています。

参考書を何冊も読みましたが、ドライブやフォルダ情報を得ても、どうやってそれらをノードにしたら良いのか、よくわかりませんでした。

VisualBasic中学校のサンプルではややこしすぎる上、エラーが発生しました。
よろしくお願いいたいします。

Aベストアンサー

どこまで「真面目に」やりたいかにもよりますが……。

本当に真面目にやるなら,フォルダはディレクトリではないため,
MSDN) SHGetFolderLocation function
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762180.aspx
を起点に
MSDN) SHCreateItemFromIDList function
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762133.aspx
でIShellItemを得て,それからフォルダやファイル等を列挙していくか,
ツリービューを諦めて
MSDN) INameSpaceTreeControl interface
http://msdn.microsoft.com/en-us/library/windows/desktop/bb761630.aspx
を使うか,となります。
# 私は後者をC#でやろうとしてP/Invokeの宣言だけで諦めました……。


Visual Basic 中学校のサンプルというのは,
Site) VB サンプル集 - VB2010, VB2008, VB2005, VB.NET2003, VB.NET2002
http://homepage1.nifty.com/rucio/main/dotnet/Samples/SmpleCnt.htm
にある,
Site) VB フォルダツリー
http://homepage1.nifty.com/rucio/main/dotnet/Samples/Sample081FolderTree.htm
のことでしょうか。
非常にコンパクトなサンプルだと思いますが。
・何が分からなかったのでしょうか
・エラーとはどういうエラーでしょうか (例外であれば,その型とエラーメッセージ)
# Visual Basic 中学校には質問用の掲示板があるのですけれどね……。

どこまで「真面目に」やりたいかにもよりますが……。

本当に真面目にやるなら,フォルダはディレクトリではないため,
MSDN) SHGetFolderLocation function
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762180.aspx
を起点に
MSDN) SHCreateItemFromIDList function
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762133.aspx
でIShellItemを得て,それからフォルダやファイル等を列挙していくか,
ツリービューを諦めて
MSDN) INameSpaceTreeControl interface
http://msdn.micros...続きを読む

QVB2005 TreeViewの任意ノード選択

お世話になっております。

VB2005でWinアプリを開発中です。
ルートノードは1つで、
そこから子、孫、ひ孫・・・と階段状になるTreeViewを作っています。

  L子
     L孫
        Lひ孫
            ・・・・

このようなツリーに対し、プログラムで任意のノードを選択状態にしたいのですが、
ノードの名称などで一発で指定する方法はありますでしょうか??
上の例で、「孫」を選択状態にしたい場合、
TreeView1.SelectedNode = TreeView1.Nodes(0).Nodes(0).Nodes(0)
と書けば、できることはできるのですが。
他にもっとよい方法があるはずと思うのですが、見つけられませんでした。

VB6.0なら、下記に方法があったのですが・・・
http://oshiete1.goo.ne.jp/qa732490.html

よろしくお願いします。

Aベストアンサー

参考URLです。
http://homepage1.nifty.com/rucio/main/dotnet/Samples/SmpleCnt.htm

QC#のツリービューでツリーノードとデータの関連付け

こんにちは。
C#でツリービューの操作をしています。
すでに階層構造を持つデータがあります。これをツリービューに表示させようとしています。

TreeNode treeNodeFruits = new TreeNode("果物");

としてツリービューに追加してあげると普通に表示できますが、このままだと独自データと関連付けがされていないため、ノードをクリックした際に何もできません。
C++ではHTREEITEMのlParamにユーザーデータのポインタをセットできますが、C#ではツリーノードに関連付けできそうな項目が見当たりません。

C#ではツリーノードと独自に持つデータとの関連付けをどのようにすればよろしいのでしょうか?

Aベストアンサー

ツリービュー使ったことはありませんが……。

>C++ではHTREEITEMのlParamにユーザーデータのポインタをセットできますが、C#ではツリーノードに関連付けできそうな項目が見当たりません。

Tagプロパティとか…でしょうかねぇ……。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.treenode.tag%28v=vs.100%29.aspx

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

QC# インスタンスの破棄

C#でインスタンスの破棄を明示的に行いたいのですが、
実際の開発現場では、どのように行っているのでしょうか?

自分で調べると「ガベージコレクタ」が暗黙的に行っているようですが明示的には行わないのが普通なのでしょうか?
もしくは、「Dispose」を使用して明示的に行うのが普通なのでしょうか?

実際に開発されている方からすると簡単な事かもしれませんが教えて頂けると助かります。

以上ですが、よろしくお願いいたします。

Aベストアンサー

結論から言うと、どちらでも良いです。
できれば生成から破棄まで考えて開発できると良いですね。

ガベージコレクションが実行されることで自動開放されますから、
一切.close()や.dispose()を使わなかったとしてもプログラムが
不正終了してしまう事はほとんどありません。

実際の開発では使わなくなったものを使わなくなった時点で
明示的に破棄することが多いです。正確には明示的に破棄するもの、
明示的に破棄しないもの、の2種類に分類しています。

例えばファイルを読み書きするストリーム系のオブジェクトや
データベースとのコネクションなどです。これは開発会社や
開発チーム、案件によって若干違っていて、徹底するところや
適当なところもあります。個人的には徹底したい派ですが。。。

ガベージコレクションが発生するとプログラムの実行動作が
遅くなり、また瞬間的に大きな負担がかかることがあります。
そのため全てをガベージコレクタに任せるのではなく、
明示的に開放できるもの、メモリを大量に消費するものは
その都度、適切に開放していくことで処理効率が良くなります。

プログラミング関連の調べ物で、サンプルソース等を見ることが
あるかと思います。この時サンプルで明示的に開放していたら、
それは明示的に開放したほうが良いもの、と思いましょう。
これだけでもステップアップになりますね。

結論から言うと、どちらでも良いです。
できれば生成から破棄まで考えて開発できると良いですね。

ガベージコレクションが実行されることで自動開放されますから、
一切.close()や.dispose()を使わなかったとしてもプログラムが
不正終了してしまう事はほとんどありません。

実際の開発では使わなくなったものを使わなくなった時点で
明示的に破棄することが多いです。正確には明示的に破棄するもの、
明示的に破棄しないもの、の2種類に分類しています。

例えばファイルを読み書きするストリーム...続きを読む

QDataGridViewで指定したセルの値を取得

こんにちは。

VB2008のDataGridViewで指定したセルの値を取得をする方法がわかりません。
どなたか教えてください。

Aベストアンサー

こんばんは.

 Dim Data As String
 Data = Me.DataGridView(0, 2).Value
 MsgBox(Data)

みたいな感じで取れないですかね???


人気Q&Aランキング