ListView C# 공부하기

* 컬럼 헤더 보이기
View = View.Details

* 컬럼 헤더 추가
Columns.Add(....)

* 아이템 추가
Items.Add(...)

* 아이템의 서브아이템 추가
Items[n].SubItems.Add(...)

* 항목 지우기
Items.Clear();

ProgressBar C# 공부하기

Minimum, Maximum : 시작, 종료
Step : PerformStep() 호출 1회당 증가분
Value : 현재의 진행정도
Style : default, Continuous, Marquee

Form을 MDI 타입으로 변경 C# 공부하기

Form의 속성에서 IsMdiContainer를 True로 변경

* child form 제어

Form2 child = new Form2();
child.MdiParent = this;
child.Show();


ListBox 속성 C# 공부하기

* SelectedIndices : 선택된 항목들의 컬렉션(인덱스 리스트를 반환)

* Items.Count : 총 항목수

* Items.Add : 항목 추가

Form Event - Load, Closed, Closing C# 공부하기

1. Load : 로드되며 화면에 표시되기 직전
2. Closed : 폼이 닫힐 때
3. Closing : 폼이 닫히기 직전

TreeView Tag C# 공부하기

1. 생성 . Form에 트리뷰 컨트롤을 생성한다.

2. 속성->Nodes->컬렉션->... 을 선택하면 개별 노드의 속성을 지정할 수 있다.(Tag도 지정할 수 있다.)

3. TreeNode 클릭 이벤트

private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
TreeNode tNode = e.Node;
}

Menu 추가하기 C# 공부하기

1. 도구상자에서 폼에 MenuStrip이나 ContextMenuStrip을 끌어다 놓는다.

2.Context Menu를 추가하고 싶은 컨트롤(폼의 바탕, 리치에디트, 혹은 각종 컨트롤)의 속성의 ContextMenuStrip 항목을 연결해 준다.

File Dialog, Font Dialog, Color Dialog C# 공부하기

1. Open File Dialog

private void button1_Click(object sender, EventArgs e)
{
    OpenFileDialog openFileDialog1 = new OpenFileDialog();
    openFileDialog1.Filter = "All File|*.*";
    openFileDialog1.Title = "Select a File";

    if (openFileDialog1.ShowDialog() == DialogResult.OK)
        MessageBox.Show(openFileDialog1.FileName);
}

2. Save File Dialog

private void button2_Click(object sender, EventArgs e)
{
    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
    saveFileDialog1.Filter = "All file|*.*";
    saveFileDialog1.Title = "Select a File";

    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
        MessageBox.Show(saveFileDialog1.FileName);
}

3. Font Dialog

private void button3_Click(object sender, EventArgs e)
{
    FontDialog fontDialog1 = new FontDialog();
    if (fontDialog1.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show(Convert.ToString(fontDialog1.Font));
    }
}

4. Color Dialog

private void button4_Click(object sender, EventArgs e)
{
    ColorDialog colorDialog1 = new ColorDialog();
    colorDialog1.ShowDialog();
    MessageBox.Show(Convert.ToString(colorDialog1.Color));
}

RadioButton 컨트롤 C# 공부하기

1. 속성

Text : 보여지는 이름
Name : 컨트롤의 이름

2. Event

CheckedChanged
DataBinding
Disposed
Init
Load
PreRender
Unload

3. CheckedChanged 이벤트 핸들러

private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if(radioButton1.Checked == true) MessageBox.Show("radio1");
}


CheckBox 컨트롤 C# 공부하기

1. 속성

Text : 보여지는 이름
Name : 컨트롤의 이름

2. Event

CheckedChanged
DataBinding
Disposed
Init
Load
PreRender
Unload

3. CheckedChanged 이벤트 핸들러

private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
if (((CheckBox)sender).Checked)
{
}
}


Button 컨트롤 C# 공부하기

1. 속성

Text : 보여지는 이름
Name : 컨트롤의 이름
BackColor : 배경색
BackgroundImage : 이미지 사용
TabIndex : Tab 인덱스(포커스용)
FontColor : 폰트색상

2. Event

Click
Command
DataBinding
Disposed
Init
Load
PreRender
Unload

PerformClick C# 공부하기

// otherButton의 클릭 이벤트를 강제로 발생시킨다.
otherButton.PerformClick();

MessageBox 출력 C# 공부하기

// OK버튼만 가진 메시지 박스 출력
MessageBox.Show("Message Box");

// Yes, No 버튼을 가진 메시지 박스 출력
DialogResult result = MessageBox.Show("Yes, No?", "Test", MessageBoxButtons.YesNo);
if(result == DialogResult.Yes)
{
}

* MessageBoxButtons 상수

YesNo
YesNoCancel
OK
OKCancel
RetryCancel
AbortRetryIgnore

* MessageBoxIcon 상수

Asterisk
Error
Exclamation
Hand
Information
None
Question
Stop
Warning




TextBox 숫자 입력만 받도록 하기 C# 공부하기

// 정수형 값만 입력받도록 하기
private void textNum1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!(char.IsDigit(e.KeyChar) || e.KeyChar == Convert.ToChar(Keys.Back) || e.KeyChar == '-'))
{
e.Handled = true;
}
}

// 실수형 포함해서 입력받도록 하기
private void textNum1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!(char.IsDigit(e.KeyChar) || e.KeyChar == Convert.ToChar(Keys.Back) || e.KeyChar == '-' || e.KeyChar == '.'))
{
e.Handled = true;
}
}


기초 3 - reflection C# 공부하기

1. Reflection

// 어셈블리 로딩(filename : asname)
Assembly as1 = Assembly.LoadFrom(asname);

// 어셈블리로부터 Type 리스트 가져오기
Type[] types = as1.GetTypes();

// Type의 기본정보
foreach(Type t in types)
{
 Console.WriteLine(t.FullName); // 타입이름
 Console.WriteLine(t.BaseType); // 기본타입
 Console.WriteLine(t.IsClass); // 클래스인가?
 Console.WriteLine(t.IsSealed); // 추상클래스인가?
}

// Type의 멤버 얻어오기
MemberInfo[] mInfos = t.GetMembers();

// Type의 멤버타입
foreach(MemberInfo mInfo in mInfos)
{
 string str = "기타";
 if(mInfo.MemberType == MemberTypes.Field) {str = "필드";}
 if(mInfo.MemberType == MemberTypes.Method) {str = "메소드";}
 if(mInfo.MemberType == MemberTypes.Constructor){str = "생성자";}
 if(mInfo.MemberType == MemberTypes.Property) {str = "속성";}
 if(mInfo.MemberType == MemberTypes.Event) {str = "이벤트";}
 Console.WriteLine("{0} : {1}", str, mInfo.Name);
}

// field 리스트 가져오기
FieldInfo[] fInfos = t.GetFields();

// Method 리스트 가져오기
MethodInfo[] methodInfos = t.GetMethods();

// Method의 Parameter 리스트 가져오기
foreach(MethodInfo methodInfo in methodInfos)
{
 ParameterInfo[] pInfos = methodInfo.GetParameters();
}

// 생성자 리스트 가져오기
ConstructorInfo[] cInfos = t.GetConstructors();

// 속성 리스트 가져오기
PropertyInfo[] propertyInfos = t.GetProperties();

// 이벤트 리스트 가져오기
EventInfo[] eInfos = t.GetEvents();

// Type으로부터 오브젝트 생성
object o = Activator.CreateInstance(Type);

// Type의 메소드 실행
Type.InvokeMember(...); // MSDN 참조

2. 어트리뷰트

* 실행 시점에서 특정한 정보를 전달하기 위한 일종의 선언으로 어셈블리의
메타데이터에 함께 저장된다.

// Conditional
// 아래의 경우 DEBUG와 CDEBUG가 define되어있어야 아래의 함수가 유효하다.
// 또한, 클래스나 구조체의 메소드에만 사용 가능하다.
// 해당 메소드의 호출 명령 부분이 컴파일시 제외된다.
[Conditional("DEBUG"), Conditional("CDEBUG")]
public static void c1()
{
}

// DllImport
// Unmanaged 코드를 사용할 수 있도록 한다.
// MessageBox 원형의 파라메터는(HWND, LPCTSTR, LPCTSTR, UINT)이지만
// 아래와 같이 약간 다르게 extern으로 선언해서 사용할 수 있다.
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);

// Obsolete
[Obsolete ("Some Comment")]
public static void obsolete1()
{
}


기초 2 - 액세스한정자, 함수호출, 가변인수, 오버라이딩, delegate C# 공부하기

1. 액세스 한정자


public : 개방
protected: 상속 클래스에 개방
private : 클래스 외부사용 금지
internal : 어셈블리 내에서만 개방
protected internal : 어셈블리 내의 상속 클래스에만 개방

2. 함수호출

// 값으로 호출
static void byValue(MyType v)
{
v.value = 10;
}
// 참조로 호출
static void byReference(ref MyType r)
{
r.value = 10;
}
// 반환 호출
static void objOut(out MyType o)
{
o.value = 10;
}

3. 가변 인수

static void f1(params int [] args) // int타입의 인자들만 허용
{
}
static void f2(params object [] args) // 여러 타입의 인자들을 허용
{
}
static void f3(int [] args) // params 없이 배열도 허용
{
}
static void f3(ref int [] args) // ref type 허용
{
}
static void f3(out int [] args) // out type 허용
{
}

4. 오버라이딩

// base, derived가 선언되었다고 하고 다음과 같이 실행하면
derived d = new derived();
base b = d;
b. method();

// 1
class base
{
public virtual void method()
{
// 여기 온다.
}
}
class derived
{
public void method()
{
// 여기 안 온다.
}
}

// 2
class base
{
public virtual void method()
{
// 여기 안 온다.
}
}
class derived
{
public void override method()
{
// 여기 온다.
}
}

* Object의 ToString(), Equals(), GetHashCode()도 오버라이딩 가능하다.

5. IDisposable

Garbage Collection에 의해 회복되지 않는 자원을 가진 클래스는 IDisposable 을 상속하고 Dispose()를 정의한다.

6. implicit, explicit

// explicit : 소스를 대상의 형식으로 변환하는 것으로 캐스트를 통해 사용한다.
public static explicit operator Celsius(Farenheit f)
{
    return new Celsius((5.0f/9.0f)*(f.degrees-32));
}
// explicit 의 사용
Farenheit f = new Farenheit(100.0f);
Celsius c = (Celsius)f;

// implicit : C++의 operator 처럼 정의만 해 두면 특별한 표현식 없이 사용할 수 있다.
public static implicit operator double(Digit d)
{
return d.val;
}
public static implicit operator Digit(double d)
{
return new Digit(d);
}

7. Delegate

// delegate 선언
public delegate void myvoid1();

class Test
{
    // delegate 선언과 동일한 형태의 메소드
    public static void myvoid2()
    {
        Console.WriteLine("asdf");
    }

    public static void Main()
    {
        // delegate객체 생성
        myvoid1 mv1 = new myvoid1(myvoid2);
        // delegate객체 실행
        mv1();
    }
}

8. Delegate 연산

* delegate 여러개를 묶어서 실행 할 수 있다. 묶여진 delegate중 일부를 제거할 수도 있다. 

using System;
public delegate void myvoid1();

class Test
{
    public static void myvoid2()
    {
        Console.WriteLine("asdf");
    }
    public static void myvoid3()
    {
        Console.WriteLine("zxcv");
    }
    public static void Main()
    {
        myvoid1 mv1 = new myvoid1(myvoid2);
        myvoid1 mv2 = new myvoid1(myvoid3);
        myvoid1 mv3 = mv1 + mv2;
        myvoid1 mv4 = mv3 - mv1;
        mv1();
        mv2();
        mv3();
        mv4();
    }
}

// 결과
asdf // mv1
zxcv // mv2
asdf // mv3
zxcv //
zxcv // mv4

9. Delegate event

// delegate 선언
public delegate void dgate1(object sender, eArg1 e);

// event arg 재정의
public class eArg1 : EventArgs
{
    public string str;
    public eArg1(string str)
    {
        this.str = str;
    }
}

// messgae object 선언(버튼 비슷한 메시지 발생자)
class msgObject
{
    // 이벤트 선언 : 액세스 지정자 + event + delegate이름 + 이벤트 이름
    public event dgate1 evt1;
    public string Message
    {
        set
        {
            if(evt1 == null) return;
            evt1(this, new eArg1(value));
        }
    }
}

// handler test
class test
{
    public static void onHandler(object sender, eArg1 e)
    {
        Console.WriteLine("handler : {0}", e.str);
    }
    public static void Main()
    {
        msgObject obj1 = new msgObject(); // 메시지 오브젝트를 생성하고,
        obj1.evt1 += new dgate1(onHandler); // 오브젝트와 핸들러를 연결한 상태에서
        obj1.Message = "테스트"; // 메시지를 전송한다.
    }
}


몬테 크리스토. 영화

http://movie.daum.net/moviedetail/moviedetailMain.do?movieId=3443

아우... 책을 언제 읽은지도 까마득해서 내용도 기억 안났었는데...
(읽었는지 아닌지도 잘 모르겠...)

여하튼 '암굴왕'으로도 많이 알려진 몬테 크리스토?



곁 가지 별로 없이 결론으로만 쭈욱 달려가는데도 지루함은 별로 없었다.

다른 사람들 어찌 봤나 영화평을 봤더니 재미있다는 사람들도 있고,
원작과 많이 틀리다는 이야기도 많고(이건 소설을 영화로 만든 작품들에 공통적으로 쏟아지는 비평)...

책을 영화한편에 모두 담는 건 힘들겠지.. 아마...

기초 1 - enum, struct, 객체연산자, checked, unchecked, foreach C# 공부하기

1. enum type

// 선언
enum mytype1 { qwer, asdf, zxcv }
// 사용
Console.WriteLine(mytype1.qwer);
// 결과
qwer

별다른 정의 없이도 WriteLine을 통해 바로 출력이 가능한 점이 편해 보인다.
뭐... 숫자도 바로 출력 가능한가 보다.

int i1 = sizeof(int);
Console.WriteLine(i1);

2. struct type

// 선언
struct mystruct1
{
    public String str;
    public int n;
}
// 사용
mystruct1 st1;
st1.str = "qwerasdf";
st1.n = 32;

멤버변수 앞에 public을 선언하지 않으면 C의 struct처럼 자유롭게 접근하지 못한다.

3. 객체연산자

// 다음과 같은 클래스들을 선언하고
class ctype1{}
class ctype2 : ctype1{}

// new : *를 쓰지 않는다. delete는 없다.
ctype1 p1 = new ctype1();
ctype2 p2 = new ctype2();

// System.Object로 부터 파생되는 모든 클래스에 공통적으로 정의되는 mothods
bool bVal = p1.Equals(p1);
int nHashCode = p1.GetHashCode();
System.Type eType = p1.GetType();
String strVal = p1.ToString();

// typeof
if (p1.GetType() == typeof(ctype1))
{
    Console.WriteLine("equal");
}

// 강제 캐스팅
p2 = (ctype2)p1;

// is(is a kind of로 생각할 수 있다)
if (p2 is ctype1)
{
Console.WriteLine("p2 is ctype1"); // 여기 온다.
}
if (p2 is ctype2)
{
Console.WriteLine("p2 is ctype2"); // 여기도 온다.
}

// as(down-casting) : 실패하면 null이 넣어진다.
ctype1 p1new = p1 as ctype1;
ctype2 p2new = p1 as ctype2;
if (p1new == null)
{
Console.WriteLine("p1new is null"); // 여기 안온다.
}
if (p2new == null)
{
Console.WriteLine("p2new is null"); // 여기 온다.
}

// boxing, unboxing(성능희생이 있다)
int i = 123;
object o = (object)i;// boxing(힙에 개체 인스턴스가 생성되고 값이 복사된다, 타입 및 값을 보존한다)
o = 123;
i = (int)o;    // unboxing(호환되지 않는 타입이나 null을 unbox하려하면 exception)


4. cheched, unchecked

아래와 같이 {,} 로 감싸준 부분에서 overflow발생 시 exception을 발생시킬지 아닐지를 결정할 수 있다.

checked
{
  ...
}
unchecked
{
 ...
}

5. foreach

* 배열, .NET Framework 컬렉션 클래스 또는 IEnumerable 인터페이스를 구현하는 임의의 클래스나 구조체에 대하여 사용할 수 있다.

// 테스트
class ForEachTest
{
    static void Main(string[] args)
    {
        int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
        foreach (int i in fibarray)
        {
            System.Console.WriteLine(i);
        }
    }
}

// 결과
0
1
2
3
5
8
13




C# 시작하기. C# 공부하기

1. C# 실행환경

* 소스코드(C#, VB, ...)를 각각의 컴파일러에 의해 MSIL(MS Intermediate Language)로 변경시킨 후.
* 각 플랫폼마다 준비된 CLR(Common Language Runtime)에 의해 MSIL을 구동한다.

응??? JVM과 다른게 뭐냐.
OpenGL의 오른손좌표계를 굳이 무시하고, Direct3D를 왼손좌표계로 만들던 MS의 모습이 여기서도 또 나온건지도...
여하튼 닷넷 프레임워크가 설치된 환경에서 아래의 닷넷 어셈블리 형태가 실행 가능해진다.

2. 닷넷 어셈블리

매니페스트 +
형식 메타데이터 +
MSIL +
리소스

VS에 포함된 IL 디스어셈블러를 통해 닷넷 어셈블리의 내용을 확인할 수 있다.



Objective-C 간단 정리 [3] - 클래스 확장 y

1. 카테고리 확장

기존의 클래스에 메소드만을 추가하는 클래스 확장 방법이다.

@interface obj1 (category1)
{
method declarations...
}
@end

@implementation obj1 (category1)
method definitions...
@end

obj1은 기존에 정의된 클래스이며, category1은 사용자가 정의한 이름을 넣는다.
내부를 비우고 ()로만 카테고리 확장을 하는 것도 가능하다.

또한 카테고리 확장 시에 기존의 메소드와 같은 이름을 가진 메소드를 정의하게 되면 오버라이딩 하게 된다.



13계단. 영화

http://movie.daum.net/moviedetail/moviedetailMain.do?movieId=39546

이렇게 긴장감 있고 박진감 넘치는 영화. 액션영화도 아닌데 말이지....

진지하게 볼 만한 영화를 원한다면 이 영화 괜찮다.

글 쓰려다 보니...

스포는 없다.

별 네개 반.



Objective-C 간단 정리 [2] - Messaging y

1. class method, instance method

메소드 선언 앞에 붙이는 +, -로 구분하며 +는 class method, -는 instance method이다.
instance method는 멤버함수, class method는 static함수로 생각할 수 있다.

2. method(멤버함수) 정의

// void method1();
-(void)method1;
// void method2(int param1);
-(void)method2 : (int)param1;
// void method3(int param1, int param2);
// andOther1은 키워드가 아니며 Messaging시 파라메터 호출을 위해 필요하다.
-(void)method3 : (int)param1 andOther1:(int)param2 ;
// int method4(int param1);
-(int)method4 : (int)param1;

3. method 구현

-(void)method1{}
-(void)method2 : (int)param1{}
-(void)method3 : (int)param1 andOther1: (int)param2{}
-(int)method4 : (int)param1{return 0;}

4. method 호출(Messaging)

[receiver method]

[]도 낯설고 C++과 말이 달라 혼동이 되는데, 일단 C++의 receiver->method()라고 생각하면 틀리지 않다.

[obj1 method1];
[obj1 method2 : 0];
[obj1 method3 : 0 andOther1:1]; // 함수 정의에 만들었던 파라메터 구분자(?)
int n1 = [obj1 method4 : 0];


5. 겹치기 호출

겹치기도 가능하다.
receiver1의 method1은 method2 라는 메소드를 가진 객체이어야만 아래와 같이 겹쳐서 호출하는 것이 가능하다.

[[receiver1 method1] method2]

6. Selector

다음과 같이 조금 특이한 모습을 한 호출 방법이 있다.

[obj1 performSelector:@selector(method1:) withObject:param1];

@selector()는 다음과 같이 쓸 수 있는데,

SEL cbMethod1 = @selector(method1);

쓰이는 모양이 함수 포인터와 닮아있다. performSelector는 selector를 실행하라는 명령이 된다.
또한 다음과 같이 selector가 사용 가능한지 검사해 보는 방법도 있다.

if([obj1 respondsToSelector:@selector(method1:)]) {...}

7. self, _cmd

self : this와 마찬가지로 자기 자신을 가르킨다. 다만 클래스 메소드에서 쓰이면 클래스를, 다른 경우에는 인스턴스를 가르킨다.
_cmd : 호출된 method에 대한 selector를 가진다.(callee)

id objID = getTheReceiver();
SEL objSelector = getTheMethod();

Objective-C 간단 정리 [1] - 객체 y

1. 특징

- 다중 상속을 지원하지 않는다.
- method overriding 은 지원된다.
- operator overloading 은 지원되지 않는다.

2. 인터페이스 정의

@interface obj1 : NSObject
{
}
@end

@interface, @end 로 감싼 내부에 인터페이스를 정의한다.

3. instance method

@interface obj1 : NSObject
{
NSString* m_strName;
}

- (NSString*)m_strName; // instance method(getter의 역할을 한다.)

@end

위와 같이 정의함으로써 getter 메소드를 따로 정의할 필요가 없어진다.
사용은 다음과 같이 해준다.

obj1 myObj;
[myObj m_strName];

4. id, nil

id는 모든 객체타입을 모두 포인팅 할 수 있는 타입으로 void* 와 매우 유사하다.
다음과 같이 사용할 수 있다.

id anyObj1 = [[obj1 alloc] init];

id의 값을 NULL과 같은 nil로 지정해 줄 수도 있다.

id nullObj1 = nil;

5. isMemberOfClass, isKindOfClass, NSClassFromString

RTTI와 같은 역할을 하며 다음과 같이 쓰인다.

if([obj1 isMemberOfClass:superObj1]) ...
if([obj1 isKindOfClass:superObj1]) ...

다음은 클래스 이름으로부터 클래스 타입을 반환한다.

NSClassFromString(classname)

6. Class Type

RTTI의 연장선에 있는 것으로 생각되며 다음과 같이 쓴다.

id objClass = [obj1 class]; // 클래스 타입으로부터
id objClass2 = [aObj1 class]; // 클래스 객체로부터

아예 클래스 타입만을 나타내도록 해주는 Class를 쓸 수도 있다.

Class objClass = [obj1 class];
Class objClass2 = [aObj1 class];

6. static 변수

static변수는 상속되지 않는다.

@interface obj1
{
static int m_sStatic;
}

7. initialize, init

+initialize : 클래스 객체 초기화, 반드시 구현할 필요는 없다.
-init : 인스턴스 객체 초기화

8. forward declaration

다음과 같이 @class 를 사용해서 어딘가에 정의되어 있다고 선언해 줄 수 있다.
C++과 마찬가지로 선언만으로는 제대로 사용할 수 없다. 그렇게 하기 위해서는 #import를 통해 모두 가져와야 한다.

@class otherObj1;

9. Scope

C++과 마찬가지로 아래의 지시자를 쓰고 그 아래에 해당하는 스코프의 변수들을 선언할 수 있다.

@private
@protected
@public

수동으로 ipa 파일 만들기 y

디바이스 등록을 하지 않은 상태에서 기기에서 실행하기 위한 ipa 파일 만들기


1. 빌드된 application(device로 컴파일 된 어플리케이션)

2. Payload 디렉토리를 만들고 그곳에 application을 카피한다.

3. ditto -c -k --keepParent ./Payload [appname].ipa


물론 해킹된 기계에서만 실행할 수 있다.


device 컴파일 하기 y

1. 인증서 만들기.
 Name(이름)은 'iPhone Developer' 로 틀리지 않도록 적어준다..
 유형은 '코드 서명' 타입으로 선택한다. 
 인증서는 '로그인' 키체인에 존재해야 한다.
 다른 옵션들은 디폴트로 선택한다.

2. Info.plist 수정.
 /Developer/Platforms/iPhoneOS.platform/Info.plist 에서  
 XCiPhoneOSCodeSignContext 를 XCCodeSignContext 로 바꾸어 준다(두 개 있는데 모두 변경). 


cpp 소스 사용하기 y

소스 클래스의 확장자를
.m 에서 .mm으로 바꿔준다.
이것으로 컴파일이 다 되는 모양이다. ㅋ

CMFCPropertyGridCtrl 메시지 처리하기 MFC Feature Pack

// 선언
afx_msg LRESULT OnPropertyChanged(WPARAM wparam, LPARAM lparam);

// 메시지 맵
BEGIN_MESSAGE_MAP(Page1, PropertyPageBase)
ON_REGISTERED_MESSAGE(AFX_WM_PROPERTY_CHANGED, OnPropertyChanged)
END_MESSAGE_MAP()

// Property 추가
CMFCPropertyGridProperty* pProp1 = new CMFCPropertyGridProperty(strTitle, (_variant_t)bVal, strDesc);
assert(pProp1 );
if(pProp1  == 0) return false;
pProp1->SetData(100); // 메시지 구분을 위해 사용한다.
m_wndPropList.AddProperty(pProp1);

// 메시지 처리
LRESULT Page1::OnPropertyChanged(WPARAM wparam, LPARAM lparam)
{
CMFCPropertyGridProperty *pProp = (CMFCPropertyGridProperty*)lparam;
if (!pProp) return 0;

switch(pProp->GetData())
{
case 100:
// 메시지 처리
break;
}
}

////////////////////////////////////////////////////////////////////////////////////////////
// Boolean 속성
////////////////////////////////////////////////////////////////////////////////////////////
// 생성
CMFCPropertyGridProperty* pBooleanProp1 = new CMFCPropertyGridProperty(strTitle, (_variant_t)true or false, strDesc);
pBooleanProp1->SetData(dwID);
m_wndPropList.AddProperty(pBooleanProp1);
// 속성 지정
CMFCPropertyGridProperty* pBooleanProp1 = m_wndPropList.FindItemByData(dwID);
pBooleanProp1->SetValue((_variant_t)true or false);
// 속성 가져오기
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BOOL);
#pragma warning(disable:4800)
bool bVal = (bool)v.boolVal;
#pragma warning(default:4800)

////////////////////////////////////////////////////////////////////////////////////////////
// Dropdown Combobox
////////////////////////////////////////////////////////////////////////////////////////////
// 생성 : 초기값이 옵션에 없어도 초기값으로 출력됨, 이 경우 초기값은 추가되지 않고 콤보박스에서 선택안됨
CMFCPropertyGridProperty* pDropdownCombo1
= new CMFCPropertyGridProperty(_T("타이틀"), _T("초기값"), _T("설명"));
pDropdownCombo1->AddOption(_T("옵션1"));
pDropdownCombo1->AddOption(_T("옵션2"));
pDropdownCombo1->AllowEdit(FALSE);
pDropdownCombo1->SetData(dwID);
m_wndPropList.AddProperty(pDropdownCombo1);
// 속성 지정
CMFCPropertyGridProperty* pDropdownCombo1 = m_wndPropList.FindItemByData(dwID);
pDropdownCombo1->SetValue(_T("옵션2"));
// 속성 가져오기
USES_CONVERSION;
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BSTR);
CString strW = OLE2W(v.bstrVal);

////////////////////////////////////////////////////////////////////////////////////////////
// Integer
////////////////////////////////////////////////////////////////////////////////////////////
// 생성 : 초기값 또는 속성 지정시에 int 또는 long int형을 혼용하지 말고 한 가지로 통일해서 써야 한다.
// 다른 데이터형에 대한 경우에도 물론 혼용은 하지 않는다.
// 기본값이 아닌 값에 대해 bold로 표시하고 싶은 경우는 long int형을 써야 한다.
// 다만 Spinner 속성을 지정하는 경우에는 아무때나 int를 써도 무방하다.
CMFCPropertyGridProperty* pIntegerProp1 = new CMFCPropertyGridProperty(strTitle, (_variant_t)(long int)nVal, strDesc);
pIntegerProp1->AllowEdit(TRUE); // or FALSE
pIntegerProp1->SetData(dwID);
pIntegerProp1->EnableSpinControl(TRUE, -10, 10);
m_wndPropList.AddProperty(pIntegerProp1);
// 속성 지정
CMFCPropertyGridProperty* pIntegerProp1 = m_wndPropList.FindItemByData(dwID);
pIntegerProp1->SetValue((_variant_t)(long int)nVal);
// 속성 가져오기
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_I4);
#pragma warning(disable:4800)
int nVal = (int)v.intVal;
#pragma warning(default:4800)

////////////////////////////////////////////////////////////////////////////////////////////
// Float
////////////////////////////////////////////////////////////////////////////////////////////
// 생성
CMFCPropertyGridProperty* pFloatProp1 = new CMFCPropertyGridProperty(strTitle, (_variant_t)fVal, strDesc);
pFloatProp1->AllowEdit(TRUE); // or FALSE
pFloatProp1->SetData(dwID);
m_wndPropList.AddProperty(pFloatProp1);
// 속성 지정
CMFCPropertyGridProperty* pFloatProp1 = m_wndPropList.FindItemByData(dwID);
pFloatProp1->SetValue((_variant_t)fVal);
// 속성 가져오기
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_R4);
#pragma warning(disable:4800)
float fVal = (float)v.fltVal;
#pragma warning(default:4800)

///////////////////////////////////////////////////////////////////////////////////////////////////
// Text Edit
///////////////////////////////////////////////////////////////////////////////////////////////////
// 생성
CMFCPropertyGridProperty* pStringProp1 = new CMFCPropertyGridProperty(strTitle, (_variant_t)strVal, strDesc);
pStringProp1->AllowEdit(TRUE); // or FALSE
pStringProp1->SetData(dwID);
m_wndPropList.AddProperty(pStringProp1);
// 속성 지정
CMFCPropertyGridProperty* pStringProp1 = m_wndPropList.FindItemByData(dwID);
pStringProp1->SetValue((_variant_t) strVal);
// 속성 가져오기
USES_CONVERSION;
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BSTR);
CString strW = OLE2W(v.bstrVal);

////////////////////////////////////////////////////////////////////////////////////////////
// Font : 속성 변경시 메시지가 여러 번 온다.
////////////////////////////////////////////////////////////////////////////////////////////
// 생성
CMFCPropertyGridFontProperty* pFont1
= new CMFCPropertyGridFontProperty(strTitle, LOGFONT, CF_EFFECTS | CF_SCREENFONTS, strDesc);
pFont1->SetData(dwID);
LOGFONT* pFont = pFont1->GetLogFont();
COLORREF hColor = pFont1->GetColor();
memcpy(pFontOut, pFont, sizeof(LOGFONT)); // 폰트속성 저장(땜빵해주기)
*pColorOut = hColor; // 폰트색상 저장(땜빵해주기)
m_wndPropList.AddProperty(pFont1);
// 속성 지정
CMFCPropertyGridFontProperty* pFontProp1 = (CMFCPropertyGridFontProperty*)m_wndPropList.FindItemByData(dwID);
LOGFONT* pFont = pFontProp1->GetLogFont();
lstrcpy(pFont->lfFaceName, strW); // 속성 지정(API를 통하지 않고 직접 수정한다)
m_wndPropList.UpdateData(FALSE); // 속성 업데이트
*pColorOut = pFontProp1->GetColor(); // 폰트속성 저장(땜빵해주기)
memcpy(pFontOut, pFont, sizeof(LOGFONT)); // 폰트색상 저장(땜빵해주기)
// 속성 가져오기
USES_CONVERSION;
LPLOGFONT pFont1;
COLORREF FontColor1;
COleVariant rVariant = pFontProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BSTR);
LOGFONT* pFont1 = pFontProperty->GetLogFont();
COLORREF hColor = pFontProperty->GetColor();
if(hColor != *pColorOut || (memcmp(pFontOut, pFont1, sizeof(LOGFONT)) != 0))
{
// 이벤트 처리(이전에 저장해둔 값들과 틀린 경우)
}

////////////////////////////////////////////////////////////////////////////////////////////
// Color
////////////////////////////////////////////////////////////////////////////////////////////
// 생성
CMFCPropertyGridColorProperty* pColor1 = new CMFCPropertyGridColorProperty(strTitle, hColor, NULL, strDesc);
pColor1->SetData(dwID);
pColor1->EnableOtherButton(_T("기타...")); // "기타..." 버튼을 활성화 시킴
pColor1->AllowEdit(TRUE);
m_wndPropList.AddProperty(pColor1);
// 속성 지정
CMFCPropertyGridColorProperty* pColorProp1 = (CMFCPropertyGridColorProperty*)m_wndPropList.FindItemByData(dwID);
pColorProp1->SetColor(hColor);
// 속성 가져오기
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_I4);
COLORREF hColor = pProperty->GetColor();

////////////////////////////////////////////////////////////////////////////////////////////
// File Select, Folder Select : 처음 메시지가 두 번 오는 경우가 허다하다. 두 번째 부터는 제대로 오는 듯 하다.
////////////////////////////////////////////////////////////////////////////////////////////
// 생성
// File select
CMFCPropertyGridFileProperty* pFileSelect1
= new CMFCPropertyGridFileProperty(strTitle, TRUE, _T(""), 0, 0, strFilter, strDesc);
// Folder select
//CMFCPropertyGridFileProperty* pFileSelect1 = new CMFCPropertyGridFileProperty(strTitle, strInitialFolder);
pFileSelect1->SetData(dwID);
USES_CONVERSION;
wchar_t wbuf[1024];
COleVariant rVariant = pFileSelect1->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BSTR);
swprintf_s(wbuf, L"%s", OLE2W(v.bstrVal));
CStringW strW = wbuf; // Font 의 경우처럼 미리 저장해 놓는다.
m_wndPropList.AddProperty(pFileSelect1);
// 속성 지정
CMFCPropertyGridFileProperty* pFile1 = (CMFCPropertyGridFileProperty*)m_wndPropList.FindItemByData(dwID);
pFile1->SetValue((_variant_t)strFile);
CStringW strW = strFile; // 속성을 따로 저장
// 속성 가져오기
USES_CONVERSION;
wchar_t wbuf[1024];
COleVariant rVariant = pProperty->GetValue();
VARIANT v = rVariant.Detach();
VARTYPE vt = v.vt;
assert(vt == VT_BSTR);
swprintf_s(wbuf, L"%s", OLE2W(v.bstrVal));
CString strFile1 = wbuf;
if(strW != strFile1)
{
// 이벤트 처리(이전에 저장해둔 값들과 틀린 경우)
strW = wbuf;
}


폰트, 파일 관련 프로퍼티 변경시, 한 번의 이벤트에 메시지가 여러 번 온다.
패치 안되나...

여튼 땜질 예제..SDI.zip

CMFCPropertyGridCtrl MFC Feature Pack


// 선언
CMFCPropertyGridCtrl m_wndPropList;

// 생성
CRect rectDummy;
rectDummy.SetRectEmpty();
if (!m_wndPropList.Create(WS_VISIBLE | WS_CHILD, rectDummy, this, IDD_DUMMY_PROPERTYSHEET))
{
return -1;
}
m_wndPropList.EnableHeaderCtrl(FALSE);
m_wndPropList.EnableDescriptionArea();
m_wndPropList.SetVSDotNetLook();
//m_wndPropList.MarkModifiedProperties();

// 크기 조절(OnSize 또는 기타 적당한 위치에서)
m_wndPropList.SetWindowPos(NULL, rRect.left, rRect.top, rRect.Width(), rRect.Height(), SWP_NOACTIVATE | SWP_NOZORDER);

쉽다.
상당히 쓸모있는 것인데, MFC 추가가 너무 늦게 된 듯 하다.

CDockablPane에 콤보박스 추가하기 MFC Feature Pack



// 리소스 에디터로부터 만들어지지 않은 컨트롤
#define MYCOMBO1_ID 1000

class CMyDockRight : public CDockablePane
{
DECLARE_MESSAGE_MAP()

public:
CMyDockRight() {}
virtual ~CMyDockRight() {}

protected:
// 리소스 에디터로부터 만들어지지 않았기 때문에,
// 초기 값 및 Pane의 크기 변경에 따른 레이아웃 조정이 필요하다
void adjustLayout();

protected:
// 콤보박스 선언
CComboBox m_ComboBox1;

public:
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnCombo1(); // 수동 입력

}; // class CMyDockRight


BEGIN_MESSAGE_MAP(CMyDockRight, CDockablePane)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_SIZE()
ON_CBN_SELCHANGE(MYCOMBO1_ID, OnCombo1) // 수동입력
END_MESSAGE_MAP()

void CMyDockRight::OnPaint()
{
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect); 
dc.FillRect(&rect, &CBrush(RGB(128, 128, 128)));
}

int CMyDockRight::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDockablePane::OnCreate(lpCreateStruct) == -1)
return -1;

CRect rectDummy;
rectDummy.SetRectEmpty();

// 콤보박스 생성
if(!m_ComboBox1.Create(
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
WS_BORDER | CBS_SORT | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
rectDummy, this, MYCOMBO1_ID))
{return -1;}

// 콤보박스 폰트 변경
m_ComboBox1.SetFont(CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT)));

// fill dummy values
m_ComboBox1.AddString(_T("ComboItem1"));
m_ComboBox1.AddString(_T("ComboItem2"));
m_ComboBox1.SetCurSel(0);

// adjust layout
adjustLayout();

return 0;
}

void CMyDockRight::adjustLayout()
{
if(GetSafeHwnd() == NULL) return;

CRect rectClient;
GetClientRect(rectClient);
m_ComboBox1.SetWindowPos(NULL,
rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(),
SWP_NOACTIVATE | SWP_NOZORDER);

}

void CMyDockRight::OnSize(UINT nType, int cx, int cy)
{
CDockablePane::OnSize(nType, cx, cy);
adjustLayout();
}

void CMyDockRight::OnCombo1()
{
int nSel = m_ComboBox1.GetCurSel();
switch(nSel)
{
case 0:
break;
case 1:
break;
}
}

CDockablePane에 Icon 추가하기 MFC Feature Pack

적당한 위치에서 일단 아이콘을 로드한다.

HICON hFileViewIcon = (HICON)::LoadImage(
::AfxGetResourceHandle(),
MAKEINTRESOURCE(theApp.m_bHiColorIcons ? IDI_ICON_PANE0_HC : IDI_ICON_PANE0),
IMAGE_ICON,
::GetSystemMetrics(SM_CXSMICON),
::GetSystemMetrics(SM_CYSMICON),
0);

아이콘은 미리 제작되어 있어야 한다.

IDI_ICON_PANE0_HC  --> 하이컬러
IDI_ICON_PANE0 --> 팔레트 형식의 예전 스타일

theApp.m_bHiColorIcons 에 따라 선택해서 사용한다. 물론 theApp는 CWinAppEx의 글로벌 객체이다.

이제 생성된 CDockablePane 객체에 다음과 같이 아이콘을 지정해 줄 수 있다.

m_Panes[0].SetIcon(hFileViewIcon, FALSE);
DockPane(&m_Panes[0]);

DockPane() 이전에 아이콘을 지정해 주는 것이 좋다.
DockPane() 이후에 아이콘을 지정해 주면 스트링만으로 Tab의 크기를 계산한 이후에 스트링 앞에 아이콘을 붙여주기 때문에, 스트링이 모두 표시되지 않기 때문이다. "Pan..." 형태로 마감된다.

물론 사용자가 Dock상태를 이리저리 변경시킬 때마다 Tab크기가 다시 계산되므로 스트링이 정상적으로 표시된다.


1 2