안녕하세요? 맨날맑음 입니다.

이번 포스팅은 WPF에서 마우스 드래그를 이용한 간단한 사각형 그리기입니다. 이 예제를 응용하면 원이나 선도 그릴 수 있고, 자료구조를 이용하면 윈도우 그림판과 같은 기능도 쉽게 만들 수 있습니다.

-Fig1. 사각형을 그리는 WPF 어플리케이션-

Fig1에서 보는 바와 같이 마우스의 현재 좌표를 왼쪽 상단에 표시해 주며, 드래그를 이용하여 사각형을 그리는 기능을 합니다. WPF에서 제공하는 InkCanvas객체를 이용하면 더 간단하게 구현도 가능 하겠네요^^; 하지만 이번에는 Grid에 사각형을 그리는 방법으로 구현해 보겠습니다.

 

 

#1. 마우스 이벤트

-Fig2. WPF Window의 마우스 이벤트-

WPF의 컨트롤은 마우스 이벤트를 가지고 있습니다. 마우스 다운이나 업, 마우스 무브, 마우스 휠 등 이벤트를 지원하는데요. 우리 예제에서는 MouseLeftButtonDown과 MouseMove, MouseLeftButtonUp 세 가지 이벤트를 사용합니다. 마우스 이벤트 핸들러에서는 MouseEventArgs 객체가 인자로 넘어오고 이 이벤트객체를 이용하면 현재 마우스의 상태정보를 알 수 있습니다.

 

이름

설명

Device

이 이벤트를 시작한 입력 장치를 가져옵니다. (InputEventArgs에서 상속됨)

Handled

라우트된 이벤트가 경로를 따라 이동할 때의 현재 이벤트 처리 상태를 나타내는 값을 가져오거나 설정합니다.

LeftButton

마우스 왼쪽 단추의 현재 상태를 가져옵니다.

MiddleButton

마우스 가운데 단추의 현재 상태를 가져옵니다.

MouseDevice

이 이벤트와 연결된 마우스 장치를 가져옵니다.

OriginalSource

부모 클래스에서 Source를 조정하기 전에 순수 적중 테스트에 의해 결정되는 원본 보고 소스를 가져옵니다.

RightButton

마우스 오른쪽 단추의 현재 상태를 가져옵니다.

RoutedEvent

RoutedEventArgs 인스턴스와 연결된 RoutedEvent를 가져오거나 설정합니다. (RoutedEventArgs에서 상속됨)

Source

이벤트를 발생시킨 개체에 대한 참조를 가져오거나 설정합니다. (RoutedEventArgs에서 상속됨)

StylusDevice

이 이벤트와 연결된 스타일러스 장치를 가져옵니다.

Timestamp

이 이벤트가 발생한 시간을 가져옵니다. (InputEventArgs에서 상속됨)

XButton1

첫 번째로 확장된 마우스 단추의 현재 상태를 가져옵니다.

XButton2

두 번째로 확장된 마우스 단추의 현재 상태를 가져옵니다.

- MouseEventArgs 의 속성 (출처 : MSDN)-

이벤트 객체의 속성을 통해 마우스의 현재 상태정보를 알 수 있으며, GetPosition() 메서드를 이용하면 마우스 포인트의 좌표를 얻어 올 수도 있습니다.

 

#2. Shape객체

WPF에서 Rectangle, Ellipse, Polygon과 같은 모든 도형의 기본 클래스는 Shape입니다. Shape는 UI 요소이므로 패널이나 대부분의 컨트롤에서 사용 할 수 있습니다. Stroke 속성을 사용하면 도형의 테두리(윤곽선)의 색상을 지정 할 수 있고, StrokeThickness 속성을 이용하면 도형의 테두리 두께를 설정 할 수 있습니다. 또한 Fill 속성을 이용하면 도형의 표면 색상을 설정 할 수 있습니다.

 

-Fig3. 여러 속성을 적용하여 랜더링 된 원의 모습-

 

#3. 코드 구현

코드가 간단하여, 대부분의 설명은 주석으로 코드설명을 대신합니다. WPF 프로젝트를 생성하고, 다음과 같은 코드를 넣어 줍니다.

 

    

-Code1. MainWindow.xaml-

 

 
public partial class MainWindow : Window
 {
     /// 
     /// 드레그를 시작한 마우스 좌표;
     /// 
     Point prePosition;
     /// 
     /// 현재 그려지는 사각형
     /// 
     Rectangle currentRect;

     public MainWindow()
     {
         InitializeComponent();
         //이벤트 핸들러 생성
         this.root.MouseLeftButtonDown += new MouseButtonEventHandler(root_MouseLeftButtonDown);
         this.root.MouseMove += new MouseEventHandler(root_MouseMove);
         this.root.MouseLeftButtonUp += new MouseButtonEventHandler(root_MouseLeftButtonUp);
         
         // 좌표를 나타내는 TextBlock을 최상위로 ...
         Grid.SetZIndex(this.tbPosition, 99999);
     }

     /// 
     /// 마우스 클릭 해제 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
     {
         //마우스 캡춰를 제거한다.
         this.root.ReleaseMouseCapture();
         SetRectangleProperty();
         currentRect = null;
     }

     private void SetRectangleProperty()
     {
         //사각형의 투명도를 100% 로 설정
         currentRect.Opacity = 1;
         //사각형의 색상을 지정
         currentRect.Fill = new SolidColorBrush(Colors.LightYellow);
         //사각형의 테두리를 선으로 지정
         currentRect.StrokeDashArray = new DoubleCollection(); ;
     }

     /// 
     /// 마우스 이동 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseMove(object sender, MouseEventArgs e)
     {
         
         //현재 이동한 마우스의 좌표를 얻어온다
         Point currnetPosition = e.GetPosition(this.root);
         //좌표를 표시한다.
         this.tbPosition.Text = string.Format("마우스 좌표 : [{0},{1}]", currnetPosition.X, currnetPosition.Y);
         //마우스 왼쪽 버튼이 눌려있으면
         if (e.MouseDevice.LeftButton == MouseButtonState.Pressed)
         {
             if (currentRect != null)
             {
                 //사각형이 나타날 기준점을 설정한다.
                 double left = prePosition.X;
                 double top = prePosition.Y;
                 //마우스의 위치에 따라 적절히 기준점을 변경한다.
                 if (prePosition.X > currnetPosition.X)
                 {
                     left = currnetPosition.X;
                 }
                 if (prePosition.Y > currnetPosition.Y)
                 {
                     top = currnetPosition.Y;
                 }
                 //사각형의 위치 기준점(Margin)을 설정한다
                 currentRect.Margin = new Thickness(left, top, 0, 0);
                 //사각형의 크기를 설정한다. 음수가 나올 수 없으므로 절대값을 취해준다.
                 currentRect.Width = Math.Abs(prePosition.X - currnetPosition.X);
                 currentRect.Height = Math.Abs(prePosition.Y - currnetPosition.Y);
             }
         }
     }

     /// 
     /// 마우스 왼쪽 버튼 클릭 이벤트 핸들러
     /// 
     /// 
     /// 
     void root_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
     {
         //마우스의 좌표를 저장한다.
         prePosition = e.GetPosition(this.root);
         //마우스가 Grid밖으로 나가도 위치를 알 수 있도록 마우스 이벤트를 캡처한다.
         this.root.CaptureMouse();
         if (currentRect == null)
         {
             //사각형을 생성한다.
             CreteRectangle();               
         }
     }

     private void CreteRectangle()
     {
         
         currentRect = new Rectangle();
         currentRect.Stroke = new SolidColorBrush(Colors.DarkGreen);
         currentRect.StrokeThickness = 2;
         currentRect.Opacity = 0.7;
         //사각형을 그리는 동안은 테두리를 Dash 스타일로 설정한다.
         DoubleCollection dashSize = new DoubleCollection();
         dashSize.Add(1);
         dashSize.Add(1);
         currentRect.StrokeDashArray = dashSize;
         currentRect.StrokeDashOffset = 0;
         //사각형의 정렬 기준을 설정한다.
         currentRect.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
         currentRect.VerticalAlignment = System.Windows.VerticalAlignment.Top;
         //그리드에 추가한다.
         this.root.Children.Add(currentRect);
     }
 }

-Code2. MainWindow.xaml.cs-

마우스를 드래그하는 동안은 그림판이나 포토샵에서와 같이 점선으로 사각형의 모양을 표시 해 줄 필요가 있기 때문에 테두리의 속성을 변경 할 필요가 있습니다. 테두리를 점선으로 표시하는 속성은 Rectangle객체의 StrokeDashArray를 사용하여 설정 할 수 있으며, XAML에서는 다음과 같이 표현 할 수 있습니다.

 

-Fig4. StrokeDashArray 속성이 적용 된 Ellipse-

소스 빌드 환경 : VisualStudio2010, .NET Framework4.0

Posted by 맨날맑음

안녕하세요? 맨날맑음 입니다.

Windows Form Application에서 WPF로 만든 Windows Application을 호출하려 합니다.

WPF의 Control을 윈폼에 호스팅 하기 위해서는 ElementHost를 사용하면 되는데요(이에 관한 강좌는 추후에 포스팅 하겠습니다.)
오늘은 윈폼에서 WPF의 창(Window)를 띄우려고 합니다.

#1. 프로젝트 생성

우선 Windows Forms 응용프로그램 프로젝트와 WPF 사용자 정의 컨트롤 라이브러리 프로젝트 2개를 생성합니다.

 

#2. DLL 참조

윈폼에서 WPF 윈도우를 호출하기 위해 WPF 프로젝트의 DLL(wpfControlLibrary1)과 윈폼에서 WPF 사용을 위한 DLL을 참조 합니다.

Windows Form에서 WPF를 사용하기 위한 DLL 목록
  PresentationCore
  PresentationFramework
  System.Xaml
  WindowsBase


#3. WPF 윈도우 호출
이제 Windows Form의 소스코드에 WPF 윈도우 호출 코드를 넣습니다.(저는 간단히 버튼을 누를 때 WPF 창이 나오도록 하겠습니다)

private void button1_Click(object sender, EventArgs e)

 {

     Window1 WPF_Wnd = new Window1();

     WPF_Wnd.Show();

 }

#4. 결과 확인 

간단한 방법으로 Windows Form에서 WPF 윈도우를 호출 할 수 있습니다. 감사합니다.

Posted by 맨날맑음

안녕하세요? 맨날맑음 입니다.

 

이번에 만들어 볼 내용은 Microsoft Office Object를 이용한 간단한 PPT Viewer를 만드는 것입니다.

제가 2010년 HOONS.NET WPF 시삽으로 활동하게 되면서 어플리케이션은 WPF로 만들어 보겠습니다.

이 방법의 대략적인 과정을 살펴보면 다음과 같습니다.

 

1. Microsoft Office 12.0 Object Library를 참조한다.(Office 2007 버전에 경우 12.0)

2. ApplicationClass 객체를 이용하여 PPT 파일을 읽어온다.

3. Presentation 객체를 이용하여 슬라이드를 그림 파일로 하드에 저장한다.

4. 그림 파일을 로딩하여 마치 PTT Viewer인척(?) 한다.

 

전체적인 과정에서 보듯이 PPT파일을 읽어드려 하드에 그림파일로 저장한 것을 띄우는 방식이기 때문에 PPT에 들어있는 애니메이션 효과를 기대하기는 어렵습니다. 그래서 PTT Viewer인척(?)이라고 한 것 이구요.

 

#1. 관련 어셈블리 참조하기


우선 PPT Viewer를 구현하기 위해 두가지 객체가 필요합니다.

 

COM으로 이루어진 Microsoft Office 12.0 Object Library에 포함된 ApplicationClass 객체가 필요하구요. .NET 어셈블리중 Microsoft.Office.Interop.PowerPoint 12.0에 포함된 Presentation 객체가 필요합니다. 두가지 어셈블리를 참조하고 using도 추가해 줍니다.

 

using Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;

 

- Fig1. 관련 어셈블리 참조 -

 

 

#2. 소스 구현

string Path;

Presentation PPT;


private
void ReadPPTfile()

{

    ApplicationClass app = new ApplicationClass();

    PPT = app.Presentations.Open(Path, MsoTriState.msoTrue, MsoTriState.msoFalse, MsoTriState.msoFalse);

    app.Quit();

}      

 

private void MakePPTIamge()

{

    string myPicturesPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);

    for (int i = 0; i < PPT.Slides.Count; ++i)

    {               

        PPT.Slides[i + 1].Export(string.Format("{0}\\temp{1}.jpg", myPicturesPath, i), "JPG",

            (int)PPT.Slides[i + 1].Master.Width, (int)PPT.Slides[i + 1].Master.Height);               

    }

}

 

소스는 간단합니다. ReadPPTfile()에서 ApplicationClass 객체를 이용하여 ppt 파일을 Open하고 Presentation 객체를 return 받아 놓습니다. MakePPTIamge()에서 PPT.Slides.Export() 메서드를 호출하여 적당한 경로에 jpg 파일(다른 포맷도 지정 가능)로 저장하는 방법입니다! PPT.Slides.Count를 이용하여 읽어들인 슬라이드 갯수도 알 수 있습니다.

이제 동작에 따라 적당한 그림파일을 로딩하여 사용하면 초간단 PPT Viewer 완성입니다^^;


#3. 마치면서..

요방법의 단점을 좀 생각해 보면. 앞서 이야기한 애니메이션 효과는 사용 할 수 없다는 것과.. 많은양의 슬라이드를 로딩할 경우 오래 걸린다는 단점이 있습니다. 하지만 간단한 방법으로 구현 할 수 있고, 웹으로 뷰어를 제공 할 경우 더 어울리는 방법 일 것 같네요.

Posted by 맨날맑음

요즘 Widget(gadget)의 사용이 점점 늘고있다!

Widget은 사용자의 컴퓨터 바탕 화면에 놓거나 웹 페이지 위에 호스트할 수 있는
가벼운 단일 목적의 응용 프로그램이다.

WPF를 이용하면 Windows Vista의 사이드바에 놓이는 Widget과 같이 투명한 윈도우창을
구현하여 Widget과 같은 효과를 줄수있다!

여기서 보이는 예제는 간단한 예제이지만 이 응용프로그램에 Web Service나 요즘 한창
이슈가 되어있는 Open API를 이용하여 Mash up 서비스를 구현한다면 우리 입맛에 맞는
멋진 Widget을 만드는것도 어려운 일이 아니다!

Posted by 맨날맑음
TAG Widget, WPF