2015年7月13日月曜日

dotNET+MAXscript 手始めに。

温まって来たところで、dotNET+MAXscriptで実際にいろいろ作っていきたいと思います。
まずは、dotNETを使ったUIの基本。フォームの生成です。

こんな感じですね。

(
    --メインフォーム設定--------------------------------------------------------------
    MainFrm = dotNetObject "System.Windows.Forms.Form"
    --フォームのタイトル-----------------------
    MainFrm.text = "testform"
    --フォームサイズ--
    MainFrm.bounds = dotNetObject "system.drawing.rectangle" 50 50 200 200
    --フォームを表示--
    MainFrm.Show()
)

この4行でフォームが生成されます。
まず1行目。
mainFrmが生成されるフォームになるので、ここはなんの名前でもOKです。
「=」以降、ここで作るものがdotnetobjectである、というのを決めます。
たいてい、dotnetobject "なんちゃら~"でブツを作ってくれます。

2行目以降
ブツを作っただけで、中身(プロパティと言います)が空、もしくはデフォルト値なので、プロパティを決めていきます。
.text これはフォームのタイトルバー部分に表示される名前です。
.bounds これはmainFrmが表示されるx.y座標と、ウィンドウサイズの指定です。
ここで注意しないといけないのが、.boundsは直接値を入れてもいうことを聞いてくれないということです。
ブツを作った上で、その中に値を入れてあげないといけません。
dotNetObject "system.drawing.rectangle"でブツを作ってあげます。

""内は、どんなタイプのブツを作るか、という宣言なのですが、これはプロパティごとに決まってますので、随時調べて行きましょう。
プロパティによっては、.textのように値を直接入れてもOKなものも有りますが、どれがOKでどれがダメなものかまでは理解出来てませんので、
値を直接入れてダメなら、ブツが必要なんだなーくらいの認識でやっております。

値は、左から表示されるx座標、表示されるy座標、ウィンドウサイズ横、ウィンドウサイズ縦、となっています。

最後に、.show()で生成されます。


さて、次はこのフォームに画像を表示してみましょう。

画像の表示にはフォームのバックグラウンドに表示させる方法と、PictureBoxというdotNETオブジェクトを利用して表示させる方法とが有りますが、
ここは後から手を加えやすいようにPictureBoxを利用します。

(
    --画像読み込み&変数定義--
    mainimgfiles = "C:\\Users\\Public\\Pictures\\Sample Pictures\\sample.jpg" --表示したい画像を変数に格納--
    mainimgClass = dotNetClass "System.Drawing.Image" --クラスの定義--
    mainimg =(mainimgClass.FromFile mainimgfiles) --mainimgはmainimgクラスのファイル読み込みタイプでファイルのパスはmainimgfiles--
    mainimgWidth = mainimg.Size.Width as integer --mainimgのサイズ(幅)を参照して、intに変換--
    mainimgHeight = mainimg.Size.Height as integer --mainimgのサイズ(高さ)を参照してint型に変換--

    --dotNetオブジェクトを生成--
    imgview = dotNetObject "System.Windows.Forms.PictureBox" --imgviewはdotnetobjectでpictureboxを使います--
    imgview.bounds = dotNetObject "system.drawing.rectangle" 0 0 mainimgWidth mainimgHeight --画像の表示位置はフォームの(0,0)の位置--
    imgview.Image = mainimg --imgviewのイメージプロパティはmainimgです--
    imgview.backColor = (dotNetClass "system.drawing.color").Transparent --imgviewの背景色はカラーのクラスで、透過です。--

    --メインフォーム設定--------------------------------------------------------------
    MainFrm = dotNetObject "System.Windows.Forms.Form"
    --フォームのタイトル-----------------------
    MainFrm.text = "testform"
    --フォームサイズ--
    MainFrm.bounds = dotNetObject "system.drawing.rectangle" 50 50 200 200

    --pitureboxをフォームに追加--
    MainFrm.Controls.Add imgview --mainformにimgviewを追加します。--

    --フォームを表示--
    MainFrm.Show()
)

初めて出てきました「dotnetClass」
これはdotNetobjectと同じく、dotNet関連の物ですよ~という宣言なのですが、
正直なところなところ正確な違いは理解出来てません。
ブツは生成せずに、型を決めてくれる・・・程度の認識です。
興味のある方はMAXのヘルプ読んでみてください。

なんとなーくやってることはわかるんじゃないでしょうか。
ドット以降はすべてdotNETobjectもしくはdotNetclassのプロパティです。

幾つか注意点として上げるならば、
7行目のimgview.boundsですが、mainFrm内に表示するので、表示位置はフォームの(0,0)となります。
ここの値を変えることで、mainFrmの右下や左下なんかに表示させることが出来ます。
また、ingview.backcolorですが、これは背景色を変えることが出来ます。
今は透過していますが、違う色に変えたい場合は”picturebox .backcolor”あたりで検索するとヒットするので
調べてみてください。

わかる範囲で質問には答えようと思ってますので、twitterでもこちらのコメントでもどうぞ。

2015年6月13日土曜日

fileinのナゾ

MAXscriptには、「filein」という別のmsファイルをスクリプト内に読んでくる物があります。
例えば、

main.ms

    aaa = undefined
    filein "C:\\Program Files\\Autodesk\\3ds Max 2015\\scripts\\testA.ms"
    print aaa


testA.ms
(
aaa = "fileinのナゾ。"
)

こういった2つのscriptがあるとします。
testA.msをmain.msで記述されているパスに置いて、main.msをMAXscriptエディタ実行すると、testAは実行せずとも、main.msはtestA.msの内容を読んで、変数aaaは”fileinのナゾ。”というstring値に置き換えられます。

しかし、main.msを
macroScript testmain category:"test" internalCategory:"test" toolTip:"testmain" buttonText:"testmain"

    aaa = undefined
    filein "C:\\Program Files\\Autodesk\\3ds Max 2015\\scripts\\testA.ms"
    print aaa

と書き換えてツールバーに登録して実行すると、変数aaaはundefinedのまま、置き換わってくれません。
なんでや。


・・・しばらくナゾだったんですが、
こちらの記事で多分こういうことだろうと納得しました。
http://0303.blogspot.jp/2012/12/blog-post_5.html

はじめに、macroscript宣言をして、エディタからCtrl+Eで実行すると、usermacrosフォルダに登録されます。
なので、上記記事の5のところで、main.msは評価されているということになります。
しかしながら、fileinについては、ここでコンパイルされなんじゃないかと予想。

次に、上記6のスタートアップスクリプトにmain.msを入れてMAXを再起動。
結果としてはこちらもダメでした。

どうやらMAXのGUI構築前に、fileinは実行しとかないとダメなようですね・・・。

というわけで、stdscriptsにmain.msを入れて、testA.msを読むことが出来ました。

実際にツールを作るときには、ツール本体、filein宣言のみのmsファイル(stdscriptsにいれる)読み込む対象のmsファイル(場所はどこでもいい)
と、3つのmsファイルに分けて運用することになるかと思います。

これで、ツール本体をコンパイルしなおさなくても、対象ファイルを書き換えるだけでツールの内容を更新出来ますね。
問題があるとすれば、stdscritsで読んだ変数はグローバル変数になるというところです。
上記例でいうと、変数aaaがグローバル変数に・・・。

でも実際には読み込む対象は構造体などだと思うので、ほとんど問題無いんじゃないでしょうか。

2015年5月30日土曜日

dotNetObject "MaxCustomControls.Win32HandleWrapper"

maxHandlePointer = (Windows.GetMAXHWND())
sysPointer = dotNetObject "System.IntPtr"maxHandlePointer
maxHwnd = dotNetObject "MaxCustomControls.Win32HandleWrapper" syspointer

このdotNetオブジェクト、MAXscriptのヘルプやチュートリアルを眺めてると
フォーム生成の最後あたりでよく見かけます。

最初はなんぞやーと思ってたのですが、どうやら、
「MAXを最小化した時に一緒にフォームも最小化される」だとかのコントロールをMAX側に委ねるdotNetオブジェクトのようです。

さて、ここでヘルプ通りにdotNetオブジェクトを設定すると、
MAX2013 まではエラーなく動いてくれるのですが、2014、2015だとエラーが出てしまいます。
ヘルプ通りなのに!(※2016は未検証)

これはどういうことかというと、
2014、2015では、 「Windows.GetMAXHWND()」から"MaxCustomControls.Win32HandleWrapper"
が削除されてしまったにもかかわらず、ヘルプは昔のまま・・・・
というのが原因らしいです。

というわけで代替コード。

maxHandlePointer = (Windows.GetMAXHWND())
sysPointer = DotNetObject "System.IntPtr" maxHandlePointer
mainwin = dotNetObject "System.Windows.Forms.Control"
mainwin.fromHandle sysPointer

--フォームを生成--
maxForm = dotNetObject "MaxCustomControls.MaxForm"
maxForm.Show(mainwin)


代替コードは何通りかあると思いますが、AREAで紹介されていたコードを紹介しました。
MAXscrpitでdotNetを扱おうとすると、経験上、標準ヘルプはほとんど役に立ってません。

元ネタ:http://forums.autodesk.com/t5/programming/is-win32handlewrapper-not-in-maxcustomcontrols-anymore/td-p/5115984

2015年5月28日木曜日

blogger始めました。

サイト閉じちゃったんでblogだけ初めました。
 MAXscriptあたりの話題を書いていく予定。

MAXscriptとdotNetで苦戦した経験はきっと他の人の役にたつと信じて。