C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: ペン操作によるメニュー展開


(過去ログ 27 を表示中)

[トピック内 16 記事 (1 - 16 表示)]  << 0 >>

■11930 / inTopicNo.1)  ペン操作によるメニュー展開
  
□投稿者/ arion (30回)-(2007/12/25(Tue) 17:10:12)

分類:[C#] 

VisualStudio .NET2003 C#
.NET Framework SDK Ver.1.1
を使っています。

以前の投稿はこちらです。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=10503&KLOG=24
時間が空いてしまったので過去ログになってしまいました。

何度もすみませんがプログラムが行き詰っているのでアドバイスをお願いします。

重複になってしまいますが、私が考えいるのは、
例えば、マイドキュメントに名前が「1」、「2」、「3」、「4」、「5」という5つのフォルダやファイルがあるとします。

まずジェスチャで四角いフォームを表示させます。

そこからペンを下に動かし領域をでると、最初のフォームの下に同じ大きさのフォームが1つ現れそこには「1」のフォルダが表示されます。
さらにペンを下に動かして「1」フォルダの領域を出るとその下にまた四角いフォームが現れ「2」のフォルダが表示される。
+--+
| 1|
+--+

+--+
| 1|
+--+
| 2|
+--+

+--+
| 1|
+--+
| 2|
+--+
| 3|
+--+

というようなものです。
ある指定したフォルダに入っているフォルダやファイルを一度に全部見せるのではなく、ペンで操作した方向に1つずつ出して行きたいと考えています。
この説明では下方向のみでしたが上下左右に展開させたいです。

現在はFormとListViewで作成しています。

ソースコードは下に投稿します。

このプログラムでは、
ロードしたときにGetFile()でマイドキュメント内のフォルダやファイルのデータを全部読み込んでlistviewに表示しています。
しかしlistviewの大きさをアイテムが一つしか表示できない大きさに設定しているので無理やり一つしか表示していません。
最初には「1」フォルダ(マイドキュメントの中の最初のフォルダ)が表示されます。

フォームからカーソルが出ると、新しいフォームを表示してくれるのですが、
そこでもまたGetFile()を繰り返し、「1」フォルダを表示します。

本当はロードしたときに表示するアイテムは「1」フォルダだけで、
新しいフォームを表示したら、「2」フォルダが表示され、新しいフォームを表示するごとにマイドキュメントの中身を順番に一つずつ表示させていきたいです。
+--+
| 1|
+--+

+--+
| 1|
+--+
| 2|
+--+

+--+
| 1|
+--+
| 2|
+--+
| 3|
+--+

どのような考え方をしたらこのような動作ができるかがわかりません。
プログラムの考え方自体がよくないのでしょうか?

どんなことでもいいのでアドバイスをいただけたらうれしいです。
よろしくお願いします。
引用返信 編集キー/
■11931 / inTopicNo.2)  Re[1]: ペン操作によるメニュー展開
□投稿者/ arion (31回)-(2007/12/25(Tue) 17:10:35)
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
using WinApi;

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

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

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

		private static bool _IsTracking = false;
		public System.Windows.Forms.ListView listView1;
		private System.Windows.Forms.ImageList imageList1;
		private System.Windows.Forms.ImageList imageList2;

		public static bool IsTracking
		{
			get { return _IsTracking; }
			set { _IsTracking = value; }
		}

		private static Form1 _HotForm = null;

		public static Form1 HotForm
		{
			get { return _HotForm; }
			set { _HotForm = value; }
		}

		private void StartTrack()
		{
			Form1.IsTracking = true;
			Form1.HotForm = this;

			this.Capture = true;
		}

		private void DoTarck() //マウスカーソルの位置を読み取って新しいフォームを作る
		{
			Point point = Cursor.Position;
			if (this.Bounds.Contains(point)) return;

			this.Capture = false;

			int x = this.Location.X;
			int y = this.Location.Y;

			if (point.X < this.Left)
			{
				x -= this.Width;
			}
			else if (this.Right < point.X)
			{
				x += this.Width;
			}

			if (point.Y < this.Top)
			{
				y -= this.Height;
			}
			else if (this.Bottom < point.Y)
			{
				y += this.Height;
			}

			Form1 form = new Form1();
			form.StartPosition = FormStartPosition.Manual;
			form.Location = new Point(x, y);
			form.Show();
			form.StartTrack();
		}

		private void DoAction()
		{
			this.Capture = false;

			Form1.HotForm = null;
			Form1.IsTracking = false;

			int i = listView1.SelectedIndices[0]; 
			string ss = ((FileSystemInfo)fileinfo[i]).FullName;
			Process.Start(ss);
			Program.MainForm.Close();
		}


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

		#region Windows フォーム デザイナで生成されたコード 
		/// <summary>
		/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディタで変更しないでください。
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.listView1 = new System.Windows.Forms.ListView();
			this.imageList1 = new System.Windows.Forms.ImageList(this.components);
			this.imageList2 = new System.Windows.Forms.ImageList(this.components);
			this.SuspendLayout();
			// 
			// listView1
			// 
			this.listView1.Alignment = System.Windows.Forms.ListViewAlignment.Default;
			this.listView1.AllowDrop = true;
			this.listView1.Location = new System.Drawing.Point(8, 8);
			this.listView1.Name = "listView1";
			this.listView1.Scrollable = false;
			this.listView1.Size = new System.Drawing.Size(80, 80);
			this.listView1.TabIndex = 0;
			this.listView1.DoubleClick += new System.EventHandler(this.listView1_DoubleClick);
			// 
			// imageList1
			// 
			this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
			this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// imageList2
			// 
			this.imageList2.ImageSize = new System.Drawing.Size(16, 16);
			this.imageList2.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
			this.BackColor = System.Drawing.Color.PaleGreen;
			this.ClientSize = new System.Drawing.Size(96, 96);
			this.ControlBox = false;
			this.Controls.Add(this.listView1);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
			this.MaximizeBox = false;
			this.MinimizeBox = false;
			this.Name = "Form1";
			this.ShowInTaskbar = false;
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "Formsnake";
			this.TopMost = true;
			this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.Form1_KeyPress);
			this.Load += new System.EventHandler(this.Form1_Load);
			this.MouseLeave += new System.EventHandler(this.Form1_MouseLeave);
			this.ResumeLayout(false);

		}
		#endregion

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

		private IntPtr hImageSmall;
		private IntPtr hImageLarge;
		private int nIndex=0;
		ArrayList fileinfo = new ArrayList();

		public void GetFile()
		{
			nIndex  =0;
			fileinfo.Clear();		

			foreach(string s in System.IO.Directory.GetFileSystemEntries(@"C:\Documents and Settings\Administrator\My Documents\01"))
			{
				Shell32.SHFILEINFO shfi=new Shell32.SHFILEINFO();
				FileInfo fi=new FileInfo(s);

				//32 x 32サイズのアイコンを取得
				hImageLarge=Shell32.SHGetFileInfo(s,0,ref shfi,(uint)Marshal.SizeOf(shfi),
					Shell32.SHGFI_ICON|Shell32.SHGFI_LARGEICON);
				imageList2.Images.Add(Icon.FromHandle(shfi.hIcon));

				//16 x 16サイズのアイコンを取得
				hImageSmall=Shell32.SHGetFileInfo(s,0,ref shfi,(uint)Marshal.SizeOf(shfi),
					Shell32.SHGFI_ICON|Shell32.SHGFI_SMALLICON);
				imageList1.Images.Add(Icon.FromHandle(shfi.hIcon));
				
				//リストビューにアイテムを追加
				listView1.Items.Add(
					new ListViewItem(
					new string[]{fi.Name,Directory.GetCreationTime(fi.FullName).ToString(),
									Directory.GetLastAccessTime(fi.FullName).ToString()}
					,nIndex++)
					);
				fileinfo.Add(fi);
			}
                  }

		

		private void Form1_Load(object sender, System.EventArgs e)
		{
			this.Size = new Size(96, 96);
			//リストビューのヘッダを作成
			ColumnHeader ch1=new ColumnHeader();
			ch1.Text="File";
			ColumnHeader ch2=new ColumnHeader();
			ch2.Text="CreateDate";
			ColumnHeader ch3=new ColumnHeader();
			ch3.Text="AccessDate";

			//リストビューのヘッダ&イメージリスト&サイズ&ドッキング先の設定
			listView1.Columns.AddRange(new ColumnHeader[]{ch1,ch2,ch3});
			listView1.SmallImageList=imageList1;
			listView1.LargeImageList=imageList2;
			//listView1.Size=new Size(200,Size.Height);
			//listView1.Dock=DockStyle.Left|DockStyle.Bottom|DockStyle.Top;

			//2つのイメージリストのサイズ&色深度の設定
			imageList1.ImageSize=SystemInformation.SmallIconSize;
			imageList1.ColorDepth=ColorDepth.Depth32Bit;

			imageList2.ImageSize=SystemInformation.IconSize;
			imageList2.ColorDepth=ColorDepth.Depth32Bit;

			//ファイルの取得
			GetFile();
		}






		private void Form1_MouseLeave(object sender, System.EventArgs e)
		{
			this.DoTarck();
			Console.WriteLine("認識");
		}






		private void Form1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
		{
			if (e.KeyChar == (char)Keys.Escape)
			{
				Program.MainForm.Close();
			}
		}



		private void listView1_DoubleClick(object sender, System.EventArgs e)
		{
			if (!Form1.IsTracking)
			{
				this.StartTrack();
			}
			else
			{
				if (Form1.HotForm != Program.MainForm)
				{
					this.DoAction();
				}
			}		
		}


	}

	public class Program
	{
		public static Form1 _MainForm = null;

		public static Form1 MainForm
		{
			get { return _MainForm; }
		}
	}
}

引用返信 編集キー/
■11932 / inTopicNo.3)  Re[2]: ペン操作によるメニュー展開
□投稿者/ 囚人 (271回)-(2007/12/25(Tue) 17:41:54)
#ソースは読んでいません。

単にメニューと同じ考えでいいんじゃないですか? それじゃ駄目って事でしょうか?
メニューの「▼」の上を一定時間スタイラスがいれば次のフォームをオープンするような。それを4辺に置いておけばいいんじゃないかなーと。

お望みに仕様だとめちゃくちゃ使い辛いソフトウェアになると思います。個人的な意見ですが。

マウスでもカーソルがジャンプしますが、スタイラスは大ジャンプしませんか? いきなり画面の端をクリックできたり。そのときはオープンしないって仕様ですか?

カーソルが滑ってきたときとジャンプしてきたときの区別はどうするんでしょう?
引用返信 編集キー/
■11943 / inTopicNo.4)  Re[1]: ペン操作によるメニュー展開
□投稿者/ やじゅ (38回)-(2007/12/26(Wed) 00:08:53)
やじゅ さんの Web サイト
No11930 (arion さん) に返信
>
> どのような考え方をしたらこのような動作ができるかがわかりません。
> プログラムの考え方自体がよくないのでしょうか?
>
> どんなことでもいいのでアドバイスをいただけたらうれしいです。
> よろしくお願いします。

アルゴリズムを考える上で、ファイルの読込みやフォームの表示等はまず後回しとして
まず、Picture等で絵(アイコン)などを思ったとおりに表示できるようになってから
絵(アイコン)などをフォームに置き換え、次はファイルの読込みを作成するなど、
順を追っていった方がいいですよ。

やりたいことが一度にやれる程の技術がないと思うなら、まずコツコツとやるべし。
引用返信 編集キー/
■11944 / inTopicNo.5)  Re[2]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (2回)-(2007/12/26(Wed) 00:18:47)
2008/01/03(Thu) 22:49:22 編集(投稿者)
2007/12/26(Wed) 00:39:47 編集(投稿者)
2007/12/26(Wed) 00:32:46 編集(投稿者)
2007/12/26(Wed) 00:29:55 編集(投稿者)
2007/12/26(Wed) 00:23:14 編集(投稿者)

12回目の投稿です。

 arionさん、はじめまして。
 私が一杯食わされましたね(^^。

 すなわち、
   各Formに表示するファイル、フォルダは1つのみで、
   「1」、「2」、「3」は全てフォルダで、
   右にドラッグするとそのフォルダの中身を表示(サブディレクトリは・・・)
   左にドラッグするとファイル表示を消去
   上にドラッグするとフォルダ表示を消去 [追記]この行の記述は的外れの可能性あり
 という理解でよろしいですね。

 とりあえず考え付いた範囲で(内容の自信度は50%)、

  <対策>
  1.Form1のコンストラクタに引数を渡す(「1」、「2」、「3」に相当する数字等)。
  2.Form1のメンバに
     フォルダを表示しているFormなのか、
     ファイル     同上
    を識別するための変数を用意。

 これで、「毎回「1」が表示される問題」は解決可能と思います。

 ※コードは「こんな感じで」程度に見てください。(文法上の単純ミスがあるかもしれません)
  私の例よりさらにスマートな書き方が多分あります。

                   [修正]08/01/03文法の誤りを訂正
public enum MyType{ //名前は適当
Folder,
File
}

public class MyData{ //名前は適当
public MyType mytype;
public string name;
public int number;
}

public class Form1{

public MyData _mydata=new MyData(); //本来はプロパティで公開

public Form1():this(MyType.Folder,Environment.GetFolderPath(Environment.SpecialFolder.Personal),0){
}

public Form1(MyType mt,string directoryname, int number){
InitializeComponent();
_mydata.mytype=mt;
_mydata.name=directoryname;
_mydata.number=number;
}

private void this_load(略){
//(中略)
if (_mydata.mytype==MyType.Folder){
this.dispdirectory(_mydata.name,_mydata.number);

}else if(_mydata.mytype==MyType.File){
this.dispfile(_mydata.name,_mydata.number);

}else{
//ここには来ない
}
//※GetFileは呼び出さない
}

private void dispdirectory(string parentdirectoryname,int directorynumber){

string[] ssa=Directory.GetDirectories(parentdirectoryname);
string ss2=ssa[directorynumber];
//ss2のみListView(とArrayList)に追加
}

private void dispfile(string directoryname,int filenumber){

string[] ssa=Directory.GetFiles(directoryname);
string ss2=ssa[filenumber];
//ss2のみListView(とArrayList)に追加
}

}//End Class Of Form1

 以上、取り急ぎご報告いたします。おやすみなさい。

以上です。

引用返信 編集キー/
■11949 / inTopicNo.6)  Re[1]: ペン操作によるメニュー展開
□投稿者/ Jitta on the way (70回)-(2007/12/26(Wed) 07:12:48)
No11930 (arion さん) に返信

コマンドプロンプトで、[TAB]キーを押しているイメージですか。
面白いけど、使いにくいようにも思います。

で、今質問されている箇所って、オリジナリティの肝の部分じゃないですか?

あと、ファイルが100個あったらどうします?画面に収まりきらないですよね?あとから「あ〜!こんな障害がっ!」となるより、異常状態のケースは、思いつくだけ列挙しておくといいですよ。コードでの回避策まで用意しろとは言いません。判断地点と判断方法は用意しておきましょう。
引用返信 編集キー/
■11999 / inTopicNo.7)  Re[1]: ペン操作によるメニュー展開
□投稿者/ Jitta (442回)-(2007/12/26(Wed) 21:35:51)
Jitta さんの Web サイト
No11930 (arion さん) に返信

> どんなことでもいいのでアドバイスをいただけたらうれしいです。
> よろしくお願いします。

 ファイル一覧を管理するクラスが必要かと思います。
今の状態だと、GetFile() メソッドが呼ばれるごとにファイル一覧を読み直しています。
これでは自分が何を表示しているのか、次のフォームが何を表示するべきなのか、わかりません。


> private void DoTarck()
 x += this.With って、どこになりますか?ここは、x = this.Width + 1 くらいではないでしょうか。
 また、上や左へのアクションは、フォームを「隠す」ではなかったでしょうか?


> public class Program
 カプセル化するならきっちりやりましょうよ。

public class Program
{
    private static Form1 _MainForm = new Form1();
    public static Form1 MainForm {
        get { return this._MainForm; }
    }
}


> Program.MainForm.Close();
 メイン フォームを閉じると、アプリケーションが終了します。それでいいのでしょうか?

引用返信 編集キー/
■12369 / inTopicNo.8)  Re[3]: ペン操作によるメニュー展開
□投稿者/ arion (1回)-(2008/01/08(Tue) 18:17:49)
遅くなってすいません。
みなさん書き込みありがとうございます。

No11944 (引っ込んだID非公開 さん) に返信

>  すなわち、
>    各Formに表示するファイル、フォルダは1つのみで、
そうです。

>    「1」、「2」、「3」は全てフォルダで、
「1」、「2」、「3」はマイドキュメント等のある指定したフォルダの中身を表しているので、フォルダだったりファイルだったりします。(マイピクチャとかテキストファイルなど)

>    右にドラッグするとそのフォルダの中身を表示(サブディレクトリは・・・)
例として挙げた動作ではそうです。

例で挙げた動作以外にも、
+--+
|1|
+--+

このフォームからカーソルが右に出た場合には、

+--++--+
| 1| | 2 |
+--++--+

と表示され、さらに右にでると、
+--++--++--+
| 1| | 2 | | 3 |
+--++--++--+
となり、ここで「2」にもどると「3」が消えて
+--++--+
| 1| | 2 |
+--++--+
となります。この状態(カーソルが「2」にある状態)で下(または上)に方向を転換すると(90度転換)、次からは「2」の中身が表示されるようにしたいです。


わかりにくいと思うんですが、
基本的な動きは、
カーソルの動きにあわせてフォームが次々と出てきてくれて、
一つ前のフォームに戻ると、新しく表示されていたフォームが消えます。

最初に表示されたフォームから上方向、または下方向にカーソルを動かしている限りは、最初に設定したフォルダの中身が表示され(例ではマイドキュメント)、
あるフォルダのところで左か右に90度方向を変えると、次からは新しいフォームにそのフォルダの中身を表示します。

また、

最初に表示されたフォームから右方向、または左方向にカーソルを動かしている限りは、最初に設定したフォルダの中身が表示され(例ではマイドキュメント)、
あるフォルダのところで上か下に90度方向を変えると、次からは新しいフォームにそのフォルダの中身を表示します。

フォルダの展開をクリックではなく方向転換で行いたいと思っています。


とりあえずこのような動作です。

皆さんの書き込みを理解するのにもう少し時間がかかるのでまた投稿します。
よろしくおねがいします。


引用返信 編集キー/
■12384 / inTopicNo.9)  Re[4]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (1回)-(2008/01/08(Tue) 23:27:41)
2008/01/13(Sun) 00:58:28 編集(投稿者)
2008/01/08(Tue) 23:43:27 編集(投稿者)

13回目の投稿です

 arionさん、お久しぶりです。
 (投稿のタイミングが重なったのは、本当に偶然の一致です)

 私の個人的趣味で、arionさんのコードを参考にして私なりにSnakeを作成してみました。

 コードがVBですがご了承下さい。
 VB2008で動作確認しましたが、VB2005でも多分動作します。

 プログラム内でファイルへの書き込みは一切行っておりませんが、
 念のため使用は自己責任でお願いします。
 もちろんコードの改造は自由です。


  <詳細の説明>
   本プログラムは5つのクラスから構成されます。

    1.ContentSnakeBase(丸ごと再利用可能)・・・Snake動作の基本機能を提供。
    2.Launcher(Of T) (丸ごと再利用可能)・・・汎用ランチャー。
    3.Shell32     (丸ごと再利用可能)・・・ファイル、フォルダのアイコンを取得するためのクラス。
  [追記] ↑Jittaさんの仰っていた「カプセル化はきっちりと」の一例(のつもり)。

    4.SnakeExplorer     ・・・・・・・・・・ContentSnakeBaseの派生クラス。
                             Explorerに関する処理を記述しています。
    5.Program        ・・・・・・・・・・アプリケーションのエントリポイント。

  <ContentSnakeBaseの機能>
  [追記]↓やじゅさんの仰っていた「順を追っていった方が良い」の一例。
      ↓すなわち、まず「基本機能の部分」を基本クラスとして作成し、
      ↓     次に「付加機能の部分」を派生クラスで作成。
      ↓ここで、基本クラスを再利用可能な形にすることがポイント。[ここまで追記]

    1.巨大な透明FormにControlを表示する方法で、Snakeを表現しています。
    2.Controlの表示、消去はVisibleの切り替えではなく、Controlインスタンスの生成、破棄を行います。
    3.マウスの動きに合わせてSnakeが延伸します。
    4.Snakeの「パーツ」(すなわち各Content)は、System.Windows.Forms.Control(もしくはその派生クラス)の
       インスタンスです。(インスタンス生成自体はContentSnakeBaseの派生クラスで行う)
    5.マウスの方向にSnakeを自動延伸させる/させない、を選べます。(AutoSnake、AutoSnakeIntervalプロパティ)
  [追記] ↑囚人さんの仰っていた「カーソルが瞬間移動した場合」の対策の一例。

    6.マウスを軌跡と逆方向に動かした場合に、Snakeを短縮させる/させない、を選べます。(CanAutoShrinkプロパティ)
    7.各Contentに輪郭線を描画する/しない、を選べます。
       (ShowContentsBorderLine、ContentsBorderLineWidth、ContentsBorderLineColorプロパティ)
    8.Snakeは途中で分岐できません。Snakeは「一本道」で、HotContentは常にSnakeの先頭です。
    9.自分自身の軌跡とは交差できません。(すなわち、「輪っか」は作れない)

   ContentSnakeBaseの派生クラスを作成すれば、自作コンテンツでSnakeできます。
   arionさんのほうでも是非面白いコンテンツを考えてみてください。
   (後述しますが、VC#2005以降で派生クラスを作成可能です)
   私が作成したコンテンツ(SnakeExplorer)は、結果的にarionさんの仕様とはかなり異なったものになりました。


  <SnakeExplorerの仕様>
    1.マイドキュメントの中身を表示します。(変更可能)
    2.Snakeの延伸方向に関わらず、フォルダの中身を順番に表示します。
  [追記] ↑Jittaさんの仰っていた「ファイルが100個ある場合」の回避策の一例。

    3.ファイルをダブルクリックすると、そのファイルを開いて、Snakeが閉じます。
    4.フォルダをダブルクリックすると、
        Snakeがそのフォルダまで短縮し、
        以降はそのフォルダの中身を(Snakeの延伸方向に関わらず)順番に表示します。
    5.背景色は、
        HotContentは、水色
        ダブルクリックしたフォルダは、赤
        その他のContentは、ディレクトリ階層の深さに応じて変化します。
    6.実用性は・・・・・・・・・聞かないで下さい(汗


 これから全コードを投稿します。

 # コードがかなり長いので、投稿してよいか迷いましたが・・・
 # arionさんのコードが8KBで、私のコードは32KBです。
 # 4回に分けて、意を決して図表モードで投稿します。 [追記]本体5回、おまけ1回の計6回になりました。

 念のための補足
  1.プロジェクトのプロパティで
      「アプリケーションフレームワークを有効にする」チェックを外し、
      スタートアップフォーム(スタートアップオブジェクト)を「Sub Main」に設定
    して下さい。
  2.Windowsフォームデザイナは開かないで下さい。
  3.VB2005以降でコンパイルしてアセンブリを作成し、VC#2005以降のプロジェクトから参照すれば、
    VC#で派生クラス等のコードを作成できます。

以上です。
                 (続く)
引用返信 編集キー/
■12385 / inTopicNo.10)  Re[5]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (2回)-(2008/01/08(Tue) 23:28:38)
'                 (続き)
'               (コードの始まり)    1/4

Imports System.Collections
Imports System.ComponentModel
Imports System.Data
Imports System.IO
Imports System.Runtime.InteropServices

'エントリポイント
Public Class Program
    Public Shared Sub Main()
        Application.EnableVisualStyles()
        Dim frm As New Launcher(Of SnakeExplorer)
        ' マイドキュメントの中身を表示
        Dim path As String = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
        frm.SetStartupInformation(path)
        Application.Run(frm)
    End Sub
End Class


'(丸ごと再利用可能)汎用ランチャー
Public Class Launcher(Of T As {New, ContentSnakeBase})
    Inherits System.Windows.Forms.Form

    Dim WithEvents BtnRun As New Button
    Dim WithEvents frm As T
    Dim isTracking As Boolean = False
    Dim offset As New Point(0, 0)

    Public Sub New()
        Me.ClientSize = New Size(100, 50)
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.Fixed3D
        Me.MinimizeBox = False
        Me.MaximizeBox = False
        Me.Text = "ランチャー"
        BtnRun.Text = "Start"
        BtnRun.Dock = DockStyle.Fill
        Me.Controls.Add(BtnRun)
    End Sub

    Private m_startinfo As New Object
    Public Sub SetStartupInformation(ByVal info As Object)
        Me.m_startinfo = info
    End Sub

    Private Sub BtnRun_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnRun.Click
        If isTracking = False Then
            isTracking = True

            frm = New T
            ' ↓Lancher移動時にSnakeもついてくるようにするために必要な情報
            offset = New Point(frm.Left - Me.Left, frm.Top - Me.Top)
            ' StartupInformation(この例ではマイドキュメントのパス)を渡す
            frm.StartupInformation = Me.m_startinfo
            ' 最初のContentをLauncherの真下に表示
            frm.FirstContentScreenPosition = New Point(Me.Left, Me.Top + Me.Height)
            ' 輪郭線を描画
            frm.ShowContentsBorderLine = True
            frm.ContentsBorderLineColor = Color.BurlyWood
            frm.ContentsBorderLineWidth = 5
            ' ↓Trueにすると、指定時間間隔毎にカーソルの方向へSnakeが延伸
            ' ↓Trueのほうが操作性がまだまし
            frm.AutoSnake = True
            frm.AutoSnakeInterval = 200 '←単位はミリ秒
            ' ↓マウスを逆方向に動かした場合に、Snakeを短縮させるなら、True
            ' ↓(※AutoSnake=Trueの場合は、CanAutoShrink=Falseにしたほうが良いです)
            ' ↓SnakeExplorerでは、Trueにするとファイル、フォルダが正しく表示されない場合がある。
            ' ↓(赤いフォルダを超えてSnakeを短縮させた場合)
            frm.CanAutoShrink = False

            frm.Show()
            Cursor.Position = New Point(Me.Left + 30, Me.Top + Me.Height + 30)
        Else
            'Snake表示中に再度ボタンを押すと、Snakeを閉じる
            If frm IsNot Nothing Then frm.Close()
        End If
    End Sub

    Private Sub frm_FormClosed(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles frm.FormClosed
        isTracking = False
    End Sub

    Private Sub Me_LocationChanged(ByVal sender As Object, _
        ByVal e As System.EventArgs) Handles Me.LocationChanged
        If isTracking = False Then Return
        frm.Location = New Point(Me.Location.X + offset.X, Me.Location.Y + offset.Y)
    End Sub
End Class


'(丸ごと再利用可能)ファイル/フォルダのアイコン画像取得用のクラス
Public Class Shell32
    Public Const SHGFI_ICON As UInt32 = &H100
    Public Const SHGFI_LARGEICON As UInt32 = &H0
    Public Const SHGFI_SMALLICON As UInt32 = &H1

    Public Structure SHFILEINFO
        Public hIcon As IntPtr
        Public iIcon As Integer
        Public dwAttributes As UInt32
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
        Public szDisplayName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
        Public szTypeName As String
    End Structure

    <DllImport("shell32.dll")> _
    Public Shared Function SHGetFileInfo(ByVal pszPath As String, ByVal dwFileAttributes As UInt32, _
        ByRef psfi As SHFILEINFO, _
        ByVal cbFileInfo As UInt32, _
        ByVal uFlags As UInt32) As IntPtr
    End Function

    ''' <summary>
    ''' 32 x 32サイズのアイコンを取得
    ''' </summary>
    ''' <param name="fileordirectoryname">ファイル名、ディレクトリ名</param>
    Public Shared Function Get32x32Icon(ByVal fileordirectoryname As String) As Icon
        Dim shfi As New SHFILEINFO
        Dim hImageLarge As IntPtr
        hImageLarge = Shell32.SHGetFileInfo(fileordirectoryname, 0, shfi, _
            Convert.ToUInt32(Marshal.SizeOf(shfi)), Shell32.SHGFI_ICON Or Shell32.SHGFI_LARGEICON)
        Dim ic As Icon = Icon.FromHandle(shfi.hIcon)
        Return ic
    End Function

    ''' <summary>
    ''' 16 x 16サイズのアイコンを取得
    ''' </summary>
    ''' <param name="fileordirectoryname">ファイル名、ディレクトリ名</param>
    Public Shared Function Get16x16Icon(ByVal fileordirectoryname As String) As Icon
        Dim shfi As New SHFILEINFO
        Dim hImageSmall As IntPtr
        hImageSmall = Shell32.SHGetFileInfo(fileordirectoryname, 0, shfi, _
            Convert.ToUInt32(Marshal.SizeOf(shfi)), Shell32.SHGFI_ICON Or Shell32.SHGFI_SMALLICON)
        Dim ic As Icon = Icon.FromHandle(shfi.hIcon)
        Return ic
    End Function
End Class

'                 (続く)    1/4

引用返信 編集キー/
■12386 / inTopicNo.11)  Re[6]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (3回)-(2008/01/08(Tue) 23:29:24)
'                 (続き)    2/4

'派生クラスの一例(Explorer関連の処理を記述)
Public Class SnakeExplorer
    Inherits ContentSnakeBase

    Private fileNumber As Integer = 0
    Private FileList As List(Of FileSystemInfo)
    Private directoryDepth As Integer = 0

    Private Sub initializeFileList(ByVal path As String)
        If FileList Is Nothing Then
            FileList = New List(Of FileSystemInfo)
        Else
            FileList.Clear()
        End If
        Dim ssd() As String = Directory.GetDirectories(path)
        Dim ssf() As String = Directory.GetFiles(path)
        For Each ss As String In ssd
            FileList.Add(New DirectoryInfo(ss))
        Next
        For Each ss As String In ssf
            FileList.Add(New FileInfo(ss))
        Next
        fileNumber = 0
    End Sub

    Protected Overrides Function OnCreateNewContent(ByVal cx As Integer, ByVal cy As Integer, _
        ByVal dr As Direction) As System.Windows.Forms.Control
        'cx、cyはContent(ここではControlと同義)を格子に見立てたときの座標です。
        'フォーム起動時に最初に表示されるContentの(cx,cy)は(100,100)、
        'その右隣のContentは(101,100)、下隣のContentは(100,101)です。
        'ここで(100,100)の「100」は、基本クラスのInitialCX、InitialCYで定義されています。
        '
        'drは、Contentの展開方向です(例えば、下に展開した場合はDirection.Down)
        '
        'Contentを表示する場合は、Controlインスタンスを返します。
        'Contentを作成しない場合はNothingを返してください。
        '各Contentのサイズが同一でない場合も多分動作しますが、画面表示が変になる場合があります。
        '(例えば、Contentが重なって表示される、Formの端でContentの一部が描画されない等)
        '
        If Me.FileList Is Nothing Then
            ' ↓StartupInformationがNothingになることはない
            Dim path As String = Me.StartupInformation.ToString
            If Directory.Exists(path) = False Then
                Throw New DirectoryNotFoundException("ディレクトリ " + path + " が見つかりません。")
            End If
            initializeFileList(path)
        End If
        If FileList.Count < fileNumber + 1 Then
            '表示するファイルがない
            Return Nothing
        End If
        Dim ofe As New OneFileExplorer(FileList.Item(fileNumber), directoryDepth)
        fileNumber += 1
        AddHandler ofe.DoubleClick, AddressOf Me.OneFileExplorer_DoubleClick
        Return ofe
    End Function

    Protected Overrides Sub OnClosingContent(ByVal cw As ContentWrapper)
        'Content消去前にイベントハンドラを削除
        Dim ofe As OneFileExplorer = DirectCast(cw.Content, OneFileExplorer)
        RemoveHandler ofe.DoubleClick, AddressOf Me.OneFileExplorer_DoubleClick
        If fileNumber >= 1 Then fileNumber -= 1
    End Sub

    Protected Overrides Sub OnHotContentChanging(ByVal cw As ContentSnakeBase.ContentWrapper)
        '今までHotContentだったContentの背景色を元に戻す
        Dim ofe As OneFileExplorer = DirectCast(cw.Content, OneFileExplorer)
        If ofe.BackColor = ofe.colorHot Then
            ofe.BackColor = ofe.colorDefault
        End If
    End Sub

    Protected Overrides Sub OnHotContentChanged(ByVal cw As ContentSnakeBase.ContentWrapper)
        'HotContentの背景色を変更
        Dim ofe As OneFileExplorer = DirectCast(cw.Content, OneFileExplorer)
        If ofe.BackColor = ofe.colorDefault Then
            ofe.BackColor = ofe.colorHot
        End If
    End Sub

    Protected Overrides Sub OnPaintContent(ByVal cw As ContentSnakeBase.ContentWrapper, _
        ByVal e As System.Windows.Forms.PaintEventArgs)
        '
        '引数cwには、Contentの連接方向や座標データが格納されているので、
        'これらの情報を用いて描画したい場合にはここに処理を書いてください。
        '
    End Sub

    Private Sub OneFileExplorer_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim mc As OneFileExplorer = DirectCast(sender, OneFileExplorer)
        Dim ty As Type = mc.FSI.GetType
        Dim ss As String = mc.FSI.FullName
        If ty Is GetType(DirectoryInfo) Then
            'フォルダをダブルクリック
            Me.TruncateSnake(mc)
            mc.BackColor = mc.colorDirectory
            initializeFileList(ss)
            Me.directoryDepth = mc.directoryDepth + 1
        ElseIf ty Is GetType(FileInfo) Then
            'ファイルをダブルクリック
            Process.Start(ss)
            Me.Close()
        End If
    End Sub

    '「Snakeのパーツ」を定義したクラス
    Private Class OneFileExplorer
        Inherits System.Windows.Forms.Control

        '↓ディレクトリ階層の深さに応じてBackColorが変化します。
        Private Allcolor() As Color = {Color.Azure, Color.AntiqueWhite, Color.LemonChiffon, Color.Wheat}
        '↓環境に応じて適宜変更してください。Controlのサイズはこれに連動して決定されます。
        Private IconSize As New Size(40, 40)

        Public colorDefault As Color = Color.White
        Public colorDirectory As Color = Color.LightSalmon
        Public colorHot As Color = Color.Aqua
        Public ReadOnly FSI As FileSystemInfo
        Public ReadOnly IconImage As Icon
        Public directoryDepth As Integer = 0
        Private m_iconRectangle As Rectangle
        Private m_textRectangle As Rectangle
        Private m_strFormat As New StringFormat

        Public Sub New(ByVal fsi As FileSystemInfo, ByVal directorydepth As Integer)
            Me.FSI = fsi
            Me.directoryDepth = directorydepth
            Dim i As Integer = directorydepth Mod Allcolor.Length
            Me.colorDefault = Allcolor(i)
            Me.BackColor = Me.colorDefault
            Me.IconImage = Shell32.Get32x32Icon(fsi.FullName)
            Dim sz As Size = Me.IconSize
            Me.Size = New Size(CInt(sz.Width * 2), CInt(sz.Height * 2.3))
            m_iconRectangle = New Rectangle(CInt(sz.Width * 0.5), CInt(sz.Height * 0.25), _
                sz.Width, sz.Height)
            m_textRectangle = New Rectangle(CInt(sz.Width * 0.1), CInt(sz.Height * 1.25) + 3, _
                CInt(sz.Width * 1.8), 40)
            m_strFormat.Alignment = StringAlignment.Center
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            'アイコンとファイル名を直接描画
            e.Graphics.DrawIcon(Me.IconImage, m_iconRectangle)
            e.Graphics.DrawString(Me.FSI.Name, SystemFonts.MessageBoxFont, Brushes.Black, _
                m_textRectangle, m_strFormat)
            MyBase.OnPaint(e)
        End Sub
    End Class

End Class

'                 (続く)    2/4

引用返信 編集キー/
■12387 / inTopicNo.12)  Re[7]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (4回)-(2008/01/08(Tue) 23:30:31)
'                 (続き)    3/4

'(丸ごと再利用可能)Snake動作の基本機能を提供
Public MustInherit Class ContentSnakeBase
    Inherits System.Windows.Forms.Form

    '////////抽象メソッド達
    Protected MustOverride Function OnCreateNewContent(ByVal cx As Integer, ByVal cy As Integer, _
        ByVal dr As Direction) As Control
    Protected MustOverride Sub OnClosingContent(ByVal cw As ContentWrapper)
    Protected MustOverride Sub OnHotContentChanging(ByVal cw As ContentWrapper)
    Protected MustOverride Sub OnHotContentChanged(ByVal cw As ContentWrapper)
    Protected MustOverride Sub OnPaintContent(ByVal cw As ContentWrapper, ByVal e As PaintEventArgs)

    '////////初期化関連
    Private components As IContainer = New System.ComponentModel.Container()
    Private WithEvents Timer1 As New System.Windows.Forms.Timer(components)

    Protected ReadOnly InitialCX As Integer = 100
    Protected ReadOnly InitialCY As Integer = 100
    Private m_startupContent As ContentWrapper
    Private m_firstContentScreenPosition As New Point(0, 0)
    ''' <summary>
    ''' 起動時に最初に表示されるContentのLocationをスクリーン座標で指定します。(既定は(0,0))
    ''' </summary>
    Public Property FirstContentScreenPosition() As Point
        Get
            Return m_firstContentScreenPosition
        End Get
        Set(ByVal value As Point)
            m_firstContentScreenPosition = value
        End Set
    End Property

    Public Sub New()
        initialize()
    End Sub
    Private Sub ContentSnakeBase_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim p As Point = Me.PointToClient(m_firstContentScreenPosition)
        Me.m_startupContent = Me.createContent(p.X, p.Y, Me.InitialCX, Me.InitialCY, Direction.None)
    End Sub

    'フォームがコンポーネントの一覧をクリーンアップするために dispose をオーバーライドします。
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
        End If
        MyBase.Dispose(disposing)
    End Sub

    Private Sub initialize()
        Me.SuspendLayout()
        Me.KeyPreview = True
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 12)
        Me.BackColor = System.Drawing.Color.PaleGreen
        Me.TransparencyKey = Color.PaleGreen
        Me.Location = New Point(0, 0)
        Me.ClientSize = New Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
        Me.ControlBox = False
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
        Me.MaximizeBox = False
        Me.MinimizeBox = False
        Me.Name = "ContentSnakeBase1"
        Me.ShowInTaskbar = False
        Me.StartPosition = FormStartPosition.Manual
        Timer1.Enabled = m_autoSnake
        Timer1.Interval = m_autoSnakeInterval
        Me.ResumeLayout(False)
    End Sub

    '////////プロパティ

    Private m_startupInfomation As New Object
    ''' <summary>
    ''' 派生クラス等で上手く活用してください。(System.Windows.Forms.ControlのTagプロパティに相当)
    ''' (※Nothingは代入できません)
    ''' </summary>
    Public Property StartupInformation() As Object
        Get
            Return m_startupInfomation
        End Get
        Set(ByVal value As Object)
            If value IsNot Nothing Then
                m_startupInfomation = value
            End If
        End Set
    End Property

    Private m_canAutoShrink As Boolean = True
    ''' <summary>
    ''' マウスを逆方向に動かした場合に、Snakeを短縮させるなら、True。(既定はTrue)
    ''' (※AutoSnake=Trueの場合は、CanAutoShrink=Falseにしたほうが良いです)
    ''' </summary>
    Public Property CanAutoShrink() As Boolean
        Get
            Return m_canAutoShrink
        End Get
        Set(ByVal value As Boolean)
            m_canAutoShrink = value
        End Set
    End Property

    Private m_autoSnake As Boolean = False
    ''' <summary>
    ''' マウスの方向にSnakeを自動延伸させる場合はTrue。(既定はFalse)
    ''' </summary>
    Public Property AutoSnake() As Boolean
        Get
            Return m_autoSnake
        End Get
        Set(ByVal value As Boolean)
            m_autoSnake = value
            Timer1.Enabled = m_autoSnake
        End Set
    End Property

    Private m_autoSnakeInterval As Integer = 500
    ''' <summary>
    ''' Snakeを自動延伸させる場合の時間間隔(ミリ秒)(既定は500)
    ''' </summary>
    Public Property AutoSnakeInterval() As Integer
        Get
            Return m_autoSnakeInterval
        End Get
        Set(ByVal value As Integer)
            If value >= 100 AndAlso value <= 60000 Then
                m_autoSnakeInterval = value
                Timer1.Interval = value
            End If
        End Set
    End Property

    Private m_contentsBorderLineColor As Color = Color.BurlyWood
    ''' <summary>
    ''' 各Contentsの境界線の色(既定はColor.BurlyWood)
    ''' </summary>
    Public Property ContentsBorderLineColor() As Color
        Get
            Return m_contentsBorderLineColor
        End Get
        Set(ByVal value As Color)
            m_contentsBorderLineColor = value
        End Set
    End Property

    Private m_contentsBorderLineWidth As Integer = 5
    ''' <summary>
    ''' 各Contentsの境界線の幅(既定は5)。
    ''' </summary>
    Public Property ContentsBorderLineWidth() As Integer
        Get
            Return m_contentsBorderLineWidth
        End Get
        Set(ByVal value As Integer)
            m_contentsBorderLineWidth = value
        End Set
    End Property

    Private m_showContentsBorderLine As Boolean = True
    ''' <summary>
    ''' 各Contentsに境界線を表示させる場合はTrue。(既定はTrue)
    ''' </summary>
    Public Property ShowContentsBorderLine() As Boolean
        Get
            Return m_showContentsBorderLine
        End Get
        Set(ByVal value As Boolean)
            m_showContentsBorderLine = value
        End Set
    End Property

    Private Shared m_hotContent As ContentWrapper = Nothing
    ''' <summary>
    ''' Snakeの先頭Contentを返します(SetアクセサはPrivateです)
    ''' </summary>
    Public Property HotContent() As ContentWrapper
        Get
            Return m_hotContent
        End Get
        Private Set(ByVal value As ContentWrapper)
            If m_hotContent IsNot value Then
                If m_hotContent IsNot Nothing AndAlso m_hotContent.Content IsNot Nothing Then
                    ' ↓派生クラスに処理のチャンスを与える
                    Me.OnHotContentChanging(m_hotContent)
                    RemoveHandler m_hotContent.Content.MouseLeave, AddressOf Me.HotPanel_MouseLeave
                End If
                m_hotContent = value
                If value IsNot Nothing Then
                    AddHandler m_hotContent.Content.MouseLeave, AddressOf Me.HotPanel_MouseLeave
                    ' ↓派生クラスに処理のチャンスを与える
                    Me.OnHotContentChanged(value)
                End If
            End If
        End Set
    End Property

    '////////イベントハンドラ達

    Private Sub HotPanel_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs)
        Me.DoTrack()
    End Sub
    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If ActiveForm Is Me Then
            Me.HotPanel_MouseLeave(Me, EventArgs.Empty)
        End If
    End Sub

    ' ESCキー押下で終了
    Private Sub FormSnakeBase_KeyDown(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        If e.KeyCode = Keys.Escape Then
            Me.Close()
        End If
    End Sub

End Class

'                 (続く)    3/4

引用返信 編集キー/
■12388 / inTopicNo.13)  Re[8]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (5回)-(2008/01/08(Tue) 23:37:55)
'                 (続き)    4/4

Partial Public MustInherit Class ContentSnakeBase

    '////////Snake付帯情報

    '輪郭線描画のためだけに必要な列挙体(Contentの連接方向を表す)
    Public Enum Direction
        None
        Up
        Down
        Left
        Right
    End Enum
    Private Function GetOppositeDirection(ByVal dr As Direction) As Direction
        Select Case dr
            Case Direction.None : Return Direction.None
            Case Direction.Down : Return Direction.Up
            Case Direction.Up : Return Direction.Down
            Case Direction.Left : Return Direction.Right
            Case Direction.Right : Return Direction.Left
        End Select
    End Function

    'Content達を格納する2次元配列(実体は2重List)
    Private AllContents As New TwoDimensionList(Of ContentWrapper)
    'Snakeの軌跡を格納するStack
    Private SnakeLocus As New Stack(Of ContentWrapper)

    'Contentの付帯情報を保存するために用意したクラス
    Public Class ContentWrapper
        Public WithEvents Content As Control
        Public XY As Point
        Public PrevDir As Direction = Direction.None
        Public NextDir As Direction = Direction.None
        Public m_showborderline As Boolean = False
        Public m_borderlinewidth As Integer = 5
        Public m_borderlinecolor As Color = Color.Beige
        Public Parent As ContentSnakeBase

        'Contentの輪郭線を描画
        Private Sub Content_Paint(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.PaintEventArgs) Handles Content.Paint
            'ContentSnakeBaseの派生クラスに描画処理のチャンスを与える
            If Parent IsNot Nothing Then Parent.OnPaintContent(Me, e)

            If m_showborderline = False Then Return

            Dim c As Control = Me.Content
            Dim w As Integer = Me.m_borderlinewidth
            '↓連接部分の境界線の幅は narrow*2 になります。適宜変更してください
            Dim narrow As Integer = 1

            Dim br As New SolidBrush(Me.m_borderlinecolor)
            Dim bback As New SolidBrush(c.BackColor)

            Dim g As Graphics = e.Graphics
            Dim r As Rectangle = c.ClientRectangle

            '最初に、四方に太い輪郭線を描画
            g.FillRectangle(br, 0, 0, r.Width, w)
            g.FillRectangle(br, 0, r.Height - w, r.Width, w)
            g.FillRectangle(br, 0, 0, w, r.Height)
            g.FillRectangle(br, r.Width - w, 0, w, r.Height)

            '次に、連接部分の境界線を細くする
            For Each dr As Direction In New Direction() {PrevDir, NextDir}
                Select Case dr
                    Case Direction.Up
                        g.FillRectangle(bback, w, narrow, r.Width - 2 * w, w - narrow)
                    Case Direction.Down
                        g.FillRectangle(bback, w, r.Height - w, r.Width - 2 * w, w - narrow)
                    Case Direction.Left
                        g.FillRectangle(bback, narrow, w, w - narrow, r.Height - 2 * w)
                    Case Direction.Right
                        g.FillRectangle(bback, r.Width - w, w, w - narrow, r.Height - 2 * w)
                End Select
            Next
            br.Dispose()
            bback.Dispose()
        End Sub
    End Class

    '2次元配列を2重Listで代用
    Private Class TwoDimensionList(Of T)
        Private m_list As New List(Of List(Of T))
        ' 添え字オーバーを防止するために必要
        Private Sub ensureIndexExists(ByVal x As Integer, ByVal y As Integer)
            Do While m_list.Count < x + 1
                m_list.Add(New List(Of T))
            Loop
            Dim li As List(Of T) = m_list.Item(x)
            Do While li.Count < y + 1
                li.Add(Nothing)
            Loop
        End Sub
        Default Public Property Item(ByVal x As Integer, ByVal y As Integer) As T
            Get
                Me.ensureIndexExists(x, y)
                Return m_list.Item(x).Item(y)
            End Get
            Set(ByVal value As T)
                Me.ensureIndexExists(x, y)
                m_list.Item(x).Item(y) = value
            End Set
        End Property
        Public Sub ClearAll()
            For Each li As List(Of T) In m_list
                li.Clear()
            Next
            m_list.Clear()
        End Sub
    End Class

End Class
'                 (続く)    4/4
'         1回の投稿は10KB以内でなければならないようです。

引用返信 編集キー/
■12389 / inTopicNo.14)  Re[9]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (6回)-(2008/01/08(Tue) 23:39:12)
'                 (続き)    再び4/4

Partial Public MustInherit Class ContentSnakeBase


    '////////Snakeの表示、消去関連

    ''' <summary>
    ''' 引数で指定したContent(←これ自体は残ります)までSnakeを短縮します。 
    ''' 起動時に表示されていた先頭のContentは消去されません。
    ''' </summary>
    Protected Sub TruncateSnake(ByVal cw As ContentWrapper)
        Me.TruncateSnake(cw.Content)
    End Sub
    ''' <summary>
    ''' 引数で指定したContent(←これ自体は残ります)までSnakeを短縮します。 
    ''' 起動時に表示されていた先頭のContentは消去されません。
    ''' </summary>
    Protected Sub TruncateSnake(ByVal c As Control)
        Dim tmp As ContentWrapper
        Do
            tmp = Me.SnakeLocus.Peek()
            If (tmp.Content Is c) Or (tmp.Content Is m_startupContent.Content) Then Exit Do
            tmp = Me.SnakeLocus.Pop()
            Me.closeContent(tmp)
        Loop
        tmp.NextDir = Direction.None
        tmp.Content.Invalidate()
        Me.HotContent = tmp
    End Sub
    ''' <summary>
    ''' 引数で指定した個数だけSnakeを短縮します。
    ''' 起動時に表示されていた先頭のContentは消去されません。
    ''' </summary>
    Protected Sub TruncateSnake(ByVal cnt As Integer)
        Dim i As Integer = 0
        Dim tmp As ContentWrapper
        Do
            tmp = Me.SnakeLocus.Peek()
            If tmp.Content Is m_startupContent Then Exit Do
            If i >= cnt Then Exit Do
            tmp = Me.SnakeLocus.Pop()
            Me.closeContent(tmp)
            i += 1
        Loop
        tmp.NextDir = Direction.None
        tmp.Content.Invalidate()
        Me.HotContent = tmp
    End Sub


    Private Sub closeContent(ByVal cw As ContentWrapper)
        '↓派生クラスに処理のチャンスを与える。
        Me.OnClosingContent(cw)

        Me.SuspendLayout()
        Dim c As Control = cw.Content
        c.Visible = False
        Me.Controls.Remove(c)
        c.Dispose()
        cw.Content = Nothing ' ←Paintイベントハンドラを削除するため
        Me.AllContents(cw.XY.X, cw.XY.Y) = Nothing
        Me.ResumeLayout(False)
    End Sub

    Private Function createContent(ByVal x As Integer, ByVal y As Integer, _
        ByVal cx As Integer, ByVal cy As Integer, ByVal dr As Direction) As ContentWrapper
        '引数x,yは、展開元または展開先Contentのクライアント座標(複雑なので説明は省略)
        '引数cx,cyは、展開先Contentを格子に見立てた場合の座標
        '引数drは、Contentの展開方向(例えば、下に展開した場合にはDirection.Down)

        '↓新しいContentを生成(中身は派生クラスで実装)
        Dim c As Control = OnCreateNewContent(cx, cy, dr)
        If c Is Nothing Then Return Nothing

        If Me.HotContent IsNot Nothing Then
            Me.HotContent.NextDir = dr
            Me.HotContent.Content.Invalidate()
        End If

        Me.SuspendLayout()
        Dim cw As New ContentWrapper
        cw.Content = c
        cw.Parent = Me
        cw.XY = New Point(cx, cy)
        cw.PrevDir = Me.GetOppositeDirection(dr)
        cw.m_showborderline = Me.ShowContentsBorderLine
        cw.m_borderlinewidth = Me.ContentsBorderLineWidth
        cw.m_borderlinecolor = Me.ContentsBorderLineColor
        Me.AllContents(cx, cy) = cw
        Me.SnakeLocus.Push(cw)

        '新Contentのクライアント座標を決定
        Select Case dr
            Case Direction.Down
                'この場合は引数x,yは既に新Contentの座標が渡されるようになっている
                c.Location = New Point(x, y)
            Case Direction.Up
                c.Location = New Point(x, y - c.Height)
            Case Direction.Left
                c.Location = New Point(x - c.Width, y)
            Case Direction.Right
                'この場合は引数x,yは既に新Contentの座標が渡されるようになっている
                c.Location = New Point(x, y)
            Case Direction.None
                ' 起動時に最初に表示されるContentのみここに来る
                c.Location = New Point(x, y)
                ' ↓画面の見栄えを良くするための苦し紛れの処理
                cw.PrevDir = Direction.Up
        End Select

        c.Visible = True
        Me.Controls.Add(c)
        Me.HotContent = cw
        Me.ResumeLayout(False)
        Return cw
    End Function

    'マウスカーソルの位置を読み取って新しいContentを作る
    Private Sub DoTrack()
        Dim pt As Point = Me.PointToClient(Cursor.Position)
        Dim hci As ContentWrapper = Me.HotContent
        Dim hc As Control = hci.Content

        If hc.Bounds.Contains(pt) Then Return

        Dim x As Integer = hc.Location.X
        Dim y As Integer = hc.Location.Y
        Dim cx As Integer = hci.XY.X
        Dim cy As Integer = hci.XY.Y
        Dim dr As Direction = Direction.None

        If False Then
        ElseIf pt.Y < hc.Top Then
            If y < hc.Height Then Return ' Formからはみ出る場合は無視
            cy -= 1 : dr = Direction.Up ' yは新Content生成後に計算
        ElseIf hc.Bottom < pt.Y Then
            If y + (hc.Height * 2) > Me.ClientSize.Height Then Return ' Formからはみ出る場合は無視
            y += hc.Height : cy += 1 : dr = Direction.Down
        ElseIf pt.X < hc.Left Then
            If x < hc.Width Then Return ' Formからはみ出る場合は無視
            cx -= 1 : dr = Direction.Left ' xは新Content生成後に計算
        ElseIf hc.Right < pt.X Then
            If x + (hc.Width * 2) > Me.ClientSize.Width Then Return ' Formからはみ出る場合は無視
            x += hc.Width : cx += 1 : dr = Direction.Right
        End If

        'ランチャーの外なら無視
        If cx < 0 OrElse cy < 0 Then Return

        If Me.AllContents.Item(cx, cy) Is Nothing Then
            '新しいContentを作成
            Me.createContent(x, y, cx, cy, dr)
        Else
            '以下、Contentを消去するかどうかの判定

            '起動時に最初に表示されたContentは消去しない
            If Me.HotContent Is Me.m_startupContent Then Return
            'Stackの上から2つ目の要素を読み取る
            '(ここに来る場合はStackに2つ以上の要素が入っている)
            Dim tmp As ContentWrapper = SnakeLocus.Pop()
            Dim peekcw As ContentWrapper = SnakeLocus.Peek()
            SnakeLocus.Push(tmp)

            If peekcw Is AllContents.Item(cx, cy) Then
                If Me.CanAutoShrink = True Then
                    'Snakeを1つ短縮
                    Me.TruncateSnake(1)
                End If
            Else
                '自身の軌跡とは交差できない仕様
                Return
            End If
        End If
    End Sub

End Class

'               (コードの終わり)

引用返信 編集キー/
■12390 / inTopicNo.15)  Re[10]: ペン操作によるメニュー展開
□投稿者/ 引っ込んだID非公開 (7回)-(2008/01/08(Tue) 23:40:40)
14回目の投稿です

 ここから先はおまけです。

  以下のコードは、ContentSnakeBaseの派生クラスのかなり簡単な例です。
  丸いContentの中に矢印文字を描画します。
  仮に(仮にですよ)、「自作コンテンツでSnake」にチャレンジされる場合は、参考にしてみてください。
  繰り返しになりますが、VC#2005以降で派生クラスを作成可能です。

'<おまけ>
'ArrowSnake用のエントリポイント
Public Class ProgramArrow
    '↓コメント解除して使ってください。
    'Public Shared Sub Main()
    '    Application.EnableVisualStyles()
    '    Dim frm As New Launcher(Of ArrowSnake)
    '    Application.Run(frm)
    'End Sub
End Class
'かなり簡単な派生クラスの一例(丸いContentの中に矢印文字を描画)
Public Class ArrowSnake
    Inherits ContentSnakeBase

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        Me.ShowContentsBorderLine = False
        Me.CanAutoShrink = True
        MyBase.OnLoad(e)
    End Sub
    Protected Overrides Sub OnClosingContent(ByVal cw As ContentSnakeBase.ContentWrapper)
        '何もしない
    End Sub
    Protected Overrides Function OnCreateNewContent(ByVal cx As Integer, ByVal cy As Integer, _
        ByVal dr As Direction) As System.Windows.Forms.Control
        Dim c As New Control
        c.Size = New Size(60, 60)
        Return c
    End Function
    Protected Overrides Sub OnHotContentChanged(ByVal cw As ContentSnakeBase.ContentWrapper)
        '何もしない
    End Sub
    Protected Overrides Sub OnHotContentChanging(ByVal cw As ContentSnakeBase.ContentWrapper)
        '何もしない
    End Sub
    Protected Overrides Sub OnPaintContent(ByVal cw As ContentSnakeBase.ContentWrapper, _
        ByVal e As System.Windows.Forms.PaintEventArgs)
        Dim ss As String = ""
        Select Case cw.NextDir
            Case Direction.Down : ss = "↓"
            Case Direction.Up : ss = "↑"
            Case Direction.Left : ss = "←"
            Case Direction.Right : ss = "→"
            Case Direction.None : ss = "×"
        End Select

        Dim c As Control = cw.Content
        Dim sf As New StringFormat
        sf.Alignment = StringAlignment.Center
        sf.LineAlignment = StringAlignment.Center
        e.Graphics.FillEllipse(Brushes.AntiqueWhite, c.ClientRectangle)
        Dim fnt As New Font(SystemFonts.MessageBoxFont.Name, 20)
        e.Graphics.DrawString(ss, fnt, Brushes.Black, c.ClientRectangle, sf)
        fnt.Dispose()
    End Sub
End Class

以上です。

引用返信 編集キー/
■12539 / inTopicNo.16)  Re[5]: ペン操作によるメニュー展開
□投稿者/ arion (2回)-(2008/01/11(Fri) 12:44:52)
No12384 (引っ込んだID非公開 さん) に返信
> 2008/01/08(Tue) 23:43:27 編集(投稿者)

ありがとうございます!!

参考にさせてもらいながら自分なりに考えてみたいと思います!

また書き込みますのでよろしくお願いします!!
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -