前回は2日前
前回の記事
画像をウィンドウの外側に移動したとき
外側に出たままになっているこれを
スクロールバーを自動で表示する
デザイン画面とXAML
MainWindow
灰色のところは必要ないところ(選択画像を30度回転)
ExImage
ふたつの赤いところが前回から書き加えたところ
スクロールバーを表示する準備
これの外側にScrollViewerを設置する
Canvasにスクロールバーが表示される
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
これでそれぞれ垂直と水平バーの表示をオートにしているので
Canvasの大きさがウィンドウより大きくなった時だけ表示される
試しにCanvasの大きさを300x300にすると
スクロールバー非表示になる
左上に寄せたいから
CanvasのVerticalAlignmentをTop
HorizontalAlignmentをLeft
スクロールバーを適切に表示するには
CanvasのSize(大きさ)を指定する必要がある
その大きさは表示されている画像が全てがピッタリ収まる範囲
例えば
赤枠の範囲が求めたいSize
そのためには画像(を表示しているExImage)それぞれの位置(Locate)とSizeが必要
なので求める順番は
画像サイズ→赤枠サイズ→Canvasサイズ
こうなる
画像サイズは
Dim s As New Size(ex.Width, ex.Height)
exは画像を表示しているExImageコントロール
これでいいような気もするんだけど例えば
100x100サイズの画像を表示している状態のExImageから
サイズを取得できるプロパティはいくつかあって
RenderSize、DesiredSize、ActualWidthとActualHeight
これらは3つとも100.0139573とか微妙な値
Sourceとなっている画像自体から得られる
PixelHeightとPixelWidthは100ってあるからこれで良さそうだから
Dim b As BitmapImage = ex.Source
Dim s As New Size(b.PixelWidth, b.PixelHeight)
これでいいかと思ったら今度は
画像を回転した時には対応できなくて
こうなってしまう
ググッて
プログラミング Windows 第6版 第10章 WPF編 - 荒井省三のBlog - Site Home - MSDN Blogsここの「10.14(P469) 要素の配置先の取得」
http://blogs.msdn.com/b/shozoa/archive/2014/08/22/using-programming-windows-chapter10.aspx
TransformToVisualとTransformBoundsってのを真似して
Dim cVisual As GeneralTransform = ex.TransformToVisual(canvas1)
Dim r As Rect = cVisual.TransformBounds(New Rect(ex.RenderSize))
できた
GeneralTransformのTransformBoundsメソッドで取得できる感じ?
迷うのがTransformBoundsに渡す引数のRectのSizeを
100.0139か100のどちらにするか
結果も違ってくる
rが100.0139を渡した場合、r2が100の場合
rのサイズは 136.621
r2のサイズは 136.602
誤差みたいなものだけどどっちのほうがいいかなあ
見た目だと全く同じw
でもこれで画像(ExImage)のサイズとついでに位置も取得できた
両方書いたけどすっきりする100の方かなあ↓
Private Function GetRect(ex As ExImage) As Rect
'RenderSize版100.0139
'Dim cVisual As GeneralTransform = ex.TransformToVisual(canvas1)
'Dim r As Rect = cVisual.TransformBounds(New Rect(ex.RenderSize))
'Return r
'SourceのPixelWidth版100
Dim gt As GeneralTransform = ex.TransformToVisual(canvas1)
Dim b As BitmapImage = ex.Source
Dim r As Rect = gt.TransformBounds(New Rect(New Size(b.PixelWidth, b.PixelHeight)))
Return r
End Function
Rectは位置とサイズを入れておける、WindowsフォームアプリでいうRectangle
ex.TransformToVisual(canvas1)
これでcanvas1におけるExImageのGeneralTransformの何かを取得している?
取得したGeneralTransformのTransformBoundsメソッドに渡すRectの
位置は0,0、サイズはRenderSizeの方にしてみた
これで赤枠になる位置とサイズ範囲のRectが得られる次は複数画像がぴったり収まるサイズの取得
赤枠になる範囲の取得
これはRectクラスのUnionメソッドで取得できるRect.Union(Rect、Rect)
二つのRectを渡すとその2つが収まるピッタリのRectを返してくれる
3つ以上の時は返ってきたRectと3つめのRectを渡すことをすれば
いくつでもいい
Private Function GetUnion(ex As ObservableCollectionExImage) As Rect
Dim r As Rect = GetRect(ex(0))
'すべてのRectangleのUnionを取得
For i As Integer = 1 To ex.Count - 1
r = Rect.Union(r, GetRect(ex(i)))
Next
Return r
End Function
Dim r As Rect = GetRect(ex(0))
'すべてのRectangleのUnionを取得
For i As Integer = 1 To ex.Count - 1
r = Rect.Union(r, GetRect(ex(i)))
Next
Return r
End Function
これでOK
次
得られたRectのサイズをCanvasに指定するは
Dim r As Rect = GetUnion(CollectionExImage)
canvas1.Width = r.Width
canvas1.Height = r.Height
これでOK
水色画像をウィンドウより外側の右下に移動させたところ
スクロールバーが表示された
でも左か上方向に移動させた場合
スクロールバーが表示されないし
ウィンドウより小さな範囲の時
この場合も左上に寄せて
このように表示させたい
赤枠になる範囲の左上をCanvasの左上にピッタリ合わせれば良さそう
それぞれの左上がどれだけ離れているかは
さっき取得したRectに記録されているのでそれを使って
全部の画像を移動させる
さっきのこの状態
この時に取得したRectの中を見てみると
-54,-42,154,142
-54,-42が位置、154,142が幅と高さのサイズ
位置がマイナスになっていて左上が表示されていない
0にすればピッタリになるので
すべての画像の位置(x,y)にx+54、y+42すればいいことになる
'位置調整
Public Sub AjustLocation()
Dim r As Rect = GetUnion(CollectionExImage)
canvas1.Width = r.Width
canvas1.Height = r.Height
If r.X <> 0 OrElse r.Y <> 0 Then
For Each ex As ExImage In CollectionExImage
SetLeft(ex, GetLeft(ex) - r.X)
SetTop(ex, GetTop(ex) - r.Y)
Next
End If
End Sub
ズレていた場合だけ処理すればいいので
If r.X <> 0 OrElse r.Y <> 0 Then
位置が0以外の時だけ処理
この処理をいつするか
一番かっこいいのは画像をマウスドラッグで移動している最中なんだけど
今の方法だとウィンドウより外側に移動させた瞬間に
ものすごい勢いでCanvasが大きくなり続けてしまうので
マウスボタンを離した時で妥協…
ExImage(画像)クラスでマウスの左ボタンを離した時にしたいから
OverridesしたOnPreviewMouseLeftButtonUpに書きたい
でも位置調整のメソッドはMainWindowの方に書いてあって直接呼べないので
これを参照できるように
ExImageクラスに
Private Main As MainWindow
Public Sub New(o As MainWindow)
Main = o
End Sub
こう書いた(少し使い方が間違っているかも、よくわかっていない)
クラス作成時にMainWindowを取得してMainって名前にした変数に入れておいてこのMainから位置調整のメソッドAjustLocationを呼ぶようにした
なのでMainWindowのほうでExImageを作成するときは
Dim ex As New ExImage()
こうだったのを書きなおして
Dim ex As New ExImage(Me)
こうなった
引数にMe(自分自身のMainWindow)を渡す
これでExImageクラスからMainWindowのPublicの付いた
メソッドを呼び出せるようになったので
Protected Overrides Sub OnPreviewMouseLeftButtonUp(e As MouseButtonEventArgs)これで動いている
MyBase.OnPreviewMouseLeftButtonUp(e)
Main.AjustLocation()
End Sub
次回は画像ファイルとして保存
WPFとVBでアプリ作る準備その6、Canvas内に表示している複数画像を1枚の画像にして保存 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13921249.html