見えないマス目(グリッド)に合わせる移動
グリッドの数値を変化させて
100x100の画像を移動しているところ
前回の記事
17行目
TextBlock追加、名前は"tbLocate"にした
選択画像の位置を表示する用
23行目
Slider追加、名前はgridSdrにした
このスライダーの値を移動間隔にする、値が10なら10
ピクセルごとに移動
指定数値は1から64、変化させる最小値は1にしたいのでメモリ間隔の
TickFrequencyは初期値の1そのままでIsSnapToTickFrequencyをTrueに指定
IsManipulationEnabledも有効にしたほうが良さそうだったのでTrue
24行目
TextBlock追加、名前は"masuTbk"にした
スライダーの値が変化した時に自動で更新して表示したいので
Text="{Binding ElementName=gridSdr, Path=Value}"
これでスライダーを動かしたら連動して値を表示してくれる
まだよくわかってない
ExImageクラス
前回から変化なし
MainWindowクラス
12から65行目、98、135、153行目が今回書き加えたところ
Imports System.IO
Imports System.Windows.Controls.Primitives
Imports System.Windows.Controls.Panel
Imports System.Windows.Controls.Canvas
Class MainWindow
Private WithEvents FocusExImage As ExImage
Private CollectionExImage As New ObservableCollectionExImage
Private Sub DisplayUpdateLocate(ex As ExImage)
tbLocate.Text = "Locate = " & GetLeft(ex) & "," & GetTop(ex)
End Sub
Private Sub AjustGrid(ex As ExImage)
Dim p As Point = GetRect(ex).Location
Dim g As Integer = gridSdr.Value
Dim xm As Integer = p.X Mod g
Dim ym As Integer = p.Y Mod g
If xm <> 0 Then
SetLeft(ex, GetLeft(ex) - xm)
End If
If ym <> 0 Then
SetTop(ex, GetTop(ex) - ym)
End If
Call DisplayUpdateLocate(ex)
End Sub
Private Sub ExImage_DragMove(sender As Object, e As DragDeltaEventArgs)
Dim g As Integer = gridSdr.Value
Dim ex As ExImage = DirectCast(sender, ExImage)
Dim xMove As Integer = e.HorizontalChange
Dim yMove As Integer = e.VerticalChange
Dim xIma As Integer = GetLeft(ex) + xMove
Dim yIma As Integer = GetTop(ex) + yMove
Dim xMod As Integer = xIma Mod g
Dim yMod As Integer = yIma Mod g
SetLeft(ex, xIma - xMod)
SetTop(ex, yIma - yMod)
Call DisplayUpdateLocate(ex)
End Sub
Private Sub ExImage_Loaded(sender As Object, e As RoutedEventArgs)
Call AjustGrid(sender)
End Sub
Private Function GetBitmapImage(filePath As String) As BitmapImage
Dim bmp As New BitmapImage
Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
With bmp
.BeginInit()
.StreamSource = fs
.CacheOption = BitmapCacheOption.OnLoad
.EndInit()
.Freeze()
End With
End Using
Return bmp
End Function
Private Sub AddThumb(filesPath As String, locate As Point)
Dim ex As New ExImage(Me)
CollectionExImage.Add(ex)
SetZIndex(ex, CollectionExImage.Count - 1)
canvas1.Children.Add(ex)
Dim bmp As BitmapImage = GetBitmapImage(filesPath)
With ex
.Source = bmp
End With
SetLeft(ex, locate.X)
SetTop(ex, locate.Y)
AddHandler ex.ExDragDelta, AddressOf ExImage_DragMove
AddHandler ex.MouseDown, AddressOf ExImage_MouseDown
AddHandler ex.Loaded, AddressOf ExImage_Loaded
End Sub
Private Sub MainWindow_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
Dim filesPath() As String = e.Data.GetData(DataFormats.FileDrop)
Dim locate As New Point(0, 0)
For i As Integer = 0 To filesPath.Length - 1
Call AddThumb(filesPath(i), locate)
locate.Offset(30, 30)
Next
End Sub
Private Sub kousin()
tbZIndex.Text = "ZIndex = " & GetZIndex(FocusExImage).ToString
End Sub
Private Sub age_Click(sender As Object, e As RoutedEventArgs) Handles age.Click
Dim z As Integer = CollectionExImage.IndexOf(FocusExImage)
Call ZOrder(z, z + 1)
End Sub
Private Sub sage_Click(sender As Object, e As RoutedEventArgs) Handles sage.Click
Dim z As Integer = CollectionExImage.IndexOf(FocusExImage)
Call ZOrder(z, z - 1)
End Sub
Private Sub ZOrder(Moto As Integer, Saki As Integer)
If FocusExImage Is Nothing Then Return
CollectionExImage.Move(Moto, Saki)
Call kousin()
End Sub
Private Sub ExImage_MouseDown(sender As Object, e As RoutedEventArgs)
Call AjustGrid(sender)
FocusExImage = sender
mihon.Source = FocusExImage.Source
Call kousin()
End Sub
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
Call AjustGrid(FocusExImage)
End If
End Sub
Private Function GetRect(ex As ExImage) As Rect
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
Private Function GetUnion(ex As ObservableCollectionExImage) As Rect
Dim r As Rect = GetRect(ex(0))
For i As Integer = 1 To ex.Count - 1
r = Rect.Union(r, GetRect(ex(i)))
Next
Return r
End Function
Private Sub SaveAllImage()
If CollectionExImage.Count = 0 Then Return
Dim dialogSave As New Microsoft.Win32.SaveFileDialog
With dialogSave
.Filter = "*.png|*.png|*.jpg|*.jpg;*.jpeg|*.bmp|*.bmp|*.gif|*.gif|*.tiff|*.tiff"
.AddExtension = True
End With
If dialogSave.ShowDialog Then
Dim canvasRect As Rect = GetUnion(CollectionExImage)
Dim dv As New DrawingVisual
Using dc As DrawingContext = dv.RenderOpen
Dim vb As New VisualBrush(canvas1)
dc.DrawRectangle(vb, Nothing, canvasRect)
End Using
Dim rtb As New RenderTargetBitmap(canvasRect.Width, canvasRect.Height, 96, 96, PixelFormats.Pbgra32)
rtb.Render(dv)
Dim enc As BitmapEncoder = Nothing
Select Case dialogSave.FilterIndex
Case 1
enc = New PngBitmapEncoder
Case 2
Dim je As New JpegBitmapEncoder
je.QualityLevel = 97
enc = je
Case 3
enc = New BmpBitmapEncoder
Case 4
enc = New GifBitmapEncoder
Case 5
enc = New TiffBitmapEncoder
End Select
Dim bf As BitmapFrame = BitmapFrame.Create(rtb)
enc.Frames.Add(bf)
Using fs As New FileStream(dialogSave.FileName, FileMode.Create)
enc.Save(fs)
End Using
End If
End Sub
Private Sub save_Click(sender As Object, e As RoutedEventArgs) Handles save.Click
Call SaveAllImage()
End Sub
Private Sub kaiten_Click(sender As Object, e As RoutedEventArgs) Handles kaiten.Click
Dim rtf As New RotateTransform(30)
FocusExImage.RenderTransform = rtf
End Sub
End Class
DisplayUpdateLocate
デザイン画面で選択画像(ExImage)の位置表示をしているtvLocateの
表示を更新するだけのメソッド
使っているところは
画像をグリッドに合わせる
Private Sub AjustGrid
画像の移動中
Private Sub ExImage_DragMove
このふたつ
AjustGrid
選択画像(ExImage)の位置を最寄りのグリッド(マス目)に移動させるメソッド
実行するタイミングはマウスでクリックした直後の
Private Sub ExImage_MouseDown(sender As Object, e As RoutedEventArgs)
と、画像を移動し終わった時に位置合わせのメソッドの
Public Sub AjustLocation()
この2つ
移動先の位置は指定された数値の倍数になればいいんだから
元の位置を割った余りを求めて
元の位置から引けばいい
指定された数値(マス目間隔)が10で画像の位置がx=11,y=29の時に実行すると
画像の位置はx=10、y=20になるようにしている(左上に寄せる)
p = 11,29
g = 10
xm = 11 Mod 10 = 1 (11÷10の余りは1)
ym = 29 Mod 29 = 9 (29÷10の余りは9)
xm = 1
ym = 9
x = 11 - 1 (p.x - mx)
y = 29 - 9 (p.y - my)
x = 10
y = 20
でいいんだけど今見なおしたら
最初に位置取得しているのに25,28行目でまた位置取得している
っていうムダな計算しているな
ExImage_DragMove
さっきのAjustGridメソッドで移動前の位置はグリッドに合っているはずなので
マウスの移動距離がグリッドぶん動いた時にその位置に移動させればいいってことで
マウスの移動距離÷マス目間隔の余り = 0になった時に移動
ってのが最初の方法だったけど動きがいまいち
どうやら0になった瞬間ってのがよくなさそうだった
なので常に移動させるつもりで、もし移動先がグリッドとズレていたら動かさない
っていう方法にしたらうまく行ったというかPixtack紫陽花と同じ方法になった
ExImage_Loaded
画像(ExImage)のLoadedイベントの時にAjustGridを実行する
画像を追加した時にグリッドに合わせるようにした方がいいかなって
書いたけど要らないかな
複数の画像を任意の間隔で並べて1枚の画像にしたくて
Pixtack紫陽花を作ったんだけど
WPFでもやっとそれっぽくなってきた
予定しているテスト
- 指定した画像の表示を消す(削除)
- 指定した色を透明にする
- レイアウト
完了したテスト
- 画像ファイルドロップで画像表示
- 画像をマウスドラッグで移動
- 表示画像のレイヤー間の移動(入れ替え)ZOrder指定
- 表示画像すべてを画像ファイルとして保存
- ドラッグ移動時に指定ピクセル数ごとに移動 ←New
続きは翌日