C# Programming

Image

ListView でプロセスを表示する (その1)


開発環境: Visual Studio 2003
次のような機能のForm アプリケーションを作る。
  • プロセスの詳細情報を1秒ごとに ListView に表示する。
Image
補足: ここでは、 System.Diagnostics.Process.GetProcessesを使用しているが、フォーマンスカウンターを使うほうが、お作法として正しい使い方 です。

注意: ListView では、先頭のカラムしか編集ができない。(SubItems は編集できない。)
詳細は、Visual Studio のヘルプを見てください。
回避策は、やろうとしていることによりますが、

1、データベースを使う。
2、行を選択したイベントを拾って、編集用のダイアログを出して、そこで修正する。
3、DataGrid を使ったリスト表示→結構めんどくさい。
4、Excel をインストールしてあるのなら、Excel の SpreadSheet ActiveX コントロールを貼り付ける。→Excel があるのなら、それを使ったほうが早いんじゃない?

ってところですかねぇ。

作り方

1. フォームに ツールボックスより、ListView を貼り付ける。
2. フォームに ツールボックスより、タイマーを貼り付ける。
3. Form、Timer、ListView のプロパティを次のようにセットする。
Formのプロパティ
プロパティ
TextProcess ListView
ListView のプロパティ
プロパティ
DockFill
Timerのプロパティ
プロパティ
EnabledTrue
Interval1000

4. Timer のプロパティより、Tick イベントに OnTick をタイプすると、自動的にイベントが追加され、コードが表示される。
あとは、イベント発生時に、ListView を更新するための AddProcesses() を呼び出す。

private void OnTick(object sender, System.EventArgs e)
{
         AddProcesses();
}

5. ListView の設定を行う。

this.listView1.View = View.Details; // カラムのタイトル行を表示する。これが気が付かない。
this.listView1.AllowColumnReorder = true; // カラムの移動を可能にする。
this.listView1.GridLines = true; // グリッドラインを表示する。
this.listView1.Sorting = SortOrder.Ascending;   // 第1カラムでの昇順とする。
6. カラムを追加する。

this.listView1.Columns.Clear(); // 一応、クリアしておく。
this.listView1.Columns.Add("ProcessName", 50, HorizontalAlignment.Left); // カラムの追加。
this.listView1.Columns.Add("Id", 50, HorizontalAlignment.Right); // カラムの追加。
--- 省略 ---
7. タイマーで呼ばれたら、行を表示する。
// ちらつきを抑えるために、BeginUpdate()を呼ぶ。
this.listView1.BeginUpdate(); 
// プロセスの情報を得る。
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();

// 各プロセスごとに、ListViewItemをアロケートする。
ListViewItem[] items = new ListViewItem[processes.Length];

for (int i = 0; i < processes.Length; i++)
{
     // 各ListViewItem にプロセスの情報をAdd していく。
     items[i] = new ListViewItem(processes[i].ProcessName);
     items[i].SubItems.Add(processes[i].Id.ToString());
     --- 省略 ---
}
// ListViewItems をクリアする。
this.listView1.Items.Clear();
// AddRange でまとめて ListViewItems を追加する。
this.listView1.Items.AddRange(items);
// EndUpdate() で表示を再開する。
this.listView1.EndUpdate();
メモ:
  • BeginUpdate(), EndUpdate() を使っても、ちらつきは発生し、ほとんど効果がない。
  • AddRange() ではなく、Add でも、ほとんど性能的に問題なかった。この程度のリストの数では、問題にならないのかも。
  • 毎回、new ListViewItem をしていて、問題ないかと思い、ListViewItem を使いまわすようにしてみたが、ほとんど性能的(使用メモリサイズ、パフォーマンス)に大差なし。内部でバッファリングしてるのではないか。何も考えずに、MSのサンプルどおりに組んでも問題なさそう。
  • このプログラムは、かなりリソース(VMで、20MB)を食います。この程度で、こんなにくっちゃって大丈夫なのか?
  • 標準では、任意の行でソートができない。それ用のインターフェースが用意されている。
日付修正履歴
4/29初期バージョン作成

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace ListView
{
        /// <summary>
        /// Form1 の概要の説明です。
        /// </summary>
        public class Form1 : System.Windows.Forms.Form
        {
                private System.Windows.Forms.ListView listView1;
                private System.Windows.Forms.Timer timer1;
                private System.ComponentModel.IContainer components;

                public Form1()
                {
                        //
                        // Windows フォーム デザイナ サポートに必要です。
                        //
                        InitializeComponent();

                        //
                        // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
                        //
                        InitListView();
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null) 
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows Form Designer generated code
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
                /// コード エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
                        this.components = new System.ComponentModel.Container();
                        this.listView1 = new System.Windows.Forms.ListView();
                        this.timer1 = new System.Windows.Forms.Timer(this.components);
                        this.SuspendLayout();
                        // 
                        // listView1
                        // 
                        this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;
                        this.listView1.Name = "listView1";
                        this.listView1.Size = new System.Drawing.Size(292, 266);
                        this.listView1.TabIndex = 0;
                        // 
                        // timer1
                        // 
                        this.timer1.Enabled = true;
                        this.timer1.Interval = 1000;
                        this.timer1.Tick += new System.EventHandler(this.OnTick);
                        // 
                        // Form1
                        // 
                        this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
                        this.ClientSize = new System.Drawing.Size(292, 266);
                        this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                                                                                  this.listView1});
                        this.Name = "Form1";
                        this.Text = "Process ListView";
                        this.ResumeLayout(false);

                }
                #endregion

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main() 
                {
                        Application.Run(new Form1());
                }

                private void InitListView()
                {
                        this.listView1.View = View.Details;
                        this.listView1.AllowColumnReorder = true;
                        this.listView1.GridLines = true;
                        this.listView1.Sorting = SortOrder.Ascending;

                        this.listView1.Columns.Clear();
                        this.listView1.Columns.Add("ProcessName", 50, HorizontalAlignment.Left);
                        this.listView1.Columns.Add("Id", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("BasePriority", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("HandleCount", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("Threads", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("StartTime", 50, HorizontalAlignment.Left);
                        this.listView1.Columns.Add("PrivilegedProcessorTime", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("TotalProcessorTime", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("UserProcessorTime", 50, HorizontalAlignment.Right);
                        
                        this.listView1.Columns.Add("VirtualMemorySize", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("PeakVirtualMemorySize", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("PeakWorkingSet", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("WorkingSet", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("PagedMemorySize", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("PeakPagedMemorySize", 50, HorizontalAlignment.Right);

                        this.listView1.Columns.Add("PrivateMemorySize", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("NonpagedSystemMemorySize", 50, HorizontalAlignment.Right);
                        this.listView1.Columns.Add("PagedSystemMemorySize", 50, HorizontalAlignment.Right);
                }

                private void AddProcesses()
                {
                        this.listView1.BeginUpdate();
                        System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();

                        ListViewItem[] items = new ListViewItem[processes.Length];

                        for (int i = 0; i < processes.Length; i++)
                        {
                                items[i] = new ListViewItem(processes[i].ProcessName);
                                items[i].SubItems.Add(processes[i].Id.ToString());

                                items[i].SubItems.Add(processes[i].BasePriority.ToString());
                                items[i].SubItems.Add(processes[i].HandleCount.ToString());
                                items[i].SubItems.Add(processes[i].Threads.Count.ToString());

                                items[i].SubItems.Add(processes[i].StartTime.ToString("T"));
                                items[i].SubItems.Add(processes[i].PrivilegedProcessorTime.ToString());

                                items[i].SubItems.Add(processes[i].TotalProcessorTime.ToString());
                                items[i].SubItems.Add(processes[i].UserProcessorTime.ToString());

                                items[i].SubItems.Add( (processes[i].VirtualMemorySize/1024/1024).ToString() + " MB");
                                items[i].SubItems.Add( (processes[i].PeakVirtualMemorySize/1024/1024).ToString() + " MB");

                                items[i].SubItems.Add( (processes[i].PeakWorkingSet/1024/1024).ToString() + " MB");
                                items[i].SubItems.Add( (processes[i].WorkingSet/1024/1024).ToString() + " MB");

                                items[i].SubItems.Add( (processes[i].PagedMemorySize/1024).ToString() + " kB");
                                items[i].SubItems.Add( (processes[i].PeakPagedMemorySize/1024).ToString() + " kB");

                                items[i].SubItems.Add( (processes[i].PrivateMemorySize/1024).ToString() + " kB");
                                items[i].SubItems.Add( (processes[i].NonpagedSystemMemorySize/1024).ToString() + " kB");
                                items[i].SubItems.Add( (processes[i].PagedSystemMemorySize/1024).ToString() + " kB");
                        }
                        this.listView1.Items.Clear();
                        this.listView1.Items.AddRange(items);
                        this.listView1.EndUpdate();
                }

                private void OnTick(object sender, System.EventArgs e)
                {
                        AddProcesses();
                }

        }
}