Windows」カテゴリーアーカイブ

Windows 7 C# Build @ .NET4.0

正月といえば、やはりプログラミングですよね。

前回は .NET Framework 3.5 の WPF を使いました。
それは Windows 7 なら最初から必ず入っているからという理由もありますが。
実は .NET 4.0 でやってみたけど上手くいかなかったから…

やはり現在の最新技術である 4.0 を使ってみたいじゃないですか。
ということで色々と自分で実験してみた。
技術文書とかは読まず(解らないもん)自力で漁った結果と前置きして。

.NET 3.5 での reference はカレント及び csc.exe のディレクトリ
それと C:\Windows\assembly を探すようだ。

このファイルに見えるものは実態ではない、端末で見れば解る。
Linux ばかり使っていて良かった、以前なら端末で見ようなんて絶対に思わない。

サブディレクトリ内に実態がある、正直なんだかよく解らない。
とにかく 4.0 の csc.exe ではこの位置の PresentationCore.dll は見つけられない。

4.0 の csc.exe があるディレクトリをよく見ると、ぶっちゃけ下記だが
C:\Windows\Microsoft.NET\Framework64\v4.0.30319
に WPF というディレクトリがありソコにも PresentationCore.dll 等が。
ということはコッチを /lib オプションで指定すればいいようだ。

/lib 指定でビルド、System.Xaml.dll が見つからないとエラー…
って .NET 3.5 までは System.Xaml アセンブリなんて無かったような気がするんだが。
上記 assembly ディレクトリを漁ってもやはり見当たらないし。

WPF 4(VS 2010&.NET 4シリーズ) ? @IT

どうも .NET Framework 4.0 からのようで、XAML を使っていなくても必要なのね。
csc.exe のディレクトリ直下にある、ので System.Xaml.dll を参照追加指定だけ。
暗黙のリンクはやってくれない、何か事情があるのだろう。

ところで 64bit ディレクトリ指定にして配布は大丈夫なのだろうか?
exe に位置情報が埋め込まれていたりすると 32bit では動かないんだが。
32bit と 64bit の csc.exe でビルドして diff してみる。

exe 名以外は特に違いが見つからない、というかパス情報は無いみたい。
というかどちらも AnyCPU ビルドなんだからほとんど同じものが作られるんだね。
ネイティブで動くか WOW64 で動くかの違いだけなのかな?

どっちでも同じなら 32bit 位置指定のほうが心配が少なそうだから今後はそれで。
ということで 64 でないほうのディレクトリ指定でバッチを作る。

build32.bat

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe ^
/lib:C:\Windows\Microsoft.NET\Framework\v4.0.30319\WPF ^
/reference:System.Xaml.dll ^
/reference:PresentationCore.dll ^
/reference:PresentationFramework.dll ^
/reference:WindowsBase.dll ^
/target:winexe ^
/out:TextReader.exe ^
/win32icon:icon.ico ^
/optimize+ ^
src.cs
PAUSE

v4.0.30319 というディレクトリ名は皆同じなんだろうか…
この Blog は自分で作って自分で使う(遊ぶ)人向けなのだからオケということで。

ということで今回は自分で復習のつもりでテキストリーダーを作ってみた。
UTF-8 以外は文字化けします、私は全部 UTF-8 保存しているので問題無し。
エントリポイントが解りにくいので __main__ という名前にしたw

src.cs

using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Win32;

class TextReader : Window
{
	private TextBox _textbox;

	public TextReader()
	{
		this.Title = "てきすとりぃだぁ!";
		this.Width = 400;
		this.Height = 400;
		this.CreateControls();
	}
	private void CreateControls()
	{
		_textbox = new TextBox();
		_textbox.TextWrapping = TextWrapping.NoWrap;
		_textbox.AcceptsReturn = true;
		_textbox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
		_textbox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
		// Button
		var button = new Button();
		button.Content = "Open the Text";
		//button.Click += new RoutedEventHandler(on_button_click);
		button.Click += on_button_click;
		DockPanel.SetDock(button, Dock.Top);
		// DockPanel
		var dockpanel = new DockPanel();
		// Append
		dockpanel.Children.Add(button);
		dockpanel.Children.Add(_textbox);
		this.Content = dockpanel;
	}
	void on_button_click(object sender, RoutedEventArgs e)
	{
		var dlg = new OpenFileDialog();
		var res = dlg.ShowDialog(this);
		if (res.Value)
		{
			var sr = new StreamReader(dlg.FileName, Encoding.UTF8);
			_textbox.Text = sr.ReadToEnd();
			sr.Close();
		}
	}
}

class __main__
{
	[STAThread]
	public static void Main(string[] args)
	{
		var app = new Application();
		app.Run(new TextReader());
	}
}

textreader.zip

new RoutedEventHandler() を使わずにイベントハンドラが追加できたんだが…
以前からそうなのかな、VisualStudio だと強制的に書き込まれるはずなんだが。
余計な new が少ないのは嬉しいよ。

.NET 4.0 なので Microsoft.Win32 名前空間のダイアログも最新だ。
それ以外は 4.0 の恩恵が何も無いという…

3.0 時のような劇的進化は特に無いし 3.5 でイイやとか思ってしまうよ。
とにかく .NET 4.0 でも何もインストールせずに遊ぶ方法が解ったのでよし。

Windows 7 C# Build @ WPF

久々に Windows を使っているけど IronPython が遅すぎる。
コンパイル不要でライブラリも .NET がほぼフルで使えるので困らないし何より簡単。
なのはいいのだけれど、DLR 初期化が遅すぎて道具として使う気にならない。
地味に小物ツールを作っているんだけれど使わない…

コンパイルするなら C# で作ったほうが楽だし Web 上の Tip’s も C# なら桁違い。
それより何より Windows 7 なら何もインストールせずに C# がビルドできる。

Windows 7 の csc.exe で遊んでみる

なんか IronPython も将来性が不安な雰囲気だし。

米Microsoft、IronRubyおよびIronPythonをコミュニティに移管 – SourceForge.JP Magazine : オープンソースの話題満載

もう Windows は C# を主に利用するほうが懸命かと。
SeeMe も次で C# に戻すか考えなければ。

ということで今回は VisualStudio 等を一切使わずに WPF ウインドウを作る方法を。

VisualStudio を使ったほうが簡単だ!と言わない。
Linux ばかり使っている人間はテキストエディタとコンソールのほうが楽なんじゃい。
小物のツールを作るのに統合開発環境なんてバカな話だ。
本音は Visual C# だかの無償開発環境をインストールして何も作れない人を馬鹿にしたいから。

Microsoft.Win32.OpenFileDialog for .NET 4.0

IronPython は clr.AddReferenceByPartialName() メソッドでアセンブリ参照の追加ができた。
けど C# は同じようにコードでアセンブリ参照を追加する方法が見つからない。
というかコンパイル時に厳しい文法チェックを行う C# ではソレは無理なのかな。
素直にコンパイラオプションで参照する方法を MSDN で探す。

C# Compiler Options Listed by Category

/reference オプションを利用するだけなのか。
アイコンも /win32icon オプションだけで指定できる、VC++ より簡単だ。
引数が多くて長いのでバッチを作ったほうが楽だね。

build.bat

C:\Windows\Microsoft.NET\Framework64\v3.5\csc.exe ^
/reference:PresentationCore.dll ^
/reference:PresentationFramework.dll ^
/reference:WindowsBase.dll ^
/target:winexe ^
/out:net35wpf.exe ^
/win32icon:777.ico ^
/optimize+ ^
wpf_win.cs
PAUSE

この例は .NET 3.5 の csc.exe を使うのでフルパスを、32bit の人はパスを書き換えてね。
^ を利用すればインラインなコマンドを改行できる、bash は \ だけど。
最後に PAUSE と書けば *.bat の W クリックでコンソールが閉じないのでお勧め。
アイコンは勝手に用意して書き換えよろしく。

肝心な C# コードはせっかくなので Binding を使ってみた。
Main 関数に Single Thread Apartment 属性は必須なので忘れずに。
あ、BOM 付き UTF-8 で保存ね。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;

class OreWin : Window
{
	private TextBox _textbox;
	private TextBlock _textblock;

	public OreWin()
	{
		this.Title = "俺のういんどう!";
		this.Width = 400;
		this.Height = 120;
		this.DataContext = _textbox;
		this.CreateControls();
		// Binding
		var binding = new Binding("Text");
		binding.Source = _textbox;
		_textblock.SetBinding(TextBlock.TextProperty, binding);
	}
	private void CreateControls()
	{
		_textbox = new TextBox();
		_textblock = new TextBlock();
		var label = new TextBlock(new Bold(new Run("何か書くと下にコピーされる")));
		var stackpanel = new StackPanel();
		// Append
		stackpanel.Children.Add(label);
		stackpanel.Children.Add(_textbox);
		stackpanel.Children.Add(_textblock);
		this.Content = stackpanel;
	}
}

class Test
{
	// WPF 等では STA 属性必須!
	[STAThread]
	public static void Main(string[] args)
	{
		var win = new OreWin();
		var app = new Application();
		app.Run(win);
	}
}
//

Pascal & C++ 屋だった頃は勘違いしやすい var に否定的だったけど…
Python 屋になった後では var と書くのすら面倒臭くなってしまった。
つーかメンバアクセスに this を書かなければ気がすまなくなっているのが怖い。
new もウザい、セミコロンを忘れる、メンバ変数も this にくっつけ…(以下略
C# って何か中途半端な気がする、まあ従うだけだが。

とにかく build.bat を W クリックしてコンパイル。
アイコンを含めたコードも置いてみる。

wpf_win_src.zip

よしよし、何もインストールしないでコンパイルできたぞと。
しかも起動はアッという間、IronPython をやっていたのが馬鹿馬鹿しい。
来年からはこんな感じで Windows でも小物を作っていきますか。

******************************

2010 年の反省、サイトもブログも更新歩度が下がり続けている。
ヤル気が無くなったわけではない、株を始めたので勉強に忙しいのです。

ちなみに今年のアフィリエイト収入は三千円ちょっと…
たった二十万円で始めた株は四ヶ月で一割強増えた…
当然のように株の更なる勉強と増資の日々に…

Linux プログラミング Blog なんてアホくさくてやってらんねぇ!
いくら Linux でのアプリ作りが主な記事の Blog だからってコレでは…

やはり Windows プログラミングをもう少し増やしたほうが良さそう。
というわけでまた来年。

ubuntu japanese

色々弄くっていたら Ubuntu 10.10 がまったく起動できなくなった。
この際だから日本語 Remix 版に変更して新たにインストールすることにした。

他にも Anthy のトレイアイコンが無いとかボリュームのトレイアイコンが消えたとかetc…
細々と問題が出ていたのだけど、いくら解決方法を検索しても見つからない。

やっぱり個人なのにメインで Ubuntu を使っている人ってゼロに近いのだろうか…
それともユーザーのスキルが上がり過ぎて情報を上げてくれる人がいなくなったのだろうか…
いやまてよ、もしかして日本語 Remix 版なら大丈夫ということなのかもしれない。
と考えた結果そういうことに。

とりあえずこの HDD が死んでいないか確認、以前使っていた 10.04 の HDD に換装。
スレーブで 10.10 HDD を繋いでマウント可能かやってみる、良かったファイルは無事だった。

とにかく、このまま 10.04 の HDD に新規インストールしてファイル全部コピーでイケそう。

まずは日本語 Remix iso をダウンロードしなきゃいけない。
ミニノートの Windows 7 64bit を約一ヶ月ぶりに立ち上げる。
マジで全然 Windows を使わなくなったなぁ…
その一ヶ月前も Windows Update だけで嫌になって終了しちゃったし。

今回も当然アレもコレもと個別でアップデートが始まる、しかも時間が掛かる…
毎日使う人じゃないとやっぱりこの仕様は辛いよ…
Ubuntu も似たようなものだが一括だし再起動が糞早いからマシ。

とにかく iso のダウンロード完了。
そういえば書き込みソフトを入れていないんだが、どうしよう?

と思ったけど Windows 7 って標準機能で iso の書き込みもできたんだね。
CD-R や DVD-R をドライブに突っ込んで iso を右クリし書き込みを選択。
こんなにアッサリって…

本当に Windows 7 ってオンラインソフト殺しだよね。
こんな時代になってもオンラインソフト作者をやっている人ゴクロウサン。
ソレはどうでもよくて。

ついでに RadeonHD4350 の激安ボードを買って動画アクセラレーションを狙ったが…
インストール直後から起動できネェ!ワロタ。
結局外してインストールのやりなおし、時間と小銭の無駄だったけど何故か懐かしい。
どっちにしても AMD 690G マシンを使い続けるのはそろそろ限界かな。

ということで完了後 Anthy とボリュームのトレイアイコンは解決した。
…のかな?まだ初期状態だし以後は探りながら。

SeeMe for Windows 5.0.0

SeeMe for Windows 5.0.0 公開。
実は大半が二日前に終わっていたのですが、たった一箇所で二日掛かった。
Deleted プロパティ変更を SeeMe 本体でどうやって検知するかで。

INotifyPropertyChanged によって ListView にはバインディングされているんだけど…

<Window.Resources>
<DataTemplate x:Key="tpl_show">
    <CheckBox IsChecked="{Binding Path=delete}" IsTabStop="False" Click="CheckBox_Click" />
</DataTemplate>

と C# で作っていた時には DataTemplate で CheckBox.Click イベントのハンドラを指定していた。
こうしておけばこの DataTemplate を利用した CheckBox 全てに同一ハンドラがコネクトされる。
クリックで property が変更されましたというのを本体で知りたいだけなのでコレで十分。

IronPython では partial class にする方法が解らない(方法あるの?)というのと
SeeMe for Linux の GTK+ と限界までソックリにしたいということで ListView をパーツ化した。
結果イベントハンドラのコネクトはコードで行う以外に手が無い。

ListView サブクラスを作って partial にして XAML の x:Name 属性を…
散々試してみたんだがどうしても上手くいかない、やはり無理か?

えっと、ハンドラを含めたリソースをコードで書いて…
方法が解らない、つかそんなことできるのかいな?

res = self.custome_listview.FindResource("tpl_show")
print res
checkbox = res.LoadContent()
print checkbox
checkbox.Click += self.on_modification

例外にならないけど反映されない、困った。
海外を探しまくったけどやはり IronPython の細かい情報は少ない…

まてよ、INotifyPropertyChanged を利用しているんだ。
それならコイツを引っ張り出して CheckBox の変更を感知すればいいかも。
無理に Click イベントに拘る必要は無かったのではないか?

と気が付くまで二日も無駄にしたというわけです…

while 1:
    i += 1
    s = "Search Engine %i" % i
    if not ini.section_exists(s):
        break
    en = Engine()
    en.name   = ini.read_str(s, "Name", "")
    en.key    = ini.read_str(s, "Key", "")
    en.url    = ini.read_str(s, "URL", "")
    en.delete = not ini.read_bool(s, "Deleted", False)
    #...
    en.PropertyChanged += self.on_modification
    self.custome_liststore.Add(en)

という感じで PropertyChanged にハンドラをコードで追加メソッドにできる。
しかもコレなら全部のプロパティ変更を監視できるので自前検知処理を減らすことができる。
でもコレだけでは ObservableCollection への追加や削除は検知できないので

self.custome_liststore = ObservableCollection[Engine]()
#...
self.custome_liststore.CollectionChanged += self.on_modification

と CollectionChanged イベントにもハンドラを指定。
コレでやっと予定していたとおりの動作になった。
WPF が複雑すぎるのではなかった、自分が方法に気が付かなかっただけだ。
細かいことは SeeMe スクリプトの Python コードを見てください。

ということで予定を大幅に遅れて Windows 版公開。
メソッド名やアトリビュート名は Linux 版とだいたい合わせたので今後更新は早くなる。
と思う、つか Aspire 1410 ミニノートだけで作るのは結構辛い…

SeeMe V5 002

SeeMe for Windows v4 で一番気にしている部分。
エディット部の XAML が超テキトーであること…

Grid のレイアウトがよく解らなかったので StackPanelのみでレイアウト。
自分で見ても解り辛い、何故か下方から積み上げる最悪のコーディング。
今の私ならパネルを噛ませる技なんかを使うけど当事は手探りだったし。

IronPython でゼロから作り変えするんだ、そろそろなんとかしなければ。
ということで Grid を利用して Linux 版の GTK+ と同じになるようにする。
ちなみに Linux 版のエディット部は GtkTable を継承して

class IniEditor(gtk.Table):
    """
        カスタムタブのエディタ部
    """
    def __init__(self):
        gtk.Table.__init__(self, 6, 7)
        label = []
        for i in range(len(editor_labels)):
            l = gtk.Label(editor_labels[i])
            label.append(l)
        self.edit_name = gtk.Entry()
        self.attach(self.edit_name, 1, 2, 0, 1)
        self.edit_key = gtk.Entry()
        self.attach(self.edit_key, 3, 5, 0, 1, 0)
        self.edit_url = gtk.Entry()
        self.attach(self.edit_url, 1, 6, 1, 2)
        self.edit_query = gtk.Entry()
        self.attach(self.edit_query, 1, 6, 2, 3)
        self.edit_uniqueid = gtk.Entry()
        self.attach(self.edit_uniqueid, 1, 5, 3, 4)
        self.check_post = gtk.CheckButton(editor_checks[0])
        self.attach(self.check_post, 5, 6, 3, 4, gtk.FILL)
        self.edit_icon = gtk.Entry()
        self.attach(self.edit_icon, 1, 5, 4, 5)
        self.check_separator = gtk.CheckButton(editor_checks[1])
        self.attach(self.check_separator, 5, 6, 4, 5, gtk.FILL)
        self.edit_encode = gtk.Entry()
        self.attach(self.edit_encode, 1, 4, 5, 6)
        self.edit_type = gtk.Entry()
        self.attach(self.edit_type, 5, 6, 5, 6, 0)
        # Label
        self.attach(label[0], 0, 1, 0, 1, gtk.FILL)
        self.attach(label[1], 2, 3, 0, 1, 0, xpadding=10)
        self.attach(label[2], 0, 1, 1, 2, 0)
        self.attach(label[3], 0, 1, 2, 3, 0)
        self.attach(label[4], 0, 1, 3, 4, 0)
        self.attach(label[5], 0, 1, 4, 5, 0)
        self.attach(label[6], 0, 1, 5, 6, 0)
        self.attach(label[7], 4, 5, 5, 6, 0)
        self.etc_label = gtk.Label("<span color=\"darkgreen\">Verfbtext =  Position =  NameID =  UseTLD =  </span>")
        self.etc_label.set_use_markup(True)
        #self.etc_label.set_justify(gtk.JUSTIFY_LEFT)
        self.etc_label.set_alignment(0.1, 1.0)
        self.attach(self.etc_label, 0, 6, 6, 7)
        # Button
        self.button = gtk.Button("リストに反映")
        self.attach(self.button, 5, 6, 0, 1, 0)

こうはやりたくないなぁ…
やはりメニュー等と同様に XAML で綺麗に仕上げたい。

とりあえず基本的にコントロールサイズに Column を合わせるには Auto を指定。
サイズ変更した時に表示名エディット部は連動して広がるように。
マージンが必要な所は Margin プロパティを指定。

editor_str = """<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <Label Grid.Row='0' Grid.Column='0'>表示名</Label>
    <TextBox Grid.Row='0' Grid.Column='1' Grid.ColumnSpan='1' Name="edit_name" />
    <Label Grid.Row='0' Grid.Column='2'>キー</Label>
    <TextBox Grid.Row='0' Grid.Column='3' Grid.ColumnSpan='2' Name="edit_key" />
    <Button Grid.Row='0' Grid.Column='6' Grid.ColumnSpan='1' Margin="20,0,20,0" Name="button">リストに反映</Button>

    <Label Grid.Row='1' Grid.Column='0'>URL</Label>
    <TextBox Grid.Row='1' Grid.Column='1' Grid.ColumnSpan='5' Name="edit_url" />

    <Label Grid.Row='2' Grid.Column='0'>クエリ</Label>
    <TextBox Grid.Row='2' Grid.Column='1' Grid.ColumnSpan='5' Name="edit_query" />

    <Label Grid.Row='3' Grid.Column='0'>UNIQUEID</Label>
    <TextBox Grid.Row='3' Grid.Column='1' Grid.ColumnSpan='4' Name="edit_uniqueid" />
    <CheckBox Grid.Row='3' Grid.Column='5' Grid.ColumnSpan='2' Name="check_post">POSTで送信</CheckBox>

    <Label Grid.Row='4' Grid.Column='0'>ICON</Label>
    <TextBox Grid.Row='4' Grid.Column='1' Grid.ColumnSpan='4' Name="edit_icon" />
    <CheckBox Grid.Row='4' Grid.Column='5' Grid.ColumnSpan='2' Name="check_separator">下にセパレータ</CheckBox>

    <Label Grid.Row='5' Grid.Column='0'>エンコード</Label>
    <TextBox Grid.Row='5' Grid.Column='1' Grid.ColumnSpan='3' Name="edit_encode" />
    <Label Grid.Row='5' Grid.Column='4'>サーチタイプ</Label>
    <TextBox Grid.Row='5' Grid.Column='5' Grid.ColumnSpan='2' Name="edit_type" />

    <Label Grid.Row='6' Grid.Column='0' Grid.ColumnSpan='6' Name="label_etc" Foreground="DarkGreen">Verbtext Position NameID UseTLD</Label>
</Grid>"""

なんとか同じようになった、しかし

GTK+ と違って WPF は縮めるとこうなってしまう…
MinWidth とか数値プロパティでではなくコントロールサイズを最小サイズにしたい。
知らないだけで方法があるのだろうか?

んで、コントロール名を元にアトリビュートを作成。
ということで下記のようなコードを書いてみたのだが。

self.editor = XamlReader.Parse(editor_str)
self.editor.edit_name = self.editor.FindName("edit_name")
self.editor.edit_name.Text = "abcde"
DockPanel.SetDock(self.editor, Dock.Bottom)

なんでだよ、Python なのにアトリビュートにできないじゃん。
しかたがないからダミーのクラスを作ってみる。

class Editor():
    pass

class SeeMe(Window):
    def __init__(self, sset):
        # ...
        self.editor = Editor()
        edit = XamlReader.Parse(editor_str)
        self.editor.edit_name = edit.FindName("edit_name")
        self.editor.edit_name.Text = "abcde"
        DockPanel.SetDock(edit, Dock.Bottom)

これなら上手くいく。
XAML から作成すると Python オブジェクトとして扱ってくれないようだ。
IronPython は Python クローンだと思って使うと色々落とし穴がありますね。

seeme5_002.zip

どうでもいいけど readme.txt と ChangeLog.txt を BOM 付き UTF-8 に。
Python コードは BOM 無し UTF-8 に、色々と事情があってコレに統一。
それと改行を CRLF にしとかないと notepad.exe で改行してくれない。
Windows って面倒くさいなぁ…

見た目はなんとかなったので後は編集コードの作成だ。
連休だけど月曜は仕事だ、明日には仕上がるだろうか…

追記 @ 2010.07.19
進んでいないけど盗難が怖いのでバックアップ、畜生、夏のやろう!

seeme5_003.zip

追記 @ 2010.07.20
エディタ部への設定書き出しを実装、思っていたより手間が掛かる。
そういえば Linux 版は競合キーチェックを入れ忘れしていた…
ついでに Has endseparator をマイナスにしていない、10.60 では無意味な部分だが。

seeme5_004.zip

追記 @ 2010.07.21
__init__.pyw というファイル追加、コレを ipyw(64).exe に関連付けかドロップ。
としておけば Python ワカンネな人でも理解しやすいかも?と思ったので…
ini 保存は色々あって UTF-8 に BOM を付けるようにした。
デフォルト uuid 指定タブもなんとか完成、もう変更できるようにしておいた。
Item の編集と削除は実装したけど新規追加や並べ替え処理はまだ実装していない。
Linux 版とアトリビュート名やメソッド名合わせを考えなければもっと早く作れるけど…
次の日の仕事に影響が出ない範囲で作っているのもあって我ながら遅い…

seeme5_005.zip