'Window/WPF'에 해당되는 글 36건

  1. 2010.02.08 [ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기 3
  2. 2010.01.29 [WPF] Object Capture
  3. 2010.01.26 [WPF] 시계 만들기
  4. 2010.01.24 [WPF] Image Pixel
  5. 2010.01.24 [WPF] Drag, Scale, Rotate 1
  6. 2009.09.27 [ WPF ] Drag
Window/WPF2010. 2. 8. 15:55

Window 창의 크기를 변경 시

배치 된 컨트롤들의 크기도 함께 변경 할 경우가 있습니다.

Window의 SizeChanged 이벤트에서 다음과 같은 간단한 로직을 작성하면 됩니다.

 

Window 창의 처음 사이즈와 변경된 사이즈 만큼의 차이만큼

LayoutTransform의 ScaleTransform 값을 변경 시키면 됩니다.

 

예제 소스는 다음과 같습니다.

 

double orginalWidth, originalHeight;

 ScaleTransform scale = new ScaleTransform();

 

 public Window1()

 {

    InitializeComponent();

    this.Loaded += new RoutedEventHandler(Window1_Loaded);

 }

 

 void Window1_SizeChanged(object sender, SizeChangedEventArgs e)

 {

    ChangeSize(e.NewSize.Width, e.NewSize.Height);

 }

 

 void Window1_Loaded(object sender, RoutedEventArgs e)

 {

    orginalWidth = this.Width;

    originalHeight = this.Height;

 

    if (this.WindowState == WindowState.Maximized)

    {

        ChangeSize(this.ActualWidth, this.ActualHeight);

    }

 

    this.SizeChanged += new SizeChangedEventHandler(Window1_SizeChanged);

 }

 

 private void ChangeSize(double width, double height)

 {

    scale.ScaleX = width / orginalWidth;

    scale.ScaleY = height / originalHeight;

 

    FrameworkElement rootElement = this.Content as FrameworkElement;

 

    rootElement.LayoutTransform = scale;

 }

 

결과화면은 다음과 같습니다.

        

         

          

'Window > WPF' 카테고리의 다른 글

[ WPF ] Canvas Image Background  (0) 2010.02.11
[ WPF ] TextBox Select All Text  (0) 2010.02.11
[WPF] Object Capture  (0) 2010.01.29
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Image Pixel  (0) 2010.01.24
Posted by 열ㅇl
Window/WPF2010. 1. 29. 03:21
윈도우 창에 있는 모든 객체들은 그래픽적 요소를 가지고 있기 때문에

VisualBrush를 통해 브러쉬 요소로 사용할 수 가 있습니다.

 

이를 사용하여 윈도우 창에 있는 객체를 선택하거나 선택영역을 지정하여

해당 포맷에 맞는 이미지로 저장하는 간단한 예제를 만들어 보았습니다.

 

예제를 위해 눈사람 이라고 만들었는데 영 이상하네요. ㅎㅎ

 

객체 선택 : 마우스를 커서가 위치한 객체에 다음과 같이 빨간 테두리가 생깁니다.

                 Background 해제 시 객체만을 이미지로 저장합니다.

                 Background 체크 시 객체 영역을 이미지로 저장합니다.

                 저장 : 마우스 왼쪽 버튼

 

 

선택 영역 지정 : Cut 체크박스를 체크 한 후 마우스 왼쪽 버튼을 누른 채 이동하여 사각형을 만듭니다.

                         사각형을 드래그하여 이미지로 저장할 영역을 설정합니다.

                         저장 : 마우스 오른쪽 버튼

 

저장된 결과입니다.

 

예제는 부모 요소가 Canvas임을 고려하여 만들었습니다.

 

객체를 이미지로 변경하는 소스부분입니다.

DrawingVisual 객체로 객체 브러쉬로 사각형 그림을 그린 뒤 RenderTargetBitmap을 사용하여 Bitmap으로 변환합니다.

DrawRectangle의 Rect 첫번째 인자는 브러쉬로 칠할 시작 위치입니다.

 

   30 public static RenderTargetBitmap ConverterBitmapImage(FrameworkElement element)

   31 {

   32     DrawingVisual drawingVisual = new DrawingVisual();

   33     DrawinContext drawingContext = drawingVisual.RenderOpen();

   34 

   35     // 해당 객체의 그래픽요소로 사각형의 그림을 그립니다.

   36     drawingContext.DrawRectangle(new VisualBrush(element), null,

   37         new Rect(new Point(0, 0), new Point(element.ActualWidth, element.ActualHeight)));

   38     drawingContext.Close();

   39 

   40     // 비트맵으로 변환합니다.

   41     RenderTargetBitmap target =

   42         new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight,

   43         96, 96, System.Windows.Media.PixelFormats.Pbgra32);

   44 

   45     target.Render(drawingVisual);

   46     return target;

   47 }

 

 

선택영역을 이미지로 변환하는 부분입니다.

CopyPixels 함수에서 부모 Canvas 이미지에서 해당 영역 만큼 픽셀을 복사해 와 비트맵 소스로 변환합니다.

   104 public static BitmapSource CutAreaToImage(int x, int y, int width, int height)

  105 {

             .

             .   // 예외 처리 부분

             .

  126 

  127     byte[] pixels = CopyPixels(x, y, width, height);

  128 

  129     int stride = (width * backround.Format.BitsPerPixel + 7) / 8;

  130 

  131    return BitmapSource.Create(width, height, 96, 96, PixelFormats.Pbgra32, null, pixels, stride);

  132 }

 

 

CopyPixels은 단지 CopyPixels 함수로 픽셀을 복사합니다.

    82 public static byte[] CopyPixels(int x, int y, int width, int height)

   83 {

   84     byte[] pixels = new byte[width * height * 4];

   85     int stride = (width * backround.Format.BitsPerPixel + 7) / 8;

   86 

   87     // Canvas 이미지에서 객체 역역만큼 픽셀로 복사

   88     canvasImage.CopyPixels(new Int32Rect(x, y, width, height), pixels, stride, 0);

   89 

   90     return pixels;

   91 }

 

 

다음은 객체 영역을 계산하는 부분입니다.

객체 이미지 픽셀과 Canvas영역에서 객체 영역만큼 잘라온 픽셀을 통해 계산해 보았는데

수정이 필요한 부분이네요. -_-;; 아니면 다른 방식으로 객체 영역만을 가져와야 하겠습니다.

하나의 픽셀은 4가지의 값을 (B,G,R,A) 가지고 있기 때문에 객체 브러쉬를 통해 비트맵으로 변환하게 되면 객체가 아닌

부분은 알파값이 제로이기 때문에 이를 사용해 봤지만 에러가 좀 있네요. ㅎㅎ

  142 private static void PixelTransform(byte[] pixels, byte[] element_pixels, int length)

  143 {

  144    for(int i=3; i<length; i+=4)

  145    {

  146        if (element_pixels[i] == 0)

  147        {

  148            pixels[i] = 0;

  149        }

  150        else

  151        {

  152            if (pixels[i] > element_pixels[i])

  153            {

  154                pixels[i] = element_pixels[i];

  155                pixels[i - 1] = element_pixels[i - 1];

  156                pixels[i - 2] = element_pixels[i - 2];

  157                pixels[i - 3] = element_pixels[i - 3];

  158            }

  159        }

  160    }

  161 }

 

Save함수는 포맷에 맞게 인코딩 후 저장합니다.

   169 public static void Save(BitmapSource source, bool png)

  170 {

  171     SaveFileDialog dlg = new SaveFileDialog();

  172 

  173     dlg.Filter = "PNG|*.png|JPG|*.jpg|GIF|*.gif|BMP|*.bmp";

  174     dlg.AddExtension = true;

  175 

  176     if (dlg.ShowDialog() == true)

  177     {

  178         FileStream stream = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write);

  179         BitmapEncoder encoder = new PngBitmapEncoder();

  180 

  181         dlg.FileName.ToCharArray(dlg.FileName.Length - 3, 3);

  182 

  183         string upper = dlg.FileName.ToUpper();

  184         char[] format = upper.ToCharArray(dlg.FileName.Length - 3, 3);

  185         upper = new string(format);

  186 

  187         if (!png)

  188         {

  189             switch (upper.ToString())

  190             {

  191                 case "JPG":

  192                     encoder = new JpegBitmapEncoder();

  193                     break;

  194 

  195                 case "GIF":

  196                     encoder = new GifBitmapEncoder();

  197                     break;

  198 

  199                 case "BMP":

  200                     encoder = new BmpBitmapEncoder();

  201                     break;

  202             }

  203         }

  204 

  205         encoder.Frames.Add(BitmapFrame.Create(source));

  206 

  207         encoder.Save(stream);

  208         stream.Close();

  209     }

  210 }

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] TextBox Select All Text  (0) 2010.02.11
[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Image Pixel  (0) 2010.01.24
[WPF] Drag, Scale, Rotate  (1) 2010.01.24
Posted by 열ㅇl
Window/WPF2010. 1. 26. 17:42

DispatcherTimer, DependencyProperty, IValueConverter 이용해

위젯 형식의 간단한 시계 컨트롤을 만드는 방법에 대해 포스팅 하겠습니다.

 

결과물은 다음과 같습니다.

하나의 클래스를 통해 2개의 시계를 만들어 마우스 오른쪽 버튼을 누를 때마다 변경되도록 하였습니다.

드래그 :  마우스 왼쪽 버튼

종료 : ESC 버튼

 

         

           < 아날로그 >                                  < 디지털 >

 

 

우선 시계 모양으로 쓰일 이미지가 필요하겠죠.

위의 이미지는 배드걸 님의 블로그에서 얻을 수 있었습니다. 감사합니다.^^

 

이제 소스를 살펴보겠습니다.

코드가 짧기 때문에 이해가 쉬우실 겁니다.

 

우선 DateTime형식의 DependencyProperty를 생성 후 ClockTimer가 초기화가 될 때 타이머를 발생시킵니다.

타이머가 발생할 때마다 현재 DateTime 값으로 프로퍼티 값을 변경 시켜줍니다.

 

   10 class ClockTimer : FrameworkElement

   11 {

   12     private DispatcherTimer timer;

   13 

   14     private static DependencyProperty DateTimeProperty =

   15         DependencyProperty.Register("DateTime", typeof(DateTime), typeof(ClockTimer),

   16         new PropertyMetadata(DateTime.Now));

   17 

   18     protected override void OnInitialized(EventArgs e)

   19     {

   20         base.OnInitialized(e);

   21 

   22         timer = new DispatcherTimer();

   23         timer.Interval = TimeSpan.FromMilliseconds(1000);

   24         timer.Tick += new EventHandler(Timer_Tick);

   25         timer.Start();

   26     }

   27 

   28     private void Timer_Tick(object sender, EventArgs e)

   29     {

   30         SetValue(DateTimeProperty, DateTime.Now);

   31     }

   32 }

 

이제 이를 바인딩 용도에 맞게 IValueConverter를 사용 해 클래스들을 작성합니다.

다음은 초침을 위한 Converter입니다. 간단한 산수를 활용해(-_-;) 현재 각도를 구합니다.

   34 [ValueConversion(typeof(DateTime), typeof(int))]

   35 public class SecondsConverter : IValueConverter

   36 {

   37     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

   38     {

   39         DateTime date = (DateTime)value;

   40         return ((DateTime)value).Second * 6;

   41     }

   42 

   43     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

   44     {

   45         return null;

   46     }

   47 }

 

이제 이를 사용할 객체의 Resorces로 등록합니다.

<Grid.Resources>
   <clock:SecondsConverter x:Key="SecondsConverter"/>
   <clock:MinutesConverter x:Key="MinutesConverter"/>
   <clock:HoursConverter x:Key="HoursConverter"/>
   <clock:TimeStringConverter x:Key="TimeStringConverter"/>
    <clock:DateConverter x:Key="DateConverter"/>
</Grid.Resources>

 

마지막으로 ClockTimer 클래스 추가 후 알맞게 바인딩 합니다.

xmlns:clock="clr-namespace:WPFClock"

 

<clock:ClockTimer x:Name="Clock"/>

 

<RotateTransform Angle="{Binding Path=DateTime, Converter={StaticResource SecondsConverter}, ElementName=Clock}"/>

 

Text="{Binding Path=DateTime, Converter={StaticResource DateConverter}, ElementName=Clock}"

 

시계의 바늘들의 회전 중심을 맞추기가 약간 까다로웠지만

Height 값 만큼 Margin 값을 변경 시킨 후 RenderTransformOrigin 의 값을 변경하여 맞출 수 있었습니다.

 

 Height="42" Margin="0,0,0,42" RenderTransformOrigin="0.5,1"

 

자신이 원하는 이미지로 간단한 시계를 만들어 사용하는 것도 괜찮겠네요.

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] Object Capture  (0) 2010.01.29
[WPF] Image Pixel  (0) 2010.01.24
[WPF] Drag, Scale, Rotate  (1) 2010.01.24
[ WPF ] Drag  (0) 2009.09.27
Posted by 열ㅇl
Window/WPF2010. 1. 24. 10:14

이미지의 픽셀 값을 얻어 오기 위해서는 Bitmap으로 불러 들어와 GetPixel 함수를 호출하는 방법도 있지만

BitmapSource를 이용해 얻어오는 방법에 대해 InkCanvas를 사용해 다음과 같은 간단한 예제를 만들어 보았습니다.

 

        

 

소스는 매우 간략하기 때문에 이해가 쉬울 겁니다.

중요한 부분은 픽셀 포맷에 따라 Stride의 값을 달리하여 읽어 들어와야 하는 부분입니다.

 

비트맵의 Stride는 픽셀 데이타의 한 행의 폭으로 바이트 수를 나타냅니다.

이미지 포맷에 따라 오프셋을 구하는 효율을 위해 4의 배수로 부수적으로 의미없는 바이트가 추가 되는 경우가 있습니다.

 

예로 24Bit에서 Width가 17Pixel인 경우 51바이트(3 * 17)가 필요하지만 Stride값은 4배의 배수인 52바이트로 의미없는 1바이트가 추가됩니다.

자세한 자료는 다음 사이트를 참고 하시기 바랍니다.

http://www.bobpowell.net/lockingbits.htm

 

     9 class ImagePixelColor : Image

   10 {

   11     private static readonly DependencyProperty CurrentColorProperty =

   12         DependencyProperty.Register("CurrentColor", typeof(Color), typeof(ImagePixelColor),

   13         new FrameworkPropertyMetadata(Colors.Black,

   14             FrameworkPropertyMetadataOptions.AffectsRender));

   15 

   16     public Color CurrentColor

   17     {

   18         get

   19         {

   20             return (Color)GetValue(CurrentColorProperty);

   21         }

   22     }

   23 

   24     byte[] Pixels = new byte[4];

   25 

   26     protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

   27     {

   28         SetValue(CurrentColorProperty, GetPixelColor(e.GetPosition(this)));

   29     }

   30 

   31     protected override void OnMouseMove(MouseEventArgs e)

   32     {

   33         if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)

   34         {

   35             SetValue(CurrentColorProperty, GetPixelColor(e.GetPosition(this)));

   36         }

   37     }

   38 

   39     private Color GetPixelColor(Point CurrentPoint)

   40     {

   41         BitmapSource CurrentSource = this.Source as BitmapSource;

   42 

   43         // 비트맵 내의 좌표 값 계산

   44         CurrentPoint.X *= CurrentSource.PixelWidth / this.ActualWidth;

   45         CurrentPoint.Y *= CurrentSource.PixelHeight / this.ActualHeight;

   46 

   47         if (CurrentSource.Format == PixelFormats.Bgra32 || CurrentSource.Format == PixelFormats.Bgr32)

   48         {

   49             // 32bit stride = (width * bpp + 7) /8

   50             int Stride = (CurrentSource.PixelWidth * CurrentSource.Format.BitsPerPixel + 7) / 8;

   51             // 한 픽셀 복사

   52             CurrentSource.CopyPixels(

   53                 new Int32Rect((int)CurrentPoint.X, (int)CurrentPoint.Y, 1, 1), Pixels, Stride, 0);

   54 

   55             // 컬러로 변환 후 리턴

   56             return Color.FromArgb(Pixels[3], Pixels[2], Pixels[1], Pixels[0]);

   57         }

   58         else

   59         {

   60             MessageBox.Show("지원되지 않는 포맷형식");

   61         }

   62         // TODO: 다른 포맷 형식 추가

   63 

   64         return Color.FromArgb(Pixels[3], Pixels[2], Pixels[1], Pixels[0]);

   65     }

   66 }

 

Ink의 색상과 선택한 픽셀값을 보여주는 Rectangle의 색상을 변경하기 위해 다음과 같은 컨버트와 바인딩 시켰습니다.

IvalueConverter 인터페이스는 바인딩 엔진을 통과할 때 데이터 수정을 가능하게 하는 메소드를 가지고 있습니다.

다음의 두 함수를 통해 전달되는 데이터를 값을 변경할 수 있습니다.

 

Convert : 소스 데이터를 UI에 표시하기 위해 대상에 전달하기 전에 수정합니다.

ConvertBack : 대상 데이터를 소스 개체에 전달하기 전에 수정합니다. TwoWay 바인딩에서만 호출됩니다.

 value  대상으로 전달되는 소스 데이터
 targetType  대상 종속성 속성에 필요한 데이터 타입
 parameter  변환기 논리에 사용 될 선택적 매개 변수
 culture  변환의 문화권

 

 

    50 [ValueConversion(typeof(Color), typeof(Brush))]

   51 public class ColorBrushConverter : IValueConverter

   52 {

   53     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

   54     {

   55         return new SolidColorBrush((Color)value);

   56     }

   57 

   58     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

   59     {

   60         return null;

   61     }

   62 }

   63 

   64 [ValueConversion(typeof(Color), typeof(DrawingAttributes))]

   65 public class InkColorConverter : IValueConverter

   66 {

   67     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

   68     {

   69         DrawingAttributes attribute = new DrawingAttributes();

   70         attribute.Color = (Color)value;

   71         return attribute;

   72     }

   73 

   74     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

   75     {

   76         return null;

   77     }

   78 }

 

[ Rectangle ]

 Fill="{Binding ElementName=Palette, Path=CurrentColor, Converter={StaticResource ColorConverter}}"

 

[ InkCanvas ]

 DefaultDrawingAttributes="{Binding ElementName=Palette, Path=CurrentColor, Converter={StaticResource InkColorConverter}}"

 

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] Object Capture  (0) 2010.01.29
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Drag, Scale, Rotate  (1) 2010.01.24
[ WPF ] Drag  (0) 2009.09.27
Posted by 열ㅇl
Window/WPF2010. 1. 24. 00:57

 

 

멀티터치는 기본적으로 위와 같은 세 가지의 제스쳐를 사용하여 컨트롤 하게 됩니다.

이를 간단하게 마우스로 동작할 수 있도록 구현해 보았습니다.

멀티터치와 같이 여러 점에 반응하는 것이 아닌 마우스의 두 버튼 만으로 동작하는 점이 다르지만

객체에 전해지는 두 좌표만을 사용하는 원리에는 비슷하지 않나 싶습니다.

 

이전 Drag 예제에선 부모 컨트롤이 Canvas에 제약이 되었기 때문에

이번 예제에서는 RenderTransform 값을 변경함으로써 부모 컨트롤의 제약을 없앴습니다.

 

가지 동작 모두 처음 값과 현재 값의 차이를 구한다는 점에서 공통점이 있습니다.

드래그는 현재 좌표값에서 처음 좌표 값의 차이만큼 현재 객체의 좌표값에 더해 줌으로써 이동시킵니다.

크기 조절은 현재 비율과 처음 비율을 나누어줌으로 변경시킬 비율을 구합니다.

회전은 처음각에서 현재각의 차이를 통해 회전 각을 구합니다.

 

이론은 간단하지만 수식으로 옮기기엔 수학적인 부분이 부족하여 많은 소스들을 참고하였습니다.

수학을 잘 하시는 분이라면 쉽게 하셨을 테지만 말이죠. ^^;;

 

소스의 내용은 길지 않기 때문에 이해가 빠르실겁니다.

크기 조절과 회전 시 현재 클릭 점 위치를 기준으로 변경하여야 하기 때문에 마지막 부분에 드래그를 해주었습니다.

 

< Drag > 

   121 private void Drag(Point point)

  122 {

  123     if (!IsDragging)

  124     {

  125         // 윈도우상의 처음 좌표값의 역변환

  126         FirstCoordinate = Element.TransformToVisual(Window).Inverse.Transform(FirstPoint);

  127         IsDragging = true;

  128     }

  129 

  130     // 객체를 기준으로 역변환 값을 윈도우상의 좌표값으로 변환합니다.

  131     Point Translate = Element.TranslatePoint(FirstCoordinate, Window);

  132 

  133     // 현재 좌표값과의 차이

  134     Point Difference = new Point(point.X - Translate.X, point.Y - Translate.Y);

  135 

  136     // 좌표를 변경합니다.

  137     TranslateTrans.X += Difference.X;

  138     TranslateTrans.Y += Difference.Y;

  139 

  140     Element.RenderTransform = TransGroup;

  141 }

 

< Scale &  Rotate  >

    61 private void TransformationeEvent(object sender, MouseEventArgs e)

   62 {

   63     if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)

   64     {

   65         Point CurrentPoint = e.GetPosition(Window);

   66         Point DistanceVector = new Point((CurrentPoint.X - FirstPoint.X), (FirstPoint.Y - CurrentPoint.Y));

   67 

   68         double CurrentLength = Math.Sqrt(DistanceVector.X * DistanceVector.X

   69                                                   + DistanceVector.Y * DistanceVector.Y);

   70         double CurrentAngle = Math.Atan2(DistanceVector.Y, DistanceVector.X) * 180 / Math.PI;

   71 

   72         // 포인터 위치 표시

   73         if (ShowPosition)

   74         {

   75             ChangePosition(SecondPosition, CurrentPoint);

   76         }

   77 

   78         // 크기 변경

   79         if (CanBeScaled)

   80         {

   81             if (!IsScaling)

   82             {

   83                 // 처음 비율

   84                 FirstLength = CurrentLength / ScaleTrans.ScaleX;

   85                 IsScaling = true;

   86             }

   87 

   88             if (FirstLength > 0)

   89             {

   90                 // 현재 비율

   91                 double Scale = CurrentLength / FirstLength;

   92                 ScaleTrans.ScaleX = Scale;

   93                 ScaleTrans.ScaleY = Scale;

   94             }

   95         }

   96 

   97         // 회전

   98         if (CanBeRotated)

   99         {

  100             if (!IsRotating)

  101             {

  102                 // 처음 각도

  103                 FirstAngle = CurrentAngle + RotateTrans.Angle;

  104                 IsRotating = true;

  105             }

  106 

  107             // 현재 각도

  108             double AngleDiff = (FirstAngle - CurrentAngle + 360) % 360;

  109             RotateTrans.Angle = AngleDiff;

  110         }

  111 

  112         Drag(FirstPoint);

  113     }

  114 }

 

사용은 다음과 같이 하시면 됩니다.

Transform의 첫 인자는 변경 시킬 객체, 두 번째 인자는 해당 윈도우입니다.

CanBeDragged : 드래그 여부

CanBeScaled : 크기 조절 여부

CanBeRotated : 회전 여부

ShowPosition : 클릭 점을 표시 할지 여부

 

    38 transform = new Transform(grid, this);

   39 transform.CanBeDragged = true;

   40 transform.CanBeScaled = true;

   41 transform.CanBeRotated = true;

   42 transform.ShowPosition = true;

 

전체 소스코드는 첨부파일을 받으시길 바랍니다.

※ 프로토타입 형식으로 좀 더 유연하게 코드를 수정할 필요가 있습니다.

 

조작방법

드래그 : 왼쪽 or 오른쪽 버튼 클릭 후 이동

크기 조절 / 회전 : 왼쪽과 오른쪽 버튼을 누른 후

                         왼쪽 or 오른쪽 버튼 클릭 후 이동

                         왼쪽과 오른쪽 버튼을 한번 더 누르면 해제

 

마우스가 객체나 윈도우 창을 벗어나면 모두 해제 됩니다.

 

< 시연 영상 >
화면이 끊기네요 ㅡㅡ;;


'Window > WPF' 카테고리의 다른 글

[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] Object Capture  (0) 2010.01.29
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Image Pixel  (0) 2010.01.24
[ WPF ] Drag  (0) 2009.09.27
Posted by 열ㅇl
Window/WPF2009. 9. 27. 20:41

프로그램 작성 중 Drag 기능을 사용해야 할 때가 있습니다.

일반적으로 Window는 DragMove라는 함수를 호출하여 사용할 수 있지만

나머지는 구현을 하여야 하는 일이 생깁니다.

 

TranslateTransformDependencyProperty   이용한 간단한 예제를 만들어 보았습니다.

 

TranslateTransform은 RenderTransform의 현재 오프셋을 변경시킬 수가 있습니다.

 

DependencyProperty (의존 속성)클래스 를 이용하면 여러 객체에 대해 기능을 부여 할 수 있습니다.

의존 속성의 값을 변경하면 자동적으로 객체를 변경 시킬 수가 있습니다..

 

선언은 다음과 같습니다.

    15 private static readonly DependencyProperty DragProperty =

   16     DependencyProperty.RegisterAttached("Drag",

   17     typeof(bool),

   18     typeof(Drag),

   19     new UIPropertyMetadata(false, ChangeDragProperty));

 

4개의 파라미터는 다음과 같습니다.

 Name  등록 속성의 이름
 Property type  속성 타입
 Owner type  부모 타입
 Type metadata  메타데이터 지정

 

UIPropertyMetadata

코어 수준에서 렌더링/사용자 인터페이스에 영향을 주는 프레임워크가 아닌 속성에 대해 속성 메타데이터를 제공합니다.

 defaultValue  속성의 기본값, 일반적으로 특정 형식의 값으로 제공.
 propertyChangedCallback  속성의 유효 값이 변경될 때마다 호출되는 함수

 

[ 함수 내용 ]

 

- 프로퍼티 값 변경 시 이벤트 설정을 변경합니다.

   39 private static void ChangeDragProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)

   40 {

   41     FrameworkElement element = d as FrameworkElement;

   42 

   43     if (element != null)

   44     {

   45         if ((bool)e.NewValue)

   46         {

   47             // 오프셋 변경을 위해 생성합니다.

   48             element.RenderTransform = new TranslateTransform(0, 0);

   49 

   50             element.PreviewMouseDown += element_PreviewMouseDown;

   51             element.PreviewMouseUp += element_PreviewMouseUp;

   52         }

   53         else

   54         {

   55             element.PreviewMouseDown -= element_PreviewMouseDown;

   56             element.PreviewMouseUp -= element_PreviewMouseUp;

   57         }

   58     }

   59 }

 

 

- 드래그 시 객체를 놓치지 않기 위해 윈도우의 MouseMove를 사용했습니다.

  간단한 방법으로 객체 내의 처음 포인터 값과 현재 포인터 값의 차이만큼 오프셋을 변경합니다.

  ZIndex를 변경하여 선택한 객체를 상위로 올립니다.

   61 static void window_PreviewMouseMove(object sender, MouseEventArgs e)

   62 {

   63     if (CurrentElement != null &&

   64         e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)

   65     {

   66         Point CurrentPoint = e.GetPosition(CurrentElement);

   67 

   68         TranslateTransform Translate = CurrentElement.RenderTransform as TranslateTransform;

   69 

   70         if (Translate != null)

   71         {

   72             CurrentElement.LayoutTransform = Translate;

   73             Translate.X += CurrentPoint.X - FirstPoint.X;

   74             Translate.Y += CurrentPoint.Y - FirstPoint.Y;

   75         }

   76     }         

   77 }

   78 

   79 static void element_PreviewMouseDown(object sender, MouseButtonEventArgs e)

   80 {

   81     CurrentElement = sender as FrameworkElement;

   82 

   83     OldzIndex = Canvas.GetZIndex(CurrentElement);

   84     Canvas.SetZIndex(CurrentElement, 100);

   85 

   86     FirstPoint = e.GetPosition(CurrentElement);

   87 

   88     window.PreviewMouseMove += window_PreviewMouseMove;

   89 }

   90 

   91 private static void element_PreviewMouseUp(object sender, MouseButtonEventArgs e)

   92 {

   93     FrameworkElement element = sender as FrameworkElement;

   94 

   95     Canvas.SetZIndex(element, OldzIndex);

   96 

   97     CurrentElement = window;

   98     window.MouseMove -= window_PreviewMouseMove;

   99 }

 

 

- 다음과 같이 사용하면 됩니다.

   Drag.SetWindow(this);

    

  Drag.SetDrag(sample_btn, true);

  Drag.SetDrag(sample_image1, true);

  Drag.SetDrag(sample_image2, true);

  Drag.SetDrag(sample_text, true);

  Drag.SetDrag(title, true);

 

 

[ 시연 영상 ]

 

 

 

'Window > WPF' 카테고리의 다른 글

[ WPF ] Window 사이즈 변경 시 컨트롤 크기 변경하기  (3) 2010.02.08
[WPF] Object Capture  (0) 2010.01.29
[WPF] 시계 만들기  (0) 2010.01.26
[WPF] Image Pixel  (0) 2010.01.24
[WPF] Drag, Scale, Rotate  (1) 2010.01.24
Posted by 열ㅇl