[.NET] C#을 이용한 PropertyGrid 사용법에 대한 Summary

일단 생긴 것 부터가 범창치 않은 이 컨트롤은 활용하기에 따라서 큰 활용도가 있을 것이다. 아래는 Visual Studio.NET 2005에 붙어 있는 속성창으로써 95% 이상이 PropertyGrid라는 컨트롤로 만들어진 UI이다.


필자가 이 PropertyGrid에 큰 관심을 두는 까닭은 VS의 속성창에 해당하는 델파이의 Object Inspector에 대한 필요성에서였다. 델파이의 Object Inspector 역시 PropertyGird와 같은 기능을 하는 VCL 컴포넌트로 만들어진 UI인데, 델파이의 개발사인 볼렌드는 해당 컴포넌트를 공개하지 않고 내부적으로만 사용하여왔으며, 지금 역시 그러하다. 그래서 필요하다면 천상 만들어 쓰던지, 어디서 찾아 쓰던지 사던지 해야할 것이였다. 이런 기능을 하는 컴포넌트를 하나 만들자니 배보다 배꼽이 더 커져버리게 될 모냥이고, 찾아 쓰자니 기존의 Object Inspector에 의해 눈이 높아져버려 마음에 드는 녀석을 찾아볼 수가 없었다. 그런데 MS는 PropertyGrid 컨트롤을 그냥 기본적은 .NET 컨트롤군에 포함시켜 사용자들이 쉽게 사용할 수 있도록 공개해 놓았다. MS의 개발자 지원에서 얼마나 큰 힘을 실고 있는지를 볼 수 있는 또 하나의 해석이라고 보여진다.

기능이 다양하고 강력한 만큼 PropertyGrid 컨트롤은 사용하기가 그렇게 호락 호락 하지 않은 녀석이다. .NET 기술이 태동되기 이전인 ATL 기술에서 채용되기 시작한 Attribute 방식을 사용하여 .NET에서 PropertyGrid를 사용한다. OOP 방식과 Attribute 방식 만남이다.

여기서는 기본적인 PropertyGrid의 사용법에서 고급사용법까지 몇단계에 걸치 그 사용법을 정리하고자 한다. 먼저 기본적인 사용법을 알아보겠다. 기보적인 사용법을 알아보기 위해 하나의 예제를 작성해 볼 것이다. 또한 그 예제의 결과 화면은 아래와 같다.


일단 Category는 ID Settings와 Marketting Settings로 2개이다.  ID Settings는 Address, Age, DateOfBirth, Name, SSN, TestColor이라는 이름의 Property를 가지고 있으며, Marketting Settings는 Email과 FrequentBuyer이라는 프로퍼트를 가지고 있다.

먼저 PropertyGrid의 사용법에 대한 큰 개념은 이렇다. Category를 지정하고 지정된 Category에 속하는 속성명과 속성의 Type을 지정하는 하나의 class를 만든 후, PropertyGrid의 SelectedObject에 그 class의 인스턴스를 할당한다. 이것이 전부다. SelectObject에 class의 인스턴스를 할당하는 거야 간단한 것이고, 문제는 그 문제의 class를 만드는 것이다. 바로 이 class를 만드는 것에 대해 살펴보자.

문제의 class의 빼대는 아래와 같다.

public class Customer
{
    private string _name;
    private int _age;
    private DateTime _dateOfBirth;
    private string _SSN;
    private string _address;
    private string _email;
    private bool _frequentBuyer;
    private Color _color;

    public Customer() {}
}

_name, _age, _dateOfBirth, _SSN, _address, _email, _frequentBuyer, _color이라는 변수들은 앞서 살펴본 구현할 결과 Property에 하나 하나가 매칭된다. 그러나 여기에는 크게 2가지 문제점이 있다. _name, _age등의 접근자는 private이므로 PropertyGrid는 이 변수들을 읽어낼 수도 변경할 수도 없다. 그래서 PropertyGrid와의 소통을 위해서 이 변수들에 대한 Property 지시자를 통해 Property로 만들어보자. 그 코드는 아래와 같다.

public class Customer
{
    private string _name;
    private int _age;
    private DateTime _dateOfBirth;
    private string _SSN;
    private string _address;
    private string _email;
    private bool _frequentBuyer;
    private Color _color;

    public Customer()  {}

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    public Color TestColor
    {
        get { return _color; }
        set { _color = value; }
    }

    public string SSN
    {
        get { return _SSN; }
        set {_SSN = value; }
    }

    public string Address
    {
        get { return _address;}
        set {_address = value; }
    }

    public DateTime DateOfBirth
    {
        get {return _dateOfBirth; }
        set {_dateOfBirth = value; }
    }

    public int Age
    {
        get { return _age; }
        set {_age = value; }
    }

    public bool FrequentBuyer
    {
        get {return _frequentBuyer; }
        set { _frequentBuyer = value; }
    }

    public string Email
    {
        get { return _email;}
        set {_email = value;}
    }
}

이렇게 해서 데이터를 Property화하여 외부와의 데이터 통신을 위한 Public 처리를 마쳤다. 이제 남은 문제는 이러한 데이터를 각 Category 별로 분류를 해야한다는 것이다. 앞서 분류는 ID Settings는 Address, Age, DateOfBirth, Name, SSN, TestColor이라는 이름의 Property를 가지고 있으며, Marketting Settings는 Email과 FrequentBuyer이라는 프로퍼트를 가진다라고 하였다. 바로 여기서부터 Attribute 기법이 들어간다. Attribute 기법은 ‘[‘와 ‘]’를 통해 지정되며 클래스나 프로퍼티등에 특정한 특성(Attribute에 대한 해석은 속성이 아닌 특성으로 해야한다)을 지정하도록 하는 것이다. Category 별로 Property를 분류하기 위한 Attribute의 지시자는 CategoryAttribute이며 그 사용법은 실제 코드에 적용된 것을 살펴보면 쉽게 알 수 있을 것이다. 아래는 실제 적용되어 덧 붙여진 코드이다.

[DefaultPropertyAttribute("Name")]
public class Customer
{
    private string _name;
    private int _age;
    private DateTime _dateOfBirth;
    private string _SSN;
    private string _address;
    private string _email;
    private bool _frequentBuyer;
    private Color _color;

    public Customer() {}

    [CategoryAttribute("ID Settings"), 
    DescriptionAttribute("Name of the customer")]
    public string Name
    {
        ....
    }

    [CategoryAttribute("ID Settings"), 
    DescriptionAttribute("Color of the customer")]
    public Color TestColor
    {
        ....
    }

    [CategoryAttribute("ID Settings"),
    DescriptionAttribute("Social Security Number of the customer")]
    public string SSN
    {
        ....
    }

    [CategoryAttribute("ID Settings"),
    DescriptionAttribute("Address of the customer")]
    public string Address
    {
        ....
    }

    [CategoryAttribute("ID Settings"),
    DescriptionAttribute("Date of Birth of the Customer (optional)")]
    public DateTime DateOfBirth
    {
        ....
    }

    [CategoryAttribute("ID Settings"),
    DescriptionAttribute("Age of the customer")]
    public int Age
    {
        ....
    }

    [CategoryAttribute("Marketting Settings"),
    DescriptionAttribute("If the customer as bought more \
    than 10 times, this is set to true")]
    public bool FrequentBuyer
    {
        ....
    }

    [CategoryAttribute("Marketting Settings"),
    DescriptionAttribute("Most current e-mail of the customer")]
    public string Email
    {
        ....
    }
}

CategoryAttribute를 통해 각 Property의 Category를 지정하고 있다. CategoryAttribute 이외에 Attribute 지시자로 DescriptionAttribute와 DefaultPropertyAttribute 속성이 있는데 먼저 DefaultPropertyAttribute는 PropertyGrid가 처음 구동될때 기본적으로 선택되어질 속성을 지시하는 것이며 DescriptionAttribute는 Property를 선택했을때 PropertyGrid 컨트롤 하단의 Property의 설명에 나타날 문자열이다.

이렇게 문제의 Class를 제작했고 실제 PropertyGrid 컨트롤에 지정하는 방법은 아래와 같다. 당연이 폼상에 PropertyGrid 컨트롤을 마우스로 끌어와 넣었다는 가정에서 말이다.

private void Form1_Load(object sender, EventArgs e)
{
     Customer bill = new Customer();

    bill.Age = 50;
    bill.Address = " 114 Maple Drive ";
    bill.DateOfBirth = Convert.ToDateTime("78/9/4");
    bill.SSN = "123-345-3566";
    bill.Email = "bill@aol.com";
    bill.Name = "Bill Smith"; 
    bill.TestColor = Color.Red;

    propertyGrid1.SelectedObject = bill;
}

이제 실행해보면 애초에 원하던 결과가 나타날 것이다. 이상이 PropertyGrid의 기본적인 사용법에 대해서 살펴보았다. 다음에는 고급 사용법인 PropertyGrid에 Combo List와 사용자정의 컨트롤 등을 올리는 방법들 하나 하나를 나눠 정리해보도록 하겠다.

도움이 되었다면, 댓글이라도 하나 남겨주는 센스를 잃지 않으셨으면 합니다~ ^^*

[Linux] Fedora core6 64bit에서 VGA 카드 설정과 OpenGL 테스트 코딩

얼마전에 장만한 Dell 노트북에 리눅스(Fedora core 6, 64bits)를 설치해보았다. 멀티부팅을 통해 XP와 리눅스를 같이 설치해 보았는데, 게임이나 인터넷 뱅킹과 같은 것은 XP를 그외 개발에 관련된 코딩이나… 또.. 음.. 모르겠다. 코딩 이외에 리눅스를 어디에 써먹어야할지 아직은.. 기본적으로 OpenOffice가 설치되어져 있던데, 마이크로소프트의 오피스와 호환성의 완성도가 무척 높다. 몇달전부터 쓰던 엑셀로 쓰고 있던 생활비 내역을 리눅스의 오픈오피스로 작업을 해보았다. 이외에 워드나 파워포인트 역시 사용해 본 결과 MS의 오피스에 못지 않았다. 하지만 MS의 오피스가 UI면이나 파워포인트에서의 산출물의 품질은 더 뛰어난것같다. 아직은 말이다..

처음 페도라를 설치할때 32Bit로 했으나, 비디오 드라이버를 설치하는 과정에서 64Bit로 설치하게 되었다. 나의 노트북의 비디오 카드의 X1400이였는데, 32비트에서는 설치가 않되는줄 알았으나, 아니였다. 32비트이든, 64비트이든 상관은 없었다. 페도라가 기본적으로 제공하는 비디오카드는 vesa(정말 오랜만에 들어보는..)이다. 내 노트북의 해상도가 1680×1400인데, 1400×1400만을 지원한다.

Radeon Mobility X1400 비디오 카드를 가진 분들이 페도라 코어 6에서 비디오 드라이버를 설치할때의 어려움에 대한 해결방법을 공유하기 위해 그 방법을 기록해 둔다. 참고로 ATI사에서 제공하는 리눅스 X1400용 비디오 드라이버로 시도해 보았으나 번번이 실패했다. 검색해 본 결과로는 페도라의 경우 해당 드라이버를 자동설치하지 말고 rpm 패키지를 뽑아내어 설치하라고 되어 있었으나, 뽑아내지 못했다. 나와 같은 어려움을 격는 사용자가 많았던지 livna에서 해당 패키지를 뽑아내어 제공하고 있었다. 아래부터는 livna에서 제공하는 패키지를 통해 드라이버를 설치하는 과정이다.

1) rpm -ivh http://rpm.livna.org/livna-release-6.rpm 를 실행해 패키지 다운로드
2) pirut 실행(pirut는 메인메뉴의 “Add/Remove Software”이다)
3) pirut에서 fglrx로 검색한후, “xorg-x11-drv-fglrx”를 설치
4) /usr/sbin/ati-fglrx-config-display enable 실행
5) xorg.conf 파일을 열고 아래 항목으로 수정 및 추가

Section "Module"
	Load "dri"
	Load "extmod"
	Load "glx"
EndSection

Section "DRI"
	Group 0
	Mode 0666
EndSection
	
Section "Extensions"
	Option "Composite"	"False"
EndSection
	
Section "ServerFlags"
	Option "AIGLX" "off"
EndSection 
	
Section "Device"
	Identifier  "Videocard0"
	Driver      "fglrx"
	Option	    "DesktopSetup" "single"
EndSection 

6) Rebooting 또는 Log-out
7) fglrxinfo 실행하여 ATI에서 제공하는 OpenGL 2.0 드라이버를 지원하고 있는지 확인

display: :0.0 screen: 0
OpenGL vendor string: ATI Technologies Inc.
OpenGL renderer string: ATI Mobility Radeon X1400 Generic
OpenGL version string: 2.0.6174 (8.31.5)

 

8) glxinfo| grep direct 를 실행하여 Direct Rendering이 가능한지 확인(Yes나와야함)
9) fgl_glxgears를 실행하여 확인(3D로된 3개의 기어가 돌아가는 OpenGL용 샘플)

여기까지 하면 1680×1400 해상도와 OpenGL의 최신버전인 2.0까지 지원하며, 하드웨어 가속을 받을 수 있게 된다. (나는 여기서 환성을 지를 수 밖에 없었다!! ㅡOㅡ)

Nehe 사이트의 OpenGL 튜토리얼 중 리눅스용 소스를 다운로드 받아 실행해보았다. 링크된 샘플 소스가 3가지였는데, 그 중 SDL을 이용한 OpenGL 소스를 컴파일해 실행하였고, 그 결과의 화면은 아래와 같다.


참고로 SDL은 Simple Direct-Media Layer 라이브러리의 약자로, Windows, 리눅스, BeOS, 맥등에서 적용할 수 있는 오픈소스 라이브러리이다. Simple하고 매우 직관적인 라이브러리인지라 접근하는데 매우 쉬울듯하다. SDL은 하드웨어 가속을 받는 비디오 관련 개발, CD-ROM 및 사운드와 동영상 분야의 멀티미디어 개발 등과 쓰레드, 타이머, 플렛폼마다 다른 엔디안 체계에 대한 비종속적인 환경 지원을 하고 있다.

작은 색의 차이가 엄청난 美적 차이를 만든다..

Vista로인해 말도 많은 ActiveX 컨트롤을 회사에서 하나 만들고 있고 있는데, 클라이언트 언어로 Visual Basic을 사용하다가, 이번에 C#으로 클라이언트 언어를 바꾸어 보다가 잠시 두손을 들게 되었다.

두손을 든 이유는 바로 Color이다. C++ ATL로 만든 ActiveX에서 사용하는 색상 Type은 Visual Baisc에서 OLE_COLOR이다. 이는 C++의 COLORREF Type에서 변환되어진 것일테고… 그런데 문제는 C#에서는 이렇게 넘어온 색상의 타입을 uint로 받는다.. 쿠궁~ ㅡOㅡ;;

뭐.. 색상 따위가.. 내 앞길을 막네? 건방진 것.. 하면서 간단히 형변환하면 되겠거니 하고.. C++와 Visual Basic의 RGB에 해당하는 C#의 함수를 만들었으니.. 다음과 같다.

uint RGB(int R, int G, int B) {
    return (uint)(Color.FromArgb(R, G, B).ToArgb());
}

ㅋㅋ.. 뭐 변환 과정이 한Q가 아닌 세Q인지라(FromArgb->ToArgb->uint) 뭔가 묘상하긴 했지만, 분명 작동할터라 기대하고 실행해 보니…… 그 색감이 아래와 같다.

안습.. ㅜ_ㅜ

원래 의도한 화면은 아래와 같은데 말이다… Visual Basic으로 맹근거..

막눈, 막귀인 내가 봐도 단지 색상만 다를 뿐, 그 뒷태, 앞태는 모두 같은데… 이처럼 큰 차이를 느끼게 한다는 것을 깨달았다…. UI에서 색상 고르기를 신부감 고르기보다 더 신중하게 하여야겠다… (피곤하니 글빨이 장난아닌데.. ㅡOㅡ;;)

아시는분…… RGB 요소의 값으로 ActiveX가 원하는 색상값을 C#에 옳바르게 넣어주는 방법은….?

가우스 분산(Gauss Distribution) 난수 발생

정규분포(Normal Distribution)이라고도 하는 이 정규분산을 이루는 난수 발생의 필요는 어떤 폴리곤 안에 무작위로 점을 찍어야할 경우에서이다.

처음의 접근은 단순히 폴리곤 안의 점을 무작위로 발생시켜 찍었으나, 폴리곤 안의 점들이 너무 고르게 분포되어져 있다는 문제점이 있었다. 폴리곤의 중심으로 점들이 몰리도록하는 방법이 무엇을까 생각해보니, 가우스분산을 이루도록 점들이 폴리곤안에 난수로 발생시키도록 하였다.

가우스분산을 이루는 난수발생…. 가우스분산이라는 정의를 곰곰이 들여다보면, 어떤 구간에서 그 구간의 중심점에 더 많은 빈도(가중치)가 몰린다는 것이다. 그렇다면 몇번의 난수를 발생시켜 그 평균을 구한다면, 그 값이 가우스분산을 이루는 난수가 아니겠는가?

아래는 이러한 생각에 의한 실제 구현된 코드이다.

double gaussDistributeRand(double begin, double end, size_t detail=5) {
    double r = 0;
    for(size_t i=0; i

인자 detail은 난수를 몇번 발생시켜 평균을 구할 것인가에 대한 것으로 이 값이 커질수록 난수발생값이 중심(평균)으로 집중하는 강도를 나타낸다.

실제로 위의 코드를 적용해서 detail을 1(가우스분산이 아닌 그냥 난수발생), 2, 4, 8, 20, 100으로 주었을때의 실행결과를 보면 아래와 같다.


이미 언급한것과 같이 결과에서도 알수있듯 detail값이 커질 수록 중심으로 난수발생값이 집중된다는 것을 알 수 있다.