天天看點

使用WPF Resource以及Transform等技術實作滑鼠控制圖檔縮放和移動的效果Window1.xamlWindow1.xaml.cs

程式要實作的目的是通過滑鼠來控制圖檔的縮放和移動的效果,也就是說可以滑鼠在程式界面上拖動圖檔,通過滑鼠滾輪放大和縮小圖檔。這種功能在圖檔浏覽程式裡面再普通不過了,一般來說,如果是在MFC或者Winform裡面實作這兩個功能的話,都是通過處理滑鼠的移動和滾輪事件,在這兩個事件處理函數裡面,擷取滑鼠的位置和滾輪滾動的偏移量,然後針對性地更改圖檔的位置和高寬度來做的。

比如說,在Winform裡面實作滑鼠拖拽圖檔功能的話,代碼看起來像下面這樣:

    // 上一次滑鼠移動的位置

    private Point m_PreviousMousePosition;

    private void DoImageMove(object sender, MouseEventArgs e)

    {

        // 将sender轉化成觸發滑鼠事件的控件,在Winform程式裡面,

        // 一般都是PictureBox控件。

        PictureBox picture = sender as PictureBox;

        Debug.Assert(picture != null);

        // 或者滑鼠在PictureBox控件的相對坐标,下面的GetMouseRelativePositionTo

        // 函數是一個虛構的函數,具體的實作可以Google一下他人的實作方式。

        Point mousePosition = GetMouseRelativePositionTo(picture);

        // 移動圖檔,由于MouseMove事件會在我們移動滑鼠的時候觸發多次,

        // 是以我們可以通過擷取兩次滑鼠移動之間,滑鼠指針位置的偏移量

        // 來知道圖檔應該移動的偏移量。

        picture.X += mousePosition.X - m_PreviousMousePosition.X;

        picture.Y += mousePosition.Y - m_PreviousMousePosition.Y;

        // 将這次滑鼠的位置儲存下來。

        m_PreviousMousePosition = mousePosition;

}

對于通過滾動條來實作圖檔縮放的代碼應該會是這樣:

    private void MasterImage_MouseWheel(object sender, MouseWheelEventArgs e)

        // 強迫PictureBox控件在更改大小的時候,自動縮放圖檔

        // 以便填充整個PictureBox控件

        picture.SizeMode = PictureBoxSizeMode.StretchImage;

        // 0.001是我随便取的一個值,因為滾輪的Delta值太大了

        // 根據滑鼠滾輪的偏移量來更改PictureBox寬度和高度。

        picture.Width += e.Delta * 0.001;

        picture.Height += e.Delta * 0.001;

上面兩個代碼也是很簡潔,但問題是,如果程式需要顯示多個圖檔用來作為比對,并且我們移動其中任何一個圖檔,其它圖檔的位置也會跟着有相同的位置變化;縮放其中任何一個圖檔,其它圖檔的也有同樣程度的縮放比例。這樣,我們就得在MasterImage_MouseMove和MasterImage_MouseWheel函數裡面顯示修改所有圖檔的位置。更糟糕地是,上面的代碼很難适應的新的需求,上面的圖檔縮放代碼,實際上是以圖檔最左上角的那個點為原點來進行橫向和縱向縮放的。如果新需求是要求我們以圖檔中心的那個點為原點進行圖檔縮放的話,又該如何修改代碼呢?

WPF提供了很多函數友善我們處理圖檔,例如各式各樣的Transform類用來移動、縮放和旋轉圖檔,有各式各樣的Effect類來修改圖檔的外觀。更難得的是,這些類都可以在XAML代碼直接設定,而XAML為了提高代碼的可維護性又為我們提供了Resource這麼好的概念來将通用的代碼和設定儲存在一個中心位置,其它控件可以直接引用同一個Resource就可以擷取同樣的設定。是以,為什麼我們不能将這兩個工具結合起來編寫盡量少的代碼來實作圖檔移動和縮放的功能呢?

步驟如下:

1.         定義一個TranslateTransform執行個體來修改圖檔顯示的起始位置。

2.         定義一個ScaleTransform執行個體來縮放圖檔的大小,你可以通過設定CenterX和CenterY的值來指定圖檔縮放的原點。

3.         将兩個Transform放到一個TransformGroup裡面,這樣Image控件就可以在顯示的時候綜合使用兩個Transform的效果了。你可以注意一下,TransformGroup的基類也是Transform,想一想這采用的是哪一個設計模式?不知道,呃……看樣子我還需要寫另外一篇文章解釋一下這個設計模式……不過我最近有點忙,如果你等不及看到我下一篇文章的話,還是自己Google一下吧。

4.         将TransformGroup放到目前窗體的Resource裡面,這樣窗體裡面所有的Image控件都可以引用到這個執行個體。

5.         在滑鼠移動事件裡面修改TranslateTransform對應的值。

6.         在滑鼠滾輪事件裡面修改ScaleTransform的ScaleX和ScaleY的值來縮放圖檔。

<Window x:Class="MouseMove.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:MouseMove"

    Title="Window1" Height="600" Width="800">

    <Grid x:Name="MainPanel">

        <Grid.Resources>

            <TransformGroup x:Key="ImageTransformResource">

                <ScaleTransform />

                <TranslateTransform />

            </TransformGroup>

        </Grid.Resources>

        <Grid.ColumnDefinitions>

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

        <Rectangle Grid.Column="0" x:Name="MasterImage"

                   MouseLeftButtonDown="MasterImage_MouseLeftButtonDown"

                   MouseLeftButtonUp="MasterImage_MouseLeftButtonUp"

                   MouseMove="MasterImage_MouseMove"

                   MouseWheel="MasterImage_MouseWheel">

            <Rectangle.Fill>

                <VisualBrush Transform="{StaticResource ImageTransformResource}"Stretch="Uniform">

                    <VisualBrush.Visual>

                        <Image Source="C:"Windows"Web"Wallpaper"Architecture"Img15.jpg" />

                    </VisualBrush.Visual>

                </VisualBrush>

            </Rectangle.Fill>

        </Rectangle>

        <Rectangle Grid.Column="1"

                        <Image Source="C:"Windows"Web"Wallpaper"Architecture"Img14.jpg" />

        </Rectangle>

    </Grid>

</Window>

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

using System.Diagnostics;

namespace MouseMove

{

    /// <summary>

    /// Interaction logic for Window1.xaml

    /// </summary>

    public partial class Window1 : Window

        private bool m_IsMouseLeftButtonDown;

        public Window1()

        {

            InitializeComponent();

        }

        private void MasterImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

            Rectangle rectangle = sender as Rectangle;

            if (rectangle == null)

                return;

            rectangle.ReleaseMouseCapture();

            m_IsMouseLeftButtonDown = false;

        private Point m_PreviousMousePoint;

        private void MasterImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

                return;

            rectangle.CaptureMouse();

            m_IsMouseLeftButtonDown = true;

            m_PreviousMousePoint = e.GetPosition(rectangle);

        private void MasterImage_MouseMove(object sender, MouseEventArgs e)

            if (m_IsMouseLeftButtonDown)

                DoImageMove(rectangle, e);

        private void DoImageMove(Rectangle rectangle, MouseEventArgs e)

            //Debug.Assert(e.LeftButton == MouseButtonState.Pressed);

            if (e.LeftButton != MouseButtonState.Pressed)

            TransformGroup group = MainPanel.FindResource("ImageTransformResource") asTransformGroup;

            Debug.Assert(group != null);

            TranslateTransform transform = group.Children[1] as TranslateTransform;

            Point position = e.GetPosition(rectangle);

            transform.X += position.X - m_PreviousMousePoint.X;

            transform.Y += position.Y - m_PreviousMousePoint.Y;

            m_PreviousMousePoint = position;

        private void MasterImage_MouseWheel(object sender, MouseWheelEventArgs e)

            ScaleTransform transform = group.Children[0] as ScaleTransform;

            transform.ScaleX += e.Delta * 0.001;

            transform.ScaleY += e.Delta * 0.001;

    }

本文轉自 donjuan 部落格園部落格,原文連結: http://www.cnblogs.com/killmyday/archive/2009/06/22/1508148.html  ,如需轉載請自行聯系原作者

繼續閱讀