Feeds:
投稿
コメント

Posts Tagged ‘VSTO’

ColorIndexをEnumにする

未だにWin8にアップグレードできていません

さて、今回はExcelその他のColorIndexを列挙子にしてみます。(作ってからググったらあったけど気にしない)

ColorIndexはColorと違い定義済みの色をそれに対応する整数値から取得、設定することができます
ですがこの整数値はIntegerで入れる形となっていて非常に扱いづらいです(というのもどれがどの色に対応しているかが数字から見えないため)

というわけで数字と対応する列挙子を作成します。列挙子はIntegerで宣言しておけばIntとしても使えるためです

ColorIndexをカラーコードに変換した表についてはググったりすれば簡単に出てくるので楽だと思います。
ちなみに私はhttp://d.hatena.ne.jp/ogohnohito/20110512/p2を参考にさせていただきました
またカラーコードと色名についてはhttp://e-words.jp/p/r-colornames.htmlのほうを参照しました

とりあえず次のような感じ

Public Enum ColorIndexEx
        ''' <summary>
        ''' #000000,ColorIndex = 1に対応する
        ''' </summary>
        Black = 1
        ''' <summary>
        ''' #FFFFFF,ColorIndex = 2に対応する
        ''' </summary>
        White = 2
        ''' <summary>
        ''' #FF0000,ColorIndex = 3に対応する
        ''' </summary>
        Red = 3
        ''' <summary>
        ''' #00FF00,ColorIndex = 4に対応する
        ''' </summary>
        Lime = 4
        ''' <summary>
        ''' #0000FF,ColorIndex = 5,32に対応する
        ''' </summary>
        Blue = 5

End Enum

1から56まであります
少し重複があるのでそこをはじく必要があるので注意

ついでにxlColorIndexについても定義していまうと置き換えられるかと

さて、一つだけ問題があります
17以降がHTMLのカラーコードとしてないという事態です
#9999FFは何色なんでしょうか…

苦肉の策で_9999FF = 17とか宣言してますがなかなかひどい

一応ソースはhttps://bitbucket.org/fantasticswallow/intellioffice/src/ab714c2581f617d3f443c903fca39b3998ab1d64/IntelliOffice/ColorIndexEx.vb?at=defaultに転がっていますので適当に使いたければ(一応Ms-PLにしたいんですけどどうしたらいいんですかね)

とりあえずこの辺で

Read Full Post »

作ろうと思ってたライブラリの内容がもろ入ってて笑うどころではないなど

というわけでVSTO Power Toolsのお話です。4年は前のツールですね
これのインストールのためだけにVisual Studio 2008入れることになるとは…

Microsoft Visual Studio Tools for the Office System Power Tools v1.0.0.0はVSTO向けの便利なアプリケーションや拡張アセンブリを提供してくれるものです
OpenXMLのビューアやビルトインされたリボンのコントロールIDを選択したり?するアプリケーションなどを含んでいます。アプリケーションの方は興味があったら調べるといいかもしれません

今回話題にするのはOffice Interop API Extensionsという拡張アセンブリの方です。これの説明には”A set of C# classes for handling parameterized properties and optional/named parameters, as well as for LINQ-enabling Office collection objects.” とあります。つまりOptionalなプロパティのObjectにされてた部分をしっかり型の関連付けを行い、LINQを使えるようにもしたよって感じです

まず一つ目になんで型の関連付けがすごくいいかというお話ですがVSTOではこんな感じのメソッドが多めに用意されています

Microsoft.Office.Interop.Excel.PivotTable PivotTableWizard(
    [object SourceType = System.Type.Missing], 
    [object SourceData = System.Type.Missing], 
    [object TableDestination = System.Type.Missing], 
    [object TableName = System.Type.Missing], 
    [object RowGrand = System.Type.Missing], 
    [object ColumnGrand = System.Type.Missing], 
    [object SaveData = System.Type.Missing], 
    [object HasAutoFormat = System.Type.Missing], 
    [object AutoPage = System.Type.Missing], 
    [object Reserved = System.Type.Missing], 
    [object BackgroundQuery = System.Type.Missing], 
    [object OptimizeCache = System.Type.Missing], 
    [object PageFieldOrder = System.Type.Missing], 
    [object PageFieldWrapCount = System.Type.Missing], 
    [object ReadData = System.Type.Missing], 
    [object Connection = System.Type.Missing])

こんなメソッドどうでしょうか

何がすごいってまずVSTOなのにインテリセンスが使えないところにあります。それなりにはでますけど…
というか何入れていいのかこれだけじゃさっぱりわかりません。下手なの入れると動かないですし

これを拡張メソッドで簡単に書き換えるとこんな感じになります(VBですが)

'' <summary>
        ''' Worksheet.PivotTableWizardを実行します
        ''' </summary>
        ''' <param name="target"></param>
        ''' <param name="SourceType">レポートの集計元データの内容を示す定数。この引数を指定する場合は引数SourceDataも指定。
        ''' SourceTypeとSourceDataを省略した場合、集計元データの種類はxlDatabaseとされ、集計元データは名前付きセル範囲Databaseから取得されます。
        ''' 名前付きセル範囲Databaseが存在しないときに、現在の選択範囲がデータを含む10以上のセルの場合は、その選択範囲が使われます。そうでない場合はエラーが発生します。</param>
        ''' <param name="SourceData">レポートの作成に使うデータ。Rangeオブジェクト、セル範囲の配列、他のレポートの名前を表す文字列定数のいずれかを指定可能。外部データベースの場合、引数SourceDataは、各要素が255文字の長さまでのSQLのクエリ文字配列を格納。
        ''' 引数Connectionを使って、ODBC接続文字列を指定。以前のExcelのバージョンとの互換性について、SourceDataでは2つの要素配列を指定できます。
        ''' 1番目の要素はデータのODBCソースを指定した接続文字列です。2番目の要素はデータの取得に使用するSQLのクエリ文字列です。引数SourceDataを指定した場合、引数SourceTypeも指定する必要があります。
        ''' 引数SourceDataの範囲内にアクティブセルがある場合は、引数TableDestinationも指定する必要があります。</param>
        ''' <param name="TableDestination">レポートの配置場所を表すRangeオブジェクト</param>
        ''' <param name="TableName">新しいレポートの名前</param>
        ''' <param name="RowGrand">レポートに行の総計を表示するかどうか</param>
        ''' <param name="ColumnGrand">レポートに列の総計を表示するかどうか</param>
        ''' <param name="SaveData">レポートと共にデータを保存するかどうか。Falseの場合はレポートの定義のみ</param>
        ''' <param name="HasAutoFormat">レポートの更新時やフィールドが移動されたときに、オートフォーマットを実行するかどうか</param>
        ''' <param name="AutoPage">SourceTypeにxlConsolidationを指定した場合にのみ有効。統合元範囲のページ フィールドを自動的に作成するかどうか。
        ''' False に指定した場合は、ページ フィールドは自分で作成する必要があります。ページ フィールドは複数作成することができます。</param>
        ''' <param name="BackgroundQuery">レポートのクエリをバックグラウンド(非同期)で実行するかどうか</param>
        ''' <param name="OptimizeCache">ピボットテーブルのキャッシュの構成時に最適化を行うかどうか</param>
        ''' <param name="PageFieldOrder">ピボットテーブルレポートのレイアウトに追加するページフィールドの順序</param>
        ''' <param name="PageFieldWrapCount">ピボットテーブルの各列または各行のページ フィールドの数を指定</param>
        ''' <param name="ReadData">外部のデータベースのすべてのレコードを含む、非常に大きなピボットテーブルキャッシュを作成するかどうか。Falseの場合、実際のデータを読み込む前に、いくつかのフィールドをサーバーを基にしたページフィールドに設定できます。</param>
        ''' <param name="Connection">ODBCデータ ソースと接続できるようにするODBC設定のいずれかを含む文字列。接続文字列は"ODBC;[接続文字列]"形式です。
        ''' この引数は、PivotCache オブジェクトの Connection プロパティの設定よりも優先されます。</param>
        ''' <returns></returns>
        ''' <remarks>Reservedは使用不可につき常にnullがわたります</remarks>
        <Extension()>
        Public Function PivotTableWizard(target As Worksheet,
                 Optional SourceType As XlPivotTableSourceType = Nothing,
                 Optional SourceData As Object = Nothing,
                 Optional TableDestination As Range = Nothing,
                 Optional TableName As String = Nothing,
                 Optional RowGrand As Boolean = Nothing,
                 Optional ColumnGrand As Boolean = Nothing,
                 Optional SaveData As Boolean = Nothing,
                 Optional HasAutoFormat As Boolean = Nothing,
                 Optional AutoPage As Boolean = Nothing,
                 Optional BackgroundQuery As Boolean = False,
                 Optional OptimizeCache As Boolean = False,
                 Optional PageFieldOrder As XlOrder = XlOrder.xlDownThenOver,
                 Optional PageFieldWrapCount As Integer = 0,
                 Optional ReadData As Boolean = Nothing,
                 Optional Connection As String = Nothing) As Microsoft.Office.Interop.Excel.PivotTable

これでもまだ残念な気はしますけどマシではありますね(実際使うかといわれると微妙ですが)(そもそも引数が多い)

こういうのを全部~~Argsという形でまとめてあるのが拡張アセンブリの方です。これによって基本的に引数1つだけできれいに実行できるようになりました。 やってることはMissingへの変換があるせいで微妙に汚いですけど…

次にLINQのサポートのほうなんですけどこれはいくつかのメソッドにIEnumerableを返すItemsという関数が定義されています。中身はオブジェクト本体をyield returnしています。(ILゲフンゲフン)
yield returnなんてVBにないから気づかなかったのか…!(違う) とか思いながらこれを実装すれば何かに使えるかも知れませんね
(まあCOMObjectの壁を越えれるのかは知りませんが…)(どっちかっていうとCastに近い感じが)

さてそんな感じでこんなアセンブリもあるよって話ですが実はこのツール、VS2008までしか対応していません。Officeも12までです。便利なのに今は使うことができないという悲しい現実

VS2008を今でも使ってる方はぜひどうぞ! って感じですがいまさらVS2010も2012でもないのを使うのはちょっと

自分でとりあえず作ってみるかなー的な感じのことは思ってたりですけどね

あとこれ調べてて感じた結論は
「VSTOはC#も使えるんじゃなくてC#のためのOffice開発」
って感じですね。VB.NETなんてなかったんや…

とりあえずこの辺で

Read Full Post »

MVP for VSTOになりたいとか思うこのごろ(ならもっとちゃんとやれ

VSTO(Visual Studio Tools for Office)ではCOMアドインやVSTOアドインを用いた特殊なファイルを作ることができます。ですが実際はVSTOはVBAほど万能ではありません。それをいかに克服するか ということについてちょっと考えてみます

・VSTOとVBAの比較
そもそもVBAの上位互換がVSTOじゃないのとかそう思う方もいるかもしれないですけど(私が思ってただけかもですが)VSTOとVBAは正確にはターゲットが違います
形もリファレンスアセンブリも同じなのに何が違うんだって話ですけどVBAはアドインが作れなくてVSTOはファイルにアクセスがかなり困難です
(推測かなり含んでるのでここ違うとかありましたらぜひ)
VBAはどちらかというとファイルのための拡張という部分があると思います。VBAのコードは基本的に外部から参照ということでは使わず内部でのみ使用されます。簡単に言えば使い捨てという面があるわけです
VSTOはまったく逆でアプリケーションのための拡張という面があります。実際アドインしか作れません(拡張ファイルもファイルロード時にvstoアドインをロードします)
つまりxlsx系のプロパティのGetを行ったりしてファイルを操作するのがVBAでExcelなどのアプリケーション系の拡張を作成してメソッドの実行やプロパティのSetを行えるのがVSTOといえます

・VSTOとVBAの長所短所
もうちょっと深く考えてみます
VSTOがVBAと比較して優れている点としては
・.NETのアセンブリを利用してアプリケーションを作成できる(LINQ,Rx,etc…)
・言語としてVB.NET/C#を利用できる
・Visual Studioの環境を用いて作成することができる
逆に劣ってる点としては
・ファイルからデータを取得しづらい(COMオブジェクトとして扱われます)
・利用する環境に複数のアセンブリを必要とする(最低でも.NET Frameworkが必須)

ではVBAがVSTOより優れている点としては
・現在のExcelファイル内のデータにアクセスできる
・Excelさえ入っていれば実行可能である(セキュリティ面がうんぬんですが)
・Excelのバージョンはほとんど問わない上拡張子、フォーマットもほぼ問わない
逆としては
・言語にVisual Basicしか利用できない
・アドインを作成して全てのファイルに機能を提供するのが難しい?

などなどがあるわけです(主観)
VBAより新しいからなんとかってわけではないということですね

・VSTOからxlsxファイルへのアクセス手段
そろそろ本題
上記の通りVSTOはGetプロパティがほぼ使えない状態です。じゃあどうしたらいいかという話ですがVSTOのメリットに.NETアセンブリの利用可能があるはずです。これを使わない理由がありませんね

ではいくつか手段を考えてみましょう

・OLE DBによる接続
割とオッフィースらしい接続方法かもしれません。OLE DB(Object Linking and Embedding DataBase)によるxlsxファイルへの接続を行いファイルの情報をDataTableとして扱う手段です。OleDbAdapterを用いて接続するのですがこの時Accessのアセンブリが必要になってくるので注意
まともなクエリ構文が書けないとファイルサイズが大きくなったときにまったく使えなくなるので小さいファイルを扱うだけなら有効かもしれません。なんともいえないですけど

・LINQ to XMLを用いて直接読み込む
何かで見た気がする…? Office2007以降のファイル(~~~x,~~~m)はXMLファイルの集合体をZipファイルにして拡張子を変更しているため(xapと同じ)これを一度解凍してXElementなどを使って読み込む手段もあります
ただしこれをやるにはなぜか分かれているファイル構成に対応できなくてはいけません

・OOXMLを用いて読み込む
私的にはこれがよさげ。OOXML(Office Open XML) SDKを用いて読み込む手段です
先ほど書いた通りファイルはxmlで構成されています。このフォーマットはOpenXMLformatsを使用しているためこれにそった形で読み込めるのがこのOOXML SDKです。もともとはOfficeクライアントを作成するためのものですがファイルサイズが大きくてもちゃんと読み込めるためこれでよいんじゃないかと思います

まあそんなこんなでとりあえずOOXMLについて少しずつ調べて行こうかななどなどと

とりあえずこの辺で

Read Full Post »

調べただけ系記事

VSTOでアドインを作ってそのアドインをファイルごとに設定できるようにするにはどうしたらいいかを考えてみます。たとえばExcelアドインで基本自動で背景を表示するけど特定のファイルだけ表示しないようにしたい とかしたいとします。
(企業とかでプレゼンとかほら)

この時設定をAppDataに書き込むのはあまりよくありません。自分で使うだけなら問題はないかと思いきや一つの環境だけなら となります。2つ以上環境がある場合はAppDataに書き込んで共有でもしない限り話になりません。プレゼンしようと開いたらかわいい女の子が表示されるなんてことはあってはならないわけですね
またopenxmlformatを調べて埋め込むっていうのもありっちゃありかもしれませんけどめんどくさすぎる気がします
(propsあるしできなくはないきがしました)

WPFとかのControlだとTagというプロパティがあるしそういうのないかなーと思ったらCustomDocumentPropertiesがほぼすべてで使えるように思われます。Word、Excel、PowerPointでは使えるみたいです。ほかは調べるのがめんどくさかったんです

CustomDocumentPropertiesはその名の通りユーザー定義のドキュメントプロパティを使用するために使われます

そもそもドキュメントプロパティって何かというとコードでいうならAssemblyInfoに書くような内容のあれです
アセンブリにポインタを合わせるとツールチップで作者名とかでるじゃないですか、あれですあれ

で、BuiltinDocumentPropertiesというものもあるのですがそれはさっきの作者名とか入れる方です。基本的な事項はこっちに入れます
ですけど背景画像を自動表示しないなんてプロパティはないのでユーザー定義という形で埋め込んで使用します

とりあえず追加するなら次のような感じ

Dim dp = DirectCast(CacheInfo.GetInstance.cacheApplication.ActiveWorkbook.CustomDocumentProperties, Microsoft.Office.Core.DocumentProperties)
dp.Add("IsNotShowAutoBackground", False, Microsoft.Office.Core.MsoDocProperties.msoPropertyTypeBoolean,True, )

DocumentPropertiesはOffice.Coreにあるので注意が必要です

DocumentProperties.Add(name,linkToConvert,type,value,linkSource)では主にnameが名前、linkToConvertはセルとリンクするかどうか(bool)、typeは値の型(variantですが実際はMicrosoft.Office.Core.MsoDocProperties)、valueはtypeに該当する型の書き込む値、linkSourceはlinkToConvert時にリンクするオブジェクトを指定します

ちなみにDocumentPropertiesのデータはなぜか__comObject地獄がない気がします。たぶんです。たぶん。今度調べます(

この辺で

Read Full Post »

Kinectデータ解析のためなんです(苦しい)

APIなんかを通じてダウンロードできるデータの形式はxmlなんかも多いですがやはりjsonが多いです。jsonのみはあってもxmlのみは割と見ない感じがします?

ところでExcelにはXMLをインポートする機能があります。外部データの取り込みとして使えるあいつです。
これが予想以上に便利でXML内のメンバーを全部拾ってテーブルとしてまとめてくれます。配列をいれると壮観です
これを使えばJsonViewとかそういうの使わなくてもよくなる!?とか思ったりおもわなかったり

XML…? そうだJSON!ってことでこの使いやすいXMLインポート機能をラップしてJSONをインポートさせましょう。もちろんうまくいってない部分が大きいですが気にしない

ExcelのWorkbookにはXmlImportとXmlImportXmlというメソッドがあります。XmlImportXmlとか何かすさまじいものを感じる名前ですが
Workbook.XmlImport(String, XmlMap, Object(Boolean), Object(String|Range))(Object後の括弧内は実際の型を表します)はUrlを使用したインポートを行います。つまりAPIなんかのエンドポイントに接続といったことが可能になったりしますね。このメソッドは主に外部のXMLをインポートするために用いられます

Workbook.XmlImportXml(String, XmlMap, Object(Boolean). Object(String|Range))は引数の型全く同じですが今度はXMLの文字列を渡します。(XmlImportのほうはいまだとUri使うかな) つまるところこっちは内部のXMLをインポートできます

外部と内部の違いは何かというとまあ単純に言えばStringとしてXMLのデータがあるほうが内部です。もってないほうが外部です
今回はJSONをXMLに変換しないといけないので当然XmlImportXmlのほうを使います

・JSON→XMLの変換
さて、使うメソッドは確認できましたので次はJSONのデータの文字列をXMLに変換しなくてはなりません。さすがに内部ではXMLにしてくれません
今回使うのはもちろんJsonReaderWriterFactoryです。いやまあがっつりXmlReaderに変換しますし

JsonReaderWriterFactory.CreateJsonReader[System.Runtime.Serialization.Json namespace]はJSONのByte()からXmlDictionaryReaderを生成します。JSONデータのByte()はSystem.Text.Encoding.Unicode.GetBytesとかでJSONデータのStringを変換すればいいかなと。XmlDictionaryReaderQuotasのほうは今回はそんな怪しいデータは使わないのでMaxにします。必要に応じて変えてください
MemoryStreamにJSONのデータ書き込んだりしてもいいんですけどusingで囲ったりするの面倒なのでStringで扱ったほうがいいかなーという感じです

この時の返り値のXmlDictionaryReaderをXDocumentのコンストラクタの引数にそのまま突っ込みます。どうせXmlReader継承してるしいいよねっていう感じで
XDocumentにする理由はXElementだと配列が配列になってしまうのでXML一個として扱うならXDocumentです
ちなみにXmlDictionaryReaderまともに扱ったら大変な事態になりました

ここまでをソースコードにまとめると次のような感じです。今回はファイルから読み込みます(Webから読み込みたかったんですけどBadRequest5回ほど返されて断念)

If Not String.IsNullOrEmpty(FileSourceTextBox.Text) AndAlso IO.File.Exists(FileSourceTextBox.Text) Then
    Dim content As String = ""
    Using xreader As New StreamReader(FileSourceTextBox.Text)
        content = xreader.ReadToEnd
    End Using
    Dim xdoc = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(System.Text.Encoding.Unicode.GetBytes(content), Xml.XmlDictionaryReaderQuotas.Max))
End If

一行に収まってて力技みたいになってますが普通です。きっと普通です

・XmlImportXmlを使う
準備できたので本題へ

XmlImportXmlに必要なのはWorkbookのインスタンスとDestinationです。なぜかDestinationにNothing渡すと参照がないとか言われます。意味が分かりません

第一引数にはさっき作ったXDocumentをToStringしたものを入れれば十分です。スキーマが足りないとかいわれますがExcelが勝手にやってくれるので問題ありません
第二引数のImportMapはByRefがついてるのでNothingで構いません。XmlMapの変数宣言して入れてもいいと思います。とりあえずNothing安定な感じ
OverwriteはBooleanです。上書きしていいかを指定するものです。たぶんこれはTrueでいいかなと
Destinationはセルの位置を指定します。StringかRangeのインスタンスが必要です。これはOptionalなのにNothing入れたら進めません

WorkbookはMicrosoft.Office.Interop.Excel.Application.ActiveWorkbookを使いましょう。ActiveWorksheetなんかと違ってちゃんと型指定されてます。すばらしい

さてこの辺をまとめたメソッドを作るとこんな感じになります。先のコードとかぶってる部分がありますがそこはうまく分けてください

Private Sub jsonTextImport(ByVal text As String, workbook As Microsoft.Office.Interop.Excel.Workbook, destination As String)
    Dim _map As Microsoft.Office.Interop.Excel.XmlMap = Nothing
    Dim xdoc = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(System.Text.Encoding.Unicode.GetBytes(text), Xml.XmlDictionaryReaderQuotas.Max))
    workbook.XmlImportXml(xdoc.ToString, _map, True, destination)
End Sub

まあこんな感じでできます。DataContractJsonSerializerで作ったJSONも普通に解析できるのでぜひとも活用していきたいですね

とりあえずここらへんで

Read Full Post »

編ですが一回きりです

VSTO、今までワークシートでしか遊んでこなかったのでここらでがっつりアドインでも作ろうかと思ったので作ってました
というかExcelでGroupByできない気がしたので作りました

まあ作ったものの内容は置いといて

いつもの通りVSTOという厄介なやつと戦うことになった私ですが今回は今までと同様にひどい戦いでした

とりあえず普通にTips的なのを書いていきましょう

まずリボン拡張ですでにあるリボンのタブの中にボタンを入れる方法ですがリボン(ビジュアルデザイナー)を追加したときに最初に追加されるタブのControlIdを目的のタブのControlIdにします。
今回はデータが目的だったのでTabDataを指定しました。他のタブはあの仕様書.xlsxをご覧ください

次にボタンですがグループで固めないとだめ?なのかわかりませんけどボタン単体は入らなかったのでグループでAfterOfficeIdを指定し目的のグループのOfficeIdを指定しました

まあその辺りわからないので適当に

次にLINQをまともに扱うのは嫌だったのでCodeProviderを使用。
リフレクションとかその辺は割と調べ足りなかったのでそこまで苦戦はしないのですが…

そうです、VSTOランタイムとアドインのアセンブリ参照が一番厄介です
VSTOのランタイムはそもそも入ってない可能性が高いうえにどこに入ってるのか怪しいのとさらには絶対参照なのでどうにもならない気がします

またアセンブリの方を参照はまだなんとかなるかなーと。
http://support.microsoft.com/kb/291392にある通りCOMアドインはレジストリに位置が保存されます。
これを拾ってきて文字列からゴミを消せばディレクトリ参照は可能です
VBだと次のような感じ

Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\Microsoft\Office\Excel\Addins\プロジェクト名").GetValue("Manifest").ToString().Replace("file:///", "").Replace("/プロジェクト名.vsto|vstolocal", "")

名前は適当に置き換えてください

まさかこれに一日かかるとは…
もっと早く書けるようになりたいですね

こうして私のExcelはVB.NETとC#による謎実行が可能に…! って思ったら型推論壊れててIEnumerableに丸めるときにObjectになっててまだ先は長そう

とりあえずこの辺で

Read Full Post »

新年度です
変わりはありません

ということでAyatter ver0.9.0.579を今日の11時ころに出しました
0.9.0.577を0時半頃に出したけどまあはい
超致命バグ抱えたゲーム付きでかなりあれ
(眠かったんですって言おう
(テストプレイしてません

さて、まあ今回はtoshi_aメソッドという明らかにあれな機能つけました
気にしなくていいですね

どっちかというとまあくっつけたほうの謎ゲームのほうのお話のほうがだらだらかけなくもない

正直言えば課題用のゲームなんで割と完成度低かろうが問題はな(

とりあえずExcel+VSTOな感じでゲームもどき作ってます
どうやってかってまあVSTOなんでかなり普通にゲーム作ってUIだけExcelにすればいい感じです

VBAでやるとさすがに変態的なのでちょっと…w
汎用性上がるけど何年前のなんたら…

とはいってもVBAのヘルプドキュメント全部日本語化されてますしMSDNと同等クラスに見れるんでかなり便利です
というかVSTOにおいてはMSDNよりExcelのドキュメントのほうがはるかにレベル高いです
Excel起動→Alt+F11→F2→F1という謎のコンボを決めるだけですね

はてさて、Excelでゲーム作るとしたらまず問題点としてオブジェクトをどこに置くか的なのがありますが
まあいくらなんでもキャラクターオブジェクトを直接描画するゲームは見たことないので普通にロジックを分離します
簡単に言えばキャラクターオブジェクトを置いておくサーバー層的なのと描画を行うクライアント層に分けるみたいな感じに

さて次にセルの扱いでも
セルはパネルとかそういうのにそのまま転用して使ったり描画の最小単位にしてもいいですが
なんにせよ数字でできれば扱いたいです
(XY座標をいちいち”B3″とか”AA1″とか扱うのはめんどくさいので)
というわけで数字2つからRangeで扱える文字列を出しましょう
(VBAのときはCells(Integer X, Integer Y)があったんですけどまあはい)

とりあえずめんどくさいのでこんなものを用意しました

Private Shared ReadOnly xCharArray As Char() = {"A", "B", "C", "D", ・・・, "Y", "Z"}

AからZまで26文字Charとしてとりあえず突っ込みます
もっとスマートな方法があるはずなんで気にしないでください

次にこれを使って数字から頑張って文字に変換しましょう
ん? ググれば出る? まあそうですけど

    Private Shared ReadOnly Property GetIndexChar(ByVal tgInts As Integer) As String
        Get
            If tgInts >= 702 Then
                Dim xInts As Integer = Math.Truncate(tgInts / 702)
                If (tgInts - (xInts * 702)) >= 26 Then
                    Dim xtInts As Integer = Math.Truncate((tgInts - (xInts * 702)) / 26)
                    Return xCharArray(xInts - 1) + xCharArray(xtInts - 1) + xCharArray(tgInts - ((xInts * 702) + (xtInts * 26)))
                Else
                    Return xCharArray(xInts - 1) + "A" + xCharArray(tgInts - (xInts * 702))
                End If
            ElseIf tgInts >= 26 Then
                Dim xInt As Integer = Math.Truncate(tgInts / 26)
                Return xCharArray(xInt - 1) + xCharArray(tgInts - (xInt * 26))
            ElseIf tgInts >= 0 Then
                Return xCharArray(tgInts)
            End If
            Return Nothing
        End Get
    End Property

ところどころ-1してるのはA=1だからです
AAAA以降がほしかったら適当に計算して出すといいかもです
これにX座標を入れて文字列拾ってきてY座標の数字と組み合わせましょう

ちなみにコンテキストメニューを独自のにしたかったりつぶしたければSheet1のBeforeRightClickイベントでCancel =True入れればいいです
そのあとやら前やらに独自メニュー出すとかでも

長ったらしくなってきたのでこの辺で

Read Full Post »

Older Posts »