Silverlight를 설치하려면 여기를 클릭합니다.*
Korea 대한민국변경|Microsoft 전체 사이트
MSDN
|개발자 센터
MSDN Home   MSDN Home
MSDN 홈 > MSDN Magazine > 2001년 기사 > Windows Forms: GUI 응용 프로그램 작성을 위한 최신 프로그래밍 모델

Windows Forms: GUI 응용 프로그램 작성을 위한 최신 프로그래밍 모델

Jeff Prosise
이 문서는 독자가 Visual Basic과 C#을 잘 알고 있다는 전제 하에 작성되었습니다.
요약? Microsoft .NET용 GUI 응용 프로그램을 작성하려면 Windows Forms를 사용합니다. Windows Forms는 .NET Framework 클래스 라이브러리의 System.WinForms 이름 공간에 있는 클래스 주변에서 작성되는 새로운 스타일의 응용 프로그램입니다. Win32 API 또는 MFC에 기초하는 모델보다 명확하고 견고한 고유 프로그래밍 모델을 가진 Windows Forms는 .NET CLR(Common Language Runtime)의 관리 환경에서 실행됩니다. 이 문서에서는 프로그래밍 모델에서 Microsoft Intermediate Language 및 JIT 컴파일러에 이르기까지 Windows Forms란 무엇인지 자세히 설명합니다. 폼, 이벤트 처리기, 앵커 및 지속성을 사용하는 응용 프로그램 두 개가 단계별로 작성됩니다.
가까운 미래에는 Microsoft® .NET이 광범위하게 사용될 것입니다. Windows®의 최상위 단계를 차지하는 플랫폼인 Microsoft .NET은 Windows 기반 소프트웨어를 작성하는 것에 대한 기존 방식을 변화시키는 완전히 새로운 프로그래밍 패러다임입니다. 또한 기존에 의존해 왔던 Windows API, MFC, ATL 및 기타 도구를 .NET Framework 클래스 라이브러리라는 클래스 집합에 포함된 새 API로 대체시키는 획기적인 방식입니다. 더욱 통합된 프로그래밍 모델, 향상된 보안 및 풍부하고 완벽한 기능의 웹 응용 프로그램을 더 쉽게 작성할 수 있는 방법 등은 Microsoft .NET이 제공하는 다양한 기능의 일부에 불과합니다.

Microsoft .NET의 다양한 기능 중 가장 흥미로운 것이 바로 Windows Forms입니다. Windows Forms에서는 창을 만들거나, 사용자 입력을 처리하는 등의 일반 GUI 응용 프로그램을 작성할 수 있기 때문에 MFC 또는 Windows API에 익숙한 사용자가 .NET Framework 클래스 라이브러리를 시작할 수 있는 가장 적합한 방법입니다. 일단 Windows Forms를 배워두면 .NET Framework의 다른 부분도 쉽게 이해할 수 있습니다.

Windows Forms 방식의 Windows 기반 응용 프로그램을 작성하면 프로그래밍 모델을 균일화하고 Windows API를 괴롭히는 버그, 변동 및 불일치를 제거한다는 Windows Forms의 주요 이점을 활용할 수 있습니다. 예를 들어, 숙련된 모든 Windows 기반 프로그래머는 창을 만들 때만 특정 창 스타일을 적용할 수 있었습니다. 그러나 Windows Forms에서는 만들 때만 의미가 있는 스타일이 기존 창에 적용되면 해당 창이 즉시 소멸되고 지정된 스타일의 창이 다시 만들어집니다. 또한 .NET Framework 클래스 라이브러리는 Windows API보다 기능이 풍부하기 때문에 Windows Forms로 응용 프로그램을 작성할 때 프레임워크를 원하는 대로 사용할 수 있습니다. 일반적으로 Windows Forms를 사용하여 작성한 응용 프로그램에는 Windows API 또는 MFC를 사용하는 응용 프로그램보다 더 적은 코드가 필요합니다.

Windows Forms의 또 다른 이점은 선택한 프로그래밍 언어에 상관 없이 같은 API를 사용한다는 점입니다. 과거에는 프로그래밍 언어에 의해 API가 결정되었기 때문에 Visual Basic® 프로그래머는 Visual Basic 언어에 포함된 단일 API를, C 프로그래머는 Win32® API를, C++ 프로그래머는 대부분 MFC를 사용했습니다. 그러나 Windows Forms를 사용하는 모든 응응 프로그램은 이제 .NET Framework 클래스 라이브러리의 단일 API로 작성됩니다. 즉, 프로그래머는 선택한 언어에 상관 없이 단일 API에 대한 지식만으로 응용 프로그램을 작성할 수 있습니다.

Windows Forms는 GUI 응용 프로그램을 위한 최신 프로그래밍 모델입니다. Windows 1.0로 거슬러 올라가는 Win32 프로그래밍 모델과 달리 Windows Forms는 그 동안의 시행착오를 고려하여 디자인되었습니다.
이 문서의 목적은 Windows Forms 프로그래밍 모델을 소개하는 것입니다. 코드 샘플을 컴파일 및 실행하려면 컴퓨터에 Microsoft .NET Framework SDK를 설치해야 합니다.

맨 위로


Windows Forms 프로그래밍 모델

Windows Forms에서 "폼"이라는 용어는 최상위 창과 동의어입니다. 응용 프로그램의 주 창을 비롯한 모든 최상위 창뿐 아니라 대화 상자도 폼으로 간주합니다. 그러나 이러한 이름에도 불구하고 Windows Forms을 사용하는 응용 프로그램이 폼과 같은 모양일 필요는 없습니다. 일반 Windows 기반 응용 프로그램과 마찬가지로 창에 표시되는 모든 항목이 응용 프로그램에 의해 완전하게 제어됩니다.

프로그래머는 .NET Framework 클래스 라이브러리를 통해 Microsoft .NET을 확인합니다. MFC보다 10배 정도 크다고 생각하면 .NET Framework 클래스 라이브러리의 너비 및 깊이를 정확하게 파악할 수 있습니다. 이름 충돌을 완화하고 수백 개의 클래스를 구성하기 위해 .NET Framework 클래스 라이브러리는 계층 이름 공간으로 분할됩니다. 루트 이름 공간인 시스템은 모든 .NET 응용 프로그램이 사용하는 기본 데이터 형식을 정의합니다.

Windows Forms를 사용하는 응용 프로그램은 System.WinForms 이름 공간에서 발견된 클래스에 전적으로 의존합니다. 이 이름 공간에는 창이나 폼의 동작을 모델링하는 Form, 메뉴를 나타내는 Menu, Windows Forms 응용 프로그램이 클립보드를 액세스할 수 있게 하는 Clipboard와 같은 클래스가 포함됩니다. 또한 Button, TextBox, ListView 및 MonthCalendar와 같은 이름을 가진 컨트롤을 나타내는 수많은 클래스가 포함되어 있습니다. 해당 클래스 이름만 사용하거나 System.WinForms.Button과 같이 정식 이름을 사용하여 이러한 클래스를 참조할 수 있습니다.

거의 모든 Windows Forms 기반 응용 프로그램의 핵심은 System.WinForms.Form에서 파생된 클래스입니다. 이 클래스의 인스턴스는 응용 프로그램의 주 창을 나타냅니다. System.WinForms.Form은 폼에 대한 풍부한 프로그램적 인터페이스로 구성되는 다수의 속성 및 메서드를 가집니다. 폼의 클라이언트 영역 크기의 경우 Windows에서는 GetClientRect API 함수를 호출했지만 Windows Forms에서는 폼의 ClientRectangle 또는 ClientSize 속성을 읽습니다. 대부분의 속성은 읽기/쓰기가 가능합니다. 예를 들어, BorderStyle 속성에 기록하여 폼의 테두리 스타일을 변경하거나 Size 또는 ClientSize 속성을 사용하여 폼 크기를 조정할 수 있습니다.

누름 단추, 목록 상자 및 다른 Windows 컨트롤 유형을 사용하는 Windows Forms 기반 응용 프로그램은 System.WinForms의 컨트롤 클래스에 의존합니다. 컨트롤 프로그래밍을 크게 단순화하기 때문에 사용자는 이러한 클래스를 선호하게 됩니다. 예를 들어, 비트맵 배경이 있는 스타일이 지정된 단추를 만들려는 경우 System.Drawing.Bitmap 개체의 이미지를 배치하여 단추의 BackgroundImage 속성에 지정할 수 있습니다. 또한 편집 컨트롤의 배경색을 사용자 지정하는 경우처럼 컨트롤 색을 고려해야 할 경우도 있습니다. 이는 많은 개발자가 저자에게 전자 메일로 문의하는 사항 중 하나로서 Windows Forms를 사용하면 쉽게 해결할 수 있습니다. 즉, BackColor라는 속성에 색을 기록하면 나머지는 프레임워크가 알아서 처리합니다.

Windows Forms를 사용하는 응용 프로그램의 또 다른 주요 구성 요소는 Application이라는 System.WinForms 클래스입니다. 이 클래스에는 창을 표시하고 메시지 루프를 제공하여 Windows Forms 기반 응용 프로그램을 시작 및 실행하는 Run이라는 정적 메서드가 포함되어 있습니다. 물론 메시지 루프는 볼 수 없습니다. 메시지는 .NET 환경에서 추상적이지만 분명 존재하며 플랫폼이 세부 정보를 제공하므로 그 내용에 대해 염려할 필요는 없습니다.

그러나 여기서 잠깐 메시지를 처리하지 않는 Windows Forms인 응용 프로그램이 사용자 입력에 응답하거나 채색 시기를 알 수 있는 방법이 무엇인지 고려해야 합니다. 대부분의 클래스에는 초보자가 채색 메시지, 마우스 메시지 등에 대한 응답을 무시할 수 있는 가상 메서드가 포함되어 있습니다. 예를 들어, System.WinForms.Form에는 폼의 클라이언트 영역에 업데이트가 필요할 때 호출되는 OnPaint라는 가상 메서드가 들어 있습니다. OnMouseDown, OnKeyDown 및 OnClosing과 마찬가지로 OnPaint는 파생된 클래스에서 무시하여 대화형 폼을 작성할 수 있는 여러 가상 메서드 중 하나입니다. 다른 것이 모두 실패할 경우 Windows Forms는 폼의 내부 창 프로시저에 요청하여 Windows 메시지에 응답하기 위한 메커니즘을 제공합니다.

이 외에도 Windows Forms 프로그래밍 모델이 메뉴, 컨트롤 및 다른 GUI 응용 프로그램 요소의 입력에 응답하기 위해 폼이 사용하는 메커니즘이라는 점이 중요합니다. 일반 Windows 기반 응용 프로그램은 Windows Forms 프로세스 이벤트를 사용하여 WM_COMMAND 및 WM_NOTIFY 메시지를 처리합니다. C#이나 .NET CLR(Common Language Runtime)을 지원하는 다른 언어에서 이벤트는 메서드, 필드 및 속성과 동일한 최우선 유형의 구성원입니다. 실제로 모든 Windows Forms 컨트롤 클래스뿐 아니라 컨트롤 클래스가 아닌 많은 클래스가 이벤트를 실행합니다. 예를 들어, System.WinForms.Button의 인스턴스인 단추 컨트롤은 사용자가 클릭했을 때 Click 이벤트를 실행합니다. 단추 클릭에 응답하고자 하는 폼에는 다음 구문을 사용하여 단추와 클릭 처리기를 연관시킬 수 있습니다.

MyButton.Click += new EventHandler (OnButtonClicked);

  ???

private void OnButtonClicked (object sender, EventArgs e)
{
    MessageBox.Show ("Click!");
}
EventHandler는 System 이름 공간에 정의되어 있고 CLR에서 보안 함수 포인터에 해당하는 대리인입니다. 이 예제에서는 EventHandler를 OnButtonClicked 메서드 주위에 배치하고 MyButton이 Click 이벤트를 실행했을 때 호출되는 이벤트 처리기 목록에 추가합니다. OnButtonClick의 첫째 매개 변수는 이벤트를 실행한 개체를 식별합니다. 둘째 매개 변수는 기본적으로 Click 이벤트에 대해 무의미하지만 이벤트에 대한 추가 정보를 전달하기 위해 다른 이벤트에 의해 사용됩니다.

맨 위로


Windows Forms를 사용하는 Hello World

프로그래머로서 새 플랫폼을 배우기 시작할 때 Hello World만큼 좋은 응용 프로그램은 없습니다. 특히 닷컴 신규 업체를 비롯한 대부분의 회사는 Hello World 응용 프로그램에 기초하여 구축됩니다. 그림?1에는 Hello World 응용 프로그램의 Windows Forms 버전이 포함되어 있습니다. 이 문서의 모든 샘플은 C#로 작성되어 있지만 .NET 컴파일러를 사용할 수 있는 모든 언어로 Windows Forms 응용 프로그램을 작성할 수 있습니다. 현재 프로그래머는 C#, Visual Basic, JScript®, managed C++ 등의 언어를 선택할 수 있습니다.

우선 파일 맨 위에 using 문을 사용하면 클래스 이름만 사용하여 System, System.WinForms 및 System.Drawing 이름 공간의 클래스를 참조할 수 있다는 점에 주의합니다. 예를 들어, 다음과 같이 using 문을 사용할 수 있습니다.

using System.WinForms;
그러나 위의 명령문을 사용하지 않을 경우에는 다음과 같이 작성해야 합니다.
public class MyForm : System.WinForms.Form
즉, 다음과 같이 작성해서는 안됩니다.
public class MyForm : Form
Windows Forms를 사용하는 응용 프로그램에서 각 창 또는 폼은 System.WinForms.Form에서 파생된 클래스 인스턴스에 의해 나타납니다. 그림?1에서는 MyForm이 이러한 클래스에 해당합니다. MyForm의 생성자는 MyForm의 Text 속성에 기록하여 폼의 캡션 표시줄 텍스트를 "Windows Forms Demo"로 설정합니다. Text는 System.WinForms.Form에서 폼이 상속하는 100개 이상의 속성 중 하나입니다. 여기서는 Text만 사용했지만 나중에 이러한 속성에 대해 더 자세히 다룰 것입니다.

아시다시피 WM_PAINT 메시지는 창에 전달되고 대부분의 화면 렌더링은 이러한 메시지에 응답하여 수행됩니다. Windows Forms에서 WM_PAINT 메시지는 OnPaint라는 가상 메서드에 해당합니다. 파생된 폼 클래스는 WM_PAINT 메시지에서 응답하여 칠하기 작업을 수행하기 위해 이 메서드를 무시할 수 있습니다.

C# 컴파일러가 그림?1에 있는 무시 키워드를 해석할 때 사용자가 기본 클래스에서 상속된 가상 메서드를 무시하기로 확정했다고 간주한다는 점에 주의합니다. OnPaint 무시는 여기서 폼의 클라이언트 영역에 "Hello, world"를 기록합니다. OnPaint는 호출과 함께 Graphics 및 ClipRectangle이라는 속성이 포함된 PaintEventArgs(System.WinForms.PaintEventArgs) 개체로 전달됩니다. Graphics 속성은 Windows Forms에서 디바이스 컨텍스트에 해당하는 Graphics(System.Drawing.Graphics) 개체에 대한 참조를 보유합니다. ClipRectangle은 잘못된 폼 부분을 설명하는 Rectangle(System.Drawing.Rectangle)을 보유합니다.

MyForm의 OnPaint 메서드는 Graphics.DrawString을 사용하여 출력을 렌더링합니다. DrawString에 대한 첫째 매개 변수는 문자열 자체이고 둘째 매개 변수는 텍스트를 렌더링할 때 적용해야 할 글꼴을 설명하는 Font 개체(System.Drawing.Font)입니다. MyForm.OnPaint는 폼의 기본 글꼴 즉, Font라는 Form 속성에 저장되는 글꼴에 대한 참조를 사용합니다. 셋째 매개 변수는 텍스트 색을 지정하는 Brush(System.Drawing.Brush) 개체입니다. MyForm.OnPaint는 이 매개 변수에 대해 검정 SolidBrush(System.Drawing.SolidBrush) 개체를 만듭니다. 네 번째이자 마지막인 매개 변수는 텍스트가 놓여야 하는 위치를 설명하는 서식 직사각형입니다. MyForm.OnPaint는 ClientRectangle이라는 Form 속성에 있는 설명인 폼의 전체 클라이언트 영역을 서식 직사각형으로 사용합니다.

MyForm의 최종 구성원은 Main이라는 정적 메서드입니다. Main은 응용 프로그램의 진입점으로 모든 .NET 응용 프로그램은 Main 메서드를 가져야 합니다. Main은 다음 방법 중 하나로 선언될 수 있습니다.

public static void Main ()
public static int Main ()
public static void Main (string[] args)
public static int Main (string[] args)
Main으로 전달되는 args 매개 변수는 응용 프로그램의 명령줄 인수를 나타내는 문자열의 배열입니다. args[0]은 첫째 명령줄 매개 변수를, args[1]은 둘째 매개 변수를 보유하는 식으로 각각 해당 매개 변수를 보유합니다. 일반적으로 사용자가 진입점인 Main을 컴파일러에 알릴 경우 여러 Main 메서드를 정의할 수 있지만 대개 Main은 모든 응용 프로그램에서 한 번만 나타납니다. (Microsoft C# 컴파일러는 응용 프로그램의 진입점으로 사용되는 Main 메서드가 포함된 클래스를 지정하는 /main 스위치를 허용합니다. /main 스위치는 응용 프로그램 내의 여러 클래스가 Main 메서드를 포함할 경우에만 필요합니다.) Main은 응용 프로그램에 정의된 모든 클래스의 구성원이 될 수 있습니다.

MyForm의 인스턴스를 만들고 이에 대한 참조를 Application.Run에 전달하면 화면에 자신의 폼을 간단하게 표시할 수 있습니다. Application은 System.WinForms에 정의된 또 다른 클래스이며, Run은 폼을 만들어 화면에 표시하고 메시지 루프와 함께 서비스할 때 호출하는 메서드입니다. 그림?1에는 다음 명령문이 있습니다.

Application.Run (new MyForm ());
이 명령문은 MyForm의 인스턴스를 만들고 폼을 표시합니다.
그림?1의 코드를 입력하여 Hello.cs라는 파일에 저장했다면 이를 컴파일해야 합니다. 우선 명령 프롬프트 창을 열고 Hello.cs가 저장된 폴더로 이동한 후 다음을 입력합니다.

csc /target:winexe /out:Hello.exe /reference:System.dll
/reference:System.WinForms.dll /reference:System.Drawing.dll
/reference:Microsoft.Win32.Interop.dll Hello.cs
csc 명령은 Microsoft C# 컴파일러를 호출하고 Hello.cs는 컴파일할 파일을 식별합니다. /target:winexe 스위치는 콘솔 응용 프로그램이 아니라 GUI Windows 기반 응용 프로그램을 생성하도록 컴파일러에 지시하고 /out:Hello.exe는 결과로 만들어지는 실행 파일의 이름을 지정합니다. (CS 파일이 Hello.cs라고 명명되므로 실행 파일이 Hello.exe로 명명되도록 그대로 두려면 이 스위치를 생략할 수 있습니다.) /reference 스위치는 System.WinForms.Form 및 System.Drawing.Size와 같은 외부 유형이 정의되는 조합을 식별합니다. 구문을 단축하기 위해 /target 및 /reference를 /t 및 /r로 바꿀 수 있습니다. 그러나 Windows Forms 기반 응용 프로그램의 명령줄을 작성하기 위해서는 여전히 복잡한 csc 명령이 필요합니다.

Hello.exe는 보통의 Windows 기반 실행 파일이 아니라 다음과 같은 주요 요소가 포함된 .NET 실행 파일입니다.

  • C# 소스 코드에서 생성된 Microsoft Intermediate Language(MSIL)
  • 응용 프로그램에 정의된 유형(클래스) 및 응용 프로그램에서 참조하지만 다른 조합(예: MsCorLib.dll 및 System.WinForms.dll)에는 존재하지 않는 유형(예: System.WinForms.Form)을 설명하는 메타데이터

  • 응용 프로그램의 조합을 구성하는 파일을 설명하는 목록

.NET 언어에서 조합은 단위로 배포된 하나 이상의 파일을 모은 것입니다. 현재 사용자의 조합에는 파일이 하나만 포함되어 있고 실행 파일에 포함된 목록을 통해 이를 알 수 있습니다. 이 목록은 메타데이터의 일부로 물리적으로 저장되지만 여기서는 그 중요성을 강조하기 위해 별개로 엔티티로 다룹니다. 관리된 모든 실행 파일 즉, MSIL을 포함하는 모든 PE 파일은 조합의 일부이고 내부에 메타데이터를 갖고 있습니다. .NET 조합에 있는 파일 중 하나가 .NET 조합을 포함하는 파일, .NET 조합이 다른 조합에 대해 사용할 수 있게 하는 공용 데이터 형식 및 .NET 조합이 의존하는 다른 조합을 식별하는 목록을 포함합니다. C# 컴파일러는 사용자가 명시적으로 요청하지 않아도 이상의 필수 인프라를 모두 생성합니다. 조합, 목록 및 메타데이터와 .NET 응용 프로그램에 이들이 수행하는 역할에 대한 자세한 내용은 2000년 9월 및 10월 발행된 MSDN® Magazine의 .NET Framework에 대한 Jeffrey Richter의 문서에서 1부2부를 참조하십시오.

Hello.exe를 컴파일한 후에는 명령 프롬프트에서 다음을 입력하여 이 파일을 실행할 수 있습니다.
Hello
그림?2는 화면에 표시되는 실행 결과를 나타낸 것입니다.

그림 2 Hello.exe 실행
그림 2 Hello.exe 실행

맨 위로


ImageView 응용 프로그램

Hello World를 쉽게 시작할 수 있지만 본격으로 활용하기 위해서는 많은 노력을 기울여야 합니다. (그만큼 어렵기 때문에 앞에서 모든 회사가 Hello World 응용 프로그램에 기초하여 구축된다고 말한 것은 다소 과장이 있습니다.) 여기서는 Windows Forms를 사용하여 실제 응용 프로그램 즉, 열려 있는 PEG 파일, GIF 파일 및 다양한 형식의 이미지 파일을 처리할 수 있는 ImageView라는 비트맵 뷰어를 작성합니다. 현재 과도하게 존재하는 이미지 파일 형식을 간단하게 처리하기 위해 .NET Framework 클래스 라이브러리의 System.Drawing.Bitmap 클래스가 사용됩니다. Windows API 또는 MFC를 사용하여 동일한 응용 프로그램을 작성하려면 수백 줄의 코드가 필요할 것입니다. 그러나 Windows Forms를 사용하면 편리한 부가 기능이 포함된 응용 프로그램을 약 100줄로 작성할 수 있습니다.

맨 위로


1단계: 폼 만들기

그림?3의 Main.cs 파일에는 ImageView의 초기 버전이 포함되어 있습니다. 이 파일은 폼을 만들고 폼의 캡션 표시줄에 있는 텍스트를 "Image Viewer"로 설정하며 폼 크기를 조정하여 클라이언트 영역을 640 x 480 픽셀로 만듭니다. System.WinForms.Form에서 MyForm이 상속하는 ClientSize 속성에 Size 값(System.Drawing.Size)을 기록하여 크기 조정을 수행합니다.

컴파일을 수행하려면 Main.cs가 저장된 폴더로 이동하여 다음을 입력합니다.

  csc /target:winexe /out:ImageView.exe /reference:System.dll
  /reference:System.WinForms.dll /reference:System.Drawing.dll
  /reference:Microsoft.Win32.Interop.dll Main.cs
여기서 /out 스위치는 실행 파일이 Main.exe로 명명되는 것을 방지합니다. ImageView.exe가 컴파일되면 다음을 명령 프롬프트에 입력하여 실행합니다.

ImageView
결과로 만들어지는 창은 메뉴와 같은 GUI 응용 프로그램 요소가 없으므로 다소 단조로울 것입니다. 그러나 다음 연습에서 이 문제를 해결할 수 있습니다.


맨 위로


2단계: 옵션 메뉴 추가

이 단계에서는 응용 프로그램을 닫는 Exit 명령이 포함된 옵션 메뉴를 추가합니다. Windows Forms를 사용하는 응용 프로그램에서 최상위 메뉴(창의 제목 표시줄 밑에 나타나는 메뉴 표시줄)는 System.WinForms.MainMenu의 인스턴스입니다. System.WinForms.Form에서 폼이 상속하는 Menu 속성에 MainMenu를 지정하여 폼에 MainMenu를 첨부합니다. 메뉴에 있는 항목은 MenuItem(System.WinForms.MenuItem) 개체가 나타냅니다.

그림?4는 Main.cs에 필요한 수정이 무엇인지 보여 줍니다. 새 코드는 녹색으로 표시되어 있습니다.
MainMenu menu = new MainMenu ();
이 명령문은 MainMenu 개체를 만들고 이에 대한 참조를 메뉴라는 변수에 저장합니다.

MenuItem item = menu.MenuItems.Add ("&Options");
이 명령문은 &Options라는 메뉴 항목을 추가하고 이에 대한 참조를 항목이라는 변수에 저장합니다. MenuItems는 메뉴에 포함된 모든 메뉴 항목을 나타내는 컬렉션입니다. 따라서 이 컬렉션에서 Add를 호출하면 메뉴에 항목이 추가되고 MenuItem 개체가 반환됩니다.

item.MenuItems.Add (new MenuItem ("E&xit",
    new EventHandler (OnExit));
마지막으로 이 명령문은 옵션 메뉴에 Exit 명령을 추가하고 이를 OnExit라는 처리기에 연결합니다. 실행 시 MyForm이 상속을 통해 획득한 폼의 Close 메서드를 호출하는 OnExit는 폼을 닫고 결국 응용 프로그램을 종료합니다.

맨 위로


3단계: Open 명령 추가

그림?5의 수정된 Main.cs 버전은 옵션 메뉴에 Open 명령을 추가합니다. 옵션 메뉴의 MenuItems 컬렉션에서 Add를 호출하면 메뉴 항목을 간단히 추가할 수 있습니다. 여기서 메뉴 항목 텍스트로 "-"와 함께 기록된 Add에 대한 다른 호출은 가로 구분 기호를 추가합니다. 다음과 같이 셋째 매개 변수가 MenuItem의 생성자에 전달된다는 점에 주의합니다.

Shortcut.CtrlO
Shortcut은 System.WinForms에 정의된 열거이고 CtrlO는 키 조합인 Ctrl+O에 해당하는 열거의 한 요소입니다. 매개 변수 목록에 Shortcut.CtrlO를 포함하면 Open 명령의 바로 가기로 Ctrl+O가 정의되고 메뉴 항목 텍스트에 "CTRL+O"가 첨부됩니다.

이미지 파일을 여는 작업은 OnOpenImage로 이루어집니다. System.WinForms 이름 공간의 일부인 .NET Framework 클래스 라이브러리의 OpenFileDialog 클래스는 Windows Open File 대화 상자의 기능을 캡슐화하고 관리 코드에 의해 이 대화 상자를 사용할 수 있게 합니다. OnOpenImage는 OpenFileDialog 개체를 만들어 대화 상자의 "Files of type" 필드에 표시되어야 할 사항을 지정하는 필터 문자열로 초기화하고 OpenFileDialog.ShowDialog를 호출하여 대화 상자를 표시합니다. 사용자가 파일 이름을 입력하고 확인을 클릭하면 OnOpenImage는 OpenFileDialog의 FileName 속성에서 파일 이름을 읽어 추출한 후 다음 명령문으로 파일을 엽니다.

_MyBitmap = new Bitmap (fileName);
Bitmap은 System.Drawing.Bitmap을 줄여 쓴 것으로 비트맵을 캡슐화하고 거의 모든 형식의 이미지 파일을 파일 이름을 입력하여 열 수 있게 하는 강력한 클래스입니다. 물론 사용자가 이미지 파일이 아닌 파일을 선택할 수도 있기 때문에 이 명령문은 시험 블록에 포함됩니다. 사용자가 이미지 파일이 아닌 파일을 선택할 경우 Bitmap의 클래스 생성자는 캐치 처리기가 파악하는 예외를 알리고 OnOpenImage는 Show라는 정적 MessageBox 메서드를 호출하여 오류 메시지를 표시합니다. MessageBox(System.WinForms.MessageBox)는 메시지 상자를 배치하는 Framework 클래스입니다.

이미지 파일이 성공적으로 열린 경우 실행되는 Invalidate 호출에 주의합니다. Invalidate는 폼의 클라이언트 영역을 무효화하여 다시 칠하기를 자동으로 하는 System.WinForms.Form 메서드입니다. Windows API의 InvalidateRect 함수 및 MFC의 CWnd::InvalidateRect 함수와 마찬가지로 전체 폼 또는 폼의 일부를 무효화하는 데 Form.Invalidate를 사용할 수 있습니다. 여기서는 전체 클라이언트 영역을 무효화하기 위해 사용됩니다.

지금까지 Open 명령을 구현한 것에 이어서 이미지를 볼 수 있게 해야 합니다. 그러나 지금까지의 ImageView 코드로는 폼에 이미지를 렌더링하는 데 충분하지 않습니다. 우선 이미지 파일이 아닌 파일을 열어 그림?5 의 try...catch 논리가 제대로 작동하는지 확인해야 합니다. 그 다음, 이미지 파일을 선택한 경우 파일 이름이 폼의 제목 표시줄에 나타나는지 확인할 수 있습니다. 사용자가 여는 이미지를 표시할 수 없다면 ImageView는 아직 제한된 유틸리티에 지나지 않습니다. 따라서 이하에서는 추가 채색 논리를 통해 이러한 문제를 수정합니다.

맨 위로


4단계: OnPaint 무시

채색 논리를 추가하려면 파생된 폼 클래스에서 OnPaint를 무시하고 제공된 Graphics 개체를 사용합니다. 그림?6의 OnPaint 메서드는 _MyBitmap을 폼의 클라이언트 영역에 렌더링합니다. (_MyBitmap은 사용자가 선택한 이미지에 대해 참조를 저장하는 OnOpenImage가 초기화하는 보호된 필드임을 상기하시기 바랍니다.) 이 렌더링은 다음 두 개의 간단한 명령문으로 수행됩니다.

Graphics g = e.Graphics;
g.DrawImage (_MyBitmap, 0, 0,
    _MyBitmap.Width, _MyBitmap.Height);
결과는 그림?7에 나와 있습니다. 채색은 System.Drawing.Graphics에 정의된 많은 메서드 중 하나인 DrawImage에 의해 수행됩니다. Windows GDI에는 비트맵 이미지의 그리기 및 조작을 위한 고급 기능이 없기 때문에 Windows보다 .NET에서 화면의 비트맵에 채색하는 작업이 훨씬 간단합니다.


그림 7 JPEG 파일을 표시하는 이미지 보기
그림 7 JPEG 파일을 표시하는 이미지 보기


Graphics 개체를 사용하여 그래픽 출력을 랜더링할 경우 GDI+라는 .NET 플랫폼의 구성 요소를 사용합니다. Windows GDI와 마찬가지로 GDI+는 2차원 그래픽 생성을 위한 API입니다. 그러나 Windows GDI와 달리 GDI+는 Gdi32.dll에서 내보내진 제한된 함수 집합에 의해 제한되지 않습니다. GDI+는 그라데이션 채우기, 부동 소수점 좌표, 앤티 앨리어싱 등을 비롯하여 상당히 다양한 기능을 지원합니다. 또한 연결되지 않은 분산 응용 프로그램에 더 적절하게 사용할 수 있는 상태 비저장 프로그래밍 모델을 지원합니다.

맨 위로


5단계: 스크롤 막대 추가

이제 ImageView는 이미지를 표시할 수 있지만 이미지 크기가 폼 크기를 초과할 경우 이미지의 일부만 볼 수 있습니다. 이 문제에 대한 분명한 해결책이 바로 스크롤 막대 즉, 이미지 크기가 폼 너비를 초과할 경우 나타나는 가로 스크롤 막대 및 이미지 높이가 폼 높이를 초과할 경우 나타나는 세로 스크롤 막대입니다.

System.WinForms.Form은 스크롤을 가능하게 하는 System.WinForms.ScrollableControl로부터 속성 쌍을 상속합니다. AutoScroll은 자동 스크롤 기능을 설정 및 해제하는 Boolean 속성입니다. 자동 스크롤이 활성화되면 폼 크기가 작아 클라이언트 영역에 이미지를 모두 표시할 수 없을 경우 스크롤 막대가 자동으로 나타납니다. 폼은 사용자가 폼의 AutoScrollMinSize 속성에 Size 값을 기록하여 제공하는 보기 영역의 크기를 통해 사용자가 표시하고자 하는 이미지를 인식합니다.

그림?8의 Main.cs 버전은 ImageView에 스크롤 지원을 추가합니다. OnOpenImage에 두 개의 코드 줄 즉, 자동 스크롤을 활성화하는 코드 줄과 비트맵의 너비 및 높이와 동일하게 AutoScrollMinSize를 설정하는 코드 줄이 추가되었습니다. 또한 가로 및 세로 스크롤 위치에 해당하는 크기만큼 비트맵을 오프셋하기 위해 OnPaint가 수정되었습니다. 이러한 변경 내용은 이미지 및 폼 크기에 상관 없이 모든 이미지의 전체를 볼 수 있게 해 줍니다.

맨 위로


6단계: 자동 맞춤 옵션 추가

큰 이미지를 처리하기 위해 폼에 스크롤 막대를 추가하는 것 외에도 이미지의 실제 크기를 무시하고 렌더링하여 폼 크기에 정확하게 맞출 수도 있습니다. 어떤 방법을 사용할 것인지는 옵션 메뉴에 명령 쌍을 추가하여 사용자가 직접 결정할 수 있게 합니다. 옵션 메뉴에 추가하는 두 명령 중 Size Image to Fit Window는 이미지를 폼에 맞추며, Show Image in Native Size는 이미지를 원래 해상도로 표시하되 필요한 경우 스크롤 막대를 제공하여 큰 이미지를 볼 수 있게 합니다.

그림?9는 이러한 작업을 수행하는 방법을 보여 줍니다. 우선 필드(_NativeSize)를 추가하여 사용자의 기본 설정을 저장한 다음 MyForm의 생성자를 수정하여 새 메뉴 항목 두 개(기타 구분줄을 포함할 경우에는 세 개)를 추가합니다. 그 다음, _NativeSize를 True 또는 False로 설정하고 스크롤을 설정 및 해제하며 Invalidate를 호출하여 다시 칠하기를 자동으로 하는 명령 처리기를 추가합니다. 마지막으로 OnPaint를 수정하여 _NativeSize가 False인 경우 렌더링된 이미지 크기를 폼 크기와 일치시킵니다. 이미지 크기와 폼 크기의 일치는 폼 클라이언트 영역의 크기가 포함된 직사각형을 DrawImage의 둘째 매개 변수에 전달하여 간단히 수행할 수 있습니다. 이 직사각형은 ClientRectangle이라는 System.WinForms.Form 속성으로 쉽게 사용할 수 있습니다.

그림?9에서 주목해야 할 새 코드는 SetStyle에 대한 호출 쌍입니다. 기본적으로 크기 조정 작업은 전체 폼이 아니라 크기 조정 작업에 의해 드러난 폼의 일부만 무효화합니다. 이는 폼 크기에 맞도록 이미지 크기를 조정하지 않을 경우에는 상관이 없습니다. 그러나 크기 조정을 할 경우라면 크기가 변경될 때 전체 클라이언트 영역을 무효화하여 전체 폼을 다시 칠할 수도 있습니다. 이렇게 하려면 Windows의 경우 CS_HREDRAW 및 CS_ VREDRAW 플래그를 WNDCLASS 스타일에 포함해야 했지만, Windows Forms에서는 ControlStyles.ResizeRedraw 매개 변수로 폼의 SetStyle 메서드를 호출합니다. ControlStyles는 System에 정의된 열거이며 WinForms; ResizeRedraw는 이 열거의 구성원입니다.

맨 위로


7단계: 코드를 추가하여 메뉴 항목 선택 및 선택 취소

이제 남은 일은 _NativeSize가 True인지 아니면 False인지에 따라 Size Image to Fit Window 또는 Show Image in Native Size 옆에 확인 표시를 두는 것입니다. 이렇게 하려면 다음 두 가지 방법을 사용할 수 있습니다.

첫째 방법은 메뉴에서 두 항목 중 하나가 선택될 경우 각 MenuItem의 Checked 속성을 True 또는 False로 설정하는 것입니다. Checked를 True로 설정하면 해당 메뉴 항목 옆에 확인 표시가 놓이며, False로 설정하면 확인 표시를 두지 않습니다. 둘째 방법은 사용자가 주 메뉴에서 옵션을 클릭할 때와 옵션 메뉴가 나타날 때의 시간 간격 사이에 메뉴 항목을 즉시 선택 또는 선택 취소하는 것입니다. 다시 말하면 MFC 업데이트 처리기와 동일한 기능의 코드를 작성하는 것입니다. 후자의 경우 메뉴를 업데이트하는 코드와 _NativeSize를 True 또는 False로 설정하는 코드를 구분한다는 점에서 분명한 이점이 있으며 그림?10에 사용된 방법도 여기에 해당합니다.

최종 버전의 Main.cs에서 Size Image to Fit Window 및 Show Image in Native Size 명령을 나타내는 MenuItem 개체에 대한 참조는 각각 _itemFitToWindow 및 _itemNativeSize라는 필드에 캐시됩니다. 또한 메뉴가 풀다운되었음을 의미하는 Popup 이벤트에 대한 처리기는 다음 명령문을 통해 옵션 메뉴에 연결됩니다.

  item.Popup += new EventHandler 
     (OnPopupOptionsMenu);
옵션 메뉴가 표시될 때마다 호출되는 OnPopupOptionsMenu는 _NativeSize의 현재 값에 기초하여 _itemFitToWindow 및 _itemNativeSize가 나타내는 메뉴 항목을 선택하거나 선택 취소합니다. 결과적으로 _NativeSize의 현재 값이 무엇인지와 이 값이 획득된 방법에 상관 없이 항상 해당 메뉴 항목 옆에 확인 표시가 나타납니다. 그림?11은 최종 결과를 나타낸 것입니다.

그림 11 확인 표시가 있는 Show Image in Native Size
그림 11 확인 표시가 있는 Show Image in Native Size

맨 위로


ImageView 복습

지금까지 .NET Framework 클래스 라이브러리의 Form, Application 및 Graphics 클래스가 Windows Forms를 사용하는 응용 프로그램 작업에서 수행하는 주요 역할을 살펴 보았습니다. 여기서 ImageView가 사용하는 몇 가지 프레임워크 클래스를 다시 검토한다면 도움이 될 것입니다. 그림?12에는 특히 ImageView의 디자인 및 운영을 중심으로 한 일부 클래스가 나열되어 있습니다. Microsoft .NET 프로그래머가 되기 위해서는 기존의 Windows API, MFC 또는 Visual Basic API뿐 아니라 .NET Framework 클래스 라이브러리를 이해해야 합니다. 엄밀하게 따지면 .NET Framework 클래스 라이브러리는 .NET API이며, 이것은 Microsoft .NET이라는 분야를 이해하는 데 출발점이 됩니다. Microsoft가 이와 관련하여 언급한 모든 사항은 Windows 기반 응용 프로그램 및 웹 응용 프로그램 모두의 미래 세대를 위한 토대를 마련할 것입니다.

맨 위로


TuneTown 응용 프로그램

ImageView와 같은 응용 프로그램을 작성하는 일은 Windows Forms를 시작하기 위한 좋은 방법입니다. 그러나 ImageView는 .NET Framework에서 사용할 수 있는 Windows Forms 클래스의 일부만 사용하며 누름 단추나 기타 컨트롤을 사용하지 않는다는 점에서 일반적인 폼 기반 응용 프로그램이 아닙니다. 따라서 이하에서는 컨트롤을 사용하는 응용 프로그램 즉, 사용자가 자신의 CD 모음을 카탈로그로 만들 수 있는 응용 프로그램( 그림?13 참조)을 만들어 봅니다. 특히 IDE를 사용하여 폼을 디자인하고 이를 위한 코드를 생성할 수 있도록 Microsoft Visual Studio.NET의 모든 기능을 활용하여 문제를 해결합니다.

그림 13 CD 모음 카탈로그
그림 13 CD 모음 카탈로그

다음 연습은 Microsoft에서 2000년 11월부터 다운로드를 시작한 Visual Studio.NET의 베타 1 버전으로 작성되었습니다. 따라서 Visual Studio.NET이 최종 완료되어 릴리스되기 전에 이 연습의 화면 및 구성 자체가 변경될 수 있습니다.

맨 위로


1단계: 새 Windows Forms 프로젝트 만들기

Visual Studio® File 메뉴에서 New Project 명령을 선택하여 새 프로젝트를 만듭니다. C# 프로젝트 폴더에서 Windows Application을 프로젝트 유형으로 선택합니다( 그림?14 참조). 그 다음, 프로젝트의 이름으로 TuneTown을 입력합니다.

Figure 14 Create New Project
그림 14 새 프로젝트 만들기

맨 위로


2단계: 기본 폼 디자인

새 프로젝트가 만들어지면 Visual Studio 폼 편집기가 나타나면서 빈 폼이 제공됩니다. 폼에서 작업을 시작하기 전 Solution Explorer 창에서 기본 파일 이름인 Main1.cs를 MainForm.cs로 변경합니다. 동시에 Class View 창을 사용하여 클래스 이름을 Form1에서 MainForm으로 변경합니다.
이제 폼 편집기로 되돌아가 그림?15와 같이 목록 보기 컨트롤 하나와 누름 단추 세 개를 폼에 추가합니다. 그 다음, 추가한 컨트롤을 각각 하나씩 선택한 후 Properties 창을 사용하여 다음 단락에 설명된 것처럼 컨트롤 속성을 수정합니다.

그림 15 TuneTown의 기본 폼
그림 15 TuneTown의 기본 폼

목록 보기 컨트롤에 대해 다음과 같이 컨트롤 속성을 편집합니다.
  1. FullRowSelect 속성을 True로 설정합니다.
  2. GridLines 속성을 True로 설정합니다.
  3. View 속성을 Report로 설정합니다.
  4. Columns 컬렉션을 편집하여 목록 보기의 맨 위에 있는 머리글에 열 세 개를 추가합니다. 이 때 각 열의 Name, Text 및 Width는 첫째 열이 "TitleHeader", "Title" 및 100, 둘째 열이 "ArtistHeader", "Artist" 및 100, 마지막 셋째 열이 "CommentHeader", "Comment" 및 200입니다.
  5. Multiselect를 False로 설정합니다.
  6. HideSelection을 False로 설정합니다.
  7. Sorting을 Ascending으로 설정합니다.
  8. TabIndex를 0으로 설정합니다.
  9. Name을 "TuneView"로 설정합니다.
누름 단추 컨트롤의 속성을 다음과 같이 편집합니다.
  1. Text 속성을 각각 "&Add", "&Edit" 및 "&Remove"로 설정합니다.
  2. Name 속성을 각각 "AddButton", "EditButton" 및 "RemoveButton"으로 설정합니다.
  3. TabIndex 속성을 각각 1, 2 및 3으로 설정합니다.
마지막으로 폼 자체의 Text 속성을 "TuneTown"으로 변경합니다. 그러면 폼의 캡션 표시줄에 있는 제목이 바뀝니다.

맨 위로


3단계: 다른 폼 추가

사용자가 Add 또는 Edit 단추를 클릭했을 때 입력을 요청하는 데 사용할 수 있는 다른 폼을 만들어야 합니다. 실제로 이러한 폼은 대화 상자로 사용됩니다. 프로젝트에 다른 폼을 추가하려면 Project 메뉴에서 Add Windows Form 명령을 선택하고 뒤이어 나타나는 대화 상자에서 Windows Form을 선택합니다(그림?16 참조). 그 다음, Name 상자에 AddEditForm.cs를 입력합니다.


그림 16 새 Windows Form 추가
그림 16 새 Windows Form 추가

맨 위로


4단계: 폼 디자인

Visual Studio 폼 편집기에서 새 폼을 그림?17과 같은 모양으로 편집합니다. 레이블 컨트롤의 속성을 다음과 같이 수정합니다.

그림 17 폼 편집기
그림 17 폼 편집기

  1. Text 속성을 각각 "&Title", "&Artist" 및 "&Comment"로 설정합니다.
  2. Name 속성을 각각 "TitleLabel", "ArtistLabel" 및 "CommentLabel"로 설정합니다.
  3. TabIndex를 각각 0, 2 및 4로 설정합니다.
다음과 같이 편집 컨트롤의 속성을 수정합니다.
  1. 세 컨트롤 모두의 Text 속성을 Null로 설정합니다.
  2. Name을 각각 "TitleBox", "ArtistBox" 및 "CommentBox"로 설정합니다.
  3. TabIndex를 각각 1, 3 및 5로 설정합니다.
  4. 셋째 편집 컨트롤의 Multiline 속성을 False에서 True로 변경합니다.
그 다음, 누름 단추 두 개의 속성을 다음과 같이 수정합니다.
  1. Text를 각각 "OK" 및 "Cancel"로 설정합니다.
  2. DialogResult를 각각 OK 및 Cancel로 설정합니다.
  3. Name을 각각 "OKButton" 및 "NotOKButton"으로 설정합니다.
  4. TabIndex를 각각 6과 7로 설정합니다.
마지막으로 폼 자체의 속성을 다음과 같이 편집합니다.
  1. BorderStyle을 FixedDialog로 설정합니다.
  2. AcceptButton을 OKButton으로 설정합니다.
  3. CancelButton을 NotOKButton으로 설정합니다.
  4. MaximizeBox 및 MinimizeBox를 False로 설정합니다.
  5. ShowInTaskbar를 False로 설정합니다.
이제 폼이 완료되었으므로 코드를 작성할 차례입니다.

맨 위로


5단계: AddEditForm에 속성 추가

AddEditForm.cs를 열어 그림?18에 있는 녹색으로 된 명령문을 추가합니다. 그림?18의 코드 대부분은 Visual Studio로 작성되었습니다. 이 코드는 다음과 같이 중요한 세 가지 작업을 수행합니다.

  • 폼의 컨트롤을 나타내기 위해 AddEditForm 클래스에서 Button (System.WinForms.Button), TextBox (System.WinForms.TextBox) 및 Label (System.WinForms.Label) 필드를 선언합니다. 또한 Button, TextBox 및 Label의 인스턴스에 대한 참조로 세 필드를 초기화합니다.
  • 각 컨트롤 및 폼 자체의 속성을 초기화합니다.
  • 폼의 Controls 컬렉션을 호출하여 폼에 컨트롤을 물리적으로 추가합니다.
이 코드의 대부분은 클래스 생성자로부터 호출된 InitializeComponent라는 메서드에 위치합니다. InitializeComponent에서 "Component"는 폼 자체를 나타냅니다. InitializeComponent 메서드에서 볼 수 있는 코드의 대부분은 폼에 컨트롤을 추가하고 컨트롤 속성을 변경할 때 생성된 것입니다.

입력된 명령문은 폼 클래스에 Title, Artist 및 Comment 속성을 추가합니다. 이러한 속성은 호출자가 폼의 편집 컨트롤에 있는 텍스트를 액세스할 수 있도록 허용합니다.


맨 위로


6단계: MainForm에 이벤트 처리기 추가

이 단계에서는 MainForm 클래스에 이벤트 처리기를 추가합니다. 이벤트 처리기는 Add, Edit 또는 Remove 단추를 클릭하거나 목록 보기 컨트롤의 항목을 두 번 클릭했을 때 호출됩니다( 그림?19 참조).

Windows Forms에서 컨트롤은 사용자 입력에 응답하여 이벤트를 실행합니다. MainForm은 각 누름 단추의 Click 이벤트를 XxxButtonClicked 메서드에 연결하고 ListView의 DoubleClick 이벤트를 OnItemDoubleClicked 메서드에 연결합니다. Add 및 Edit 단추에 대한 처리기는 ShowDialog 메서드를 호출하여 초기화한 AddEditForm을 화면에 표시합니다. ShowDialog는 OK 단추가 클릭된 경우에는 DialogResult.OK를, Cancel 단추가 클릭된 경우에는 DialogResult.Cancel을 반환하여 대화 상자가 해제된 방법을 알려줍니다. 대화 상자의 내외로 데이터를 가져오기 위해 처리기는 사용자가 5단계에서 AddEditForm에 추가한 속성을 읽고 씁니다. 폼 편집기는 다시 한 번 폼 모양을 정의하는 코드를 제공하며 사용자는 폼 동작을 구현하는 코드를 제공합니다.

이제 프로젝트를 작성할 때가 되었습니다. 명령줄로 이동할 필요 없이 Visual Studio Build 메뉴에서 Build 명령을 선택합니다. 그 다음, Debug 메뉴의 Start 명령 중 하나를 선택하여 TuneTown.exe를 실행할 수 있습니다.


맨 위로


7단계: 앵커 추가

TuneTown은 거의 완료되었지만 아주 중요한 요소 즉, Windows Forms에서 가장 획기적인 기능 중 하나를 갖추고 있지 않습니다. TuneTown을 실행하여 주 창의 크기를 조정하면 어떤 기능이 부족한지를 알 수 있습니다. 즉, 폼의 BorderStyle 속성이 Sizable로 설정되었으므로 창 크기는 제대로 조정되지만(단, 크기를 조정할 수 없게 하려면 BorderStyle을 FixedDialog로 변경) 컨트롤은 그대로 유지됩니다. 이 경우 컨트롤 크기 및 위치가 폼에 맞게 자동으로 조정되어 변경된 공간을 모두 활용할 수 있다면 더 바람직할 것입니다. 이를 위해 일반 Windows 기반 응용 프로그램에서는 WM_SIZE 메시지를 처리하고 컨트롤을 프로그래밍 방식으로 이동 및 크기 조정해야 합니다. 그러나 Windows Forms의 경우 코드 줄을 하나만 작성하는 아주 간단한 방법으로 원하는 바를 달성할 수 있습니다.

모든 Windows Forms 컨트롤은 System.WinForms.RichControl에서 Anchor라는 속성을 상속합니다. Anchor 속성은 컨트롤의 가장자리가 붙어 있어야 하는 폼의 가장자리를 설명합니다. 예를 들어, 컨트롤의 Anchor 속성을 AnchorStyles.Right로 설정하면 컨트롤의 오른쪽 가장자리와 폼의 오른쪽 가장자리는 폼 크기가 조정될 경우에도 일정하게 유지됩니다. 따라서 다음 방법으로 MainForm의 컨트롤에 대한 Anchor 속성을 설정하면 누름 단추가 폼의 오른쪽 가장자리와 함께 이동하고 목록 보기 컨트롤이 세로 및 가로로 늘어나 폼의 나머지 공간을 채우도록 쉽게 구성할 수 있습니다.

우선 폼 편집기에서 MainForm을 열고 ListView의 Anchor 속성을 설정합니다. 그 다음, TopLeft로 설정되어 있는 Anchor를 All로 변경한 후 한 번에 하나씩 누름 단추의 Anchor를 TopRight로 설정합니다. 이렇게 하면 다음 명령문이 MainForm의 InitializeComponent 메서드에 추가됩니다.

  AddButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  EditButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  RemoveButton.Anchor = System.WinForms.AnchorStyles.TopRight;
  TuneView.Anchor = System.WinForms.AnchorStyles.All;
이제 응용 프로그램을 다시 작성하고 폼 크기를 재조정합니다. 그러면 컨트롤은 폼과 함께 조정되어야 합니다. 기존에는 대화 상자에서 컨트롤이 너무 작아 원하는 모든 내용을 표시할 수 없다는 점 때문에 어려움을 겪었을 것입니다. 그러나 Windows Forms의 앵커 기능을 활용하면 이러한 문제로 더 이상 고민하지 않게 될 것입니다.

맨 위로


8단계: 지속성 추가

마지막 단계는 TuneTown을 닫을 때 목록 보기 컨트롤의 내용을 디스크 파일에 기록하고 다음에 TuneTown을 시작할 때 이러한 내용을 읽어 TuneTown에 입력된 데이터를 지속시키는 것입니다. 텍스트 문자열의 입력 및 출력 작업을 단순화하기 위해 여기서는 .NET Framework 클래스 라이브러리의 StreamWriter 및 StreamReader 클래스(System.IO 이름 공간의 구성원)가 사용됩니다.

그림?20에는 필요한 변경이 무엇인지 표시되어 있습니다. OnClosing은 폼이 닫히기 바로 이전에 호출된 System.WinForms.Form으로부터 상속하는 가상 메서드입니다. MainForm의 OnClosing 구현은 로컬 사용자의 응용 프로그램 데이터 경로(SystemInformation.GetFolderPath(SpecialFolder.LocalApplicationData))에 TuneTownData.ttd라는 텍스트 파일을 만든 다음 목록 보기 컨트롤의 각 항목 및 하위 항목의 텍스트를 파일에 기록합니다. 다음 번에 TuneTown이 시작되면 MainForm의 InitializeListView 메서드는 파일을 열어 문자열을 읽은 다음 목록 보기에 다시 기록합니다.

StreamWriter 및 StreamReader 개체의 Close 메서드에 대한 호출에 주의합니다. 이러한 호출이 포함된 이유는 결정적 대 비결정적 파괴와 관련이 있습니다. C++과 같은 언어는 정확한 시점에 개체가 범위를 벗어나 파괴되는 결정적 파괴를 사용합니다. 그러나 리소스를 회수하기 위해 쓰레기 수집기를 사용하는 NET CLR은 비결정적 파괴를 사용합니다. 따라서 쓰레기 수집기가 사용되는 시기 또는 그 사용 여부가 분명하지 않습니다. 일반적으로 쓰레기 수집이 수행되는 시기는 중요하지 않습니다. 그러나 개체가 파일 핸들과 같이 메모리가 아닌 리소스를 캡슐화하는 경우 더 이상 필요하지 않은 파일 핸들을 즉시 닫기 위해 결정적 파괴를 원할 수도 있습니다. StreamWriter 개체가 포함되면 문제가 더 악화될 수 있습니다. StreamWriter 개체가 파괴될 때 호출되는 StreamWriter의 Finalize 메서드가 파일 핸들을 닫거나 또는 버퍼링된 데이터를 디스크에 플러시하는 작업을 지연시키지 때문입니다. 또한 Close를 호출하지 않을 경우 데이터가 손실될 수 있습니다. 따라서 Close에 대한 TuneTown의 호출을 포함하기 위한 블록을 최종적으로 사용하는 단계를 추가하였습니다.

맨 위로


마치는 글

TuneTown을 완벽한 기능의 응용 프로그램으로 만들기 위해 추가 작업을 수행할 수 있지만 여기서 그만 설명을 끝내기로 합니다.
Windows Form 프로그래밍 모델은 앞으로 다가올 새로운 흐름입니다. 멀지 않은 미래에 거의 대부분의 Windows 기반 프로그래밍이 .NET 방식으로 이루어질 것입니다. 모든 기업이 이러한 Microsoft의 비전에 동참하고 있다는 말하기는 아직 이르지만, 향후 몇 년 안에 그렇게 되리라 확신할 수 있습니다.



Windows 프로그래머인 동시에 교육자인 Jeff Prosise는 개발자 훈련 및 컨설팅 회사인 Wintellect의 공동 설립자입니다. Jeff에게 직접 문의하려면 jeffpro@wintellect.com으로 전자 메일을 보내시기 바랍니다.

? 최종수정일: 2001년 2월 19일

Top of Page Top of Page


Microsoft