반응형

함수는 스택에 쌓인다

 

함수를 호출할때 쌓이는 것은

 

1. 함수 호출 인자

2. 리턴할 주소

3. 함수내의 지역변수

 

함수가 종료될때 시스템 스택에서 위 3가지가 제거된다

 

 

그런데 재귀호출이무한히 반복되면 스택에서 제거되지 않고 계속 쌓이다 보니 오버플로우가 발생 된다

반응형
반응형

반응형
반응형



http://ezbeat.tistory.com/206

 

1. 종료 핸들러

종료 핸들러는 __try와 __finally로 이루어져 있습니다.

__try{
        Ezbeat 루틴
}
__finally{
        Hacker 루틴
}
코드를 보시면 __try안으로 들어와서 Ezbeat루틴을 실행하게 되면 __try루틴을 빠져나올 때 항상 __finally루틴을 실행하게 됩니다. 위 코드는 너무 추상적 이므로 직접 소스를 짜서 보도록 하겠습니다.

두 수를 입력 받아서 나누는 프로그램 입니다.

위 소스코드에서는 2가지 실험 결과를 통해 이해를 하실 수 있습니다. 결과를 보시겠습니다.


첫번째 결과에서는 9와 3을 나눠서 Result가 3이었습니다. 
__try를 빠져나오면서 __finally에 있는 코드를 실행 한 것을 볼 수 있습니다.

두번째 결과를 보시면 5와 5를 나눠서 Result가 1이었습니다.
그러면 __try에 있는 if문안으로 들어오게 됩니다. 리턴을 하게 되면서 main함수가 종료가 되겠지요.
하지만 __finally에 있는 코드는 여전히 실행을 하게 됩니다.

위 소스코드와 결과만 봐도 이해를 하셨을 것입니다. 그러면 __try루틴에 들어오게 되면 반드시 __finally루틴이 실행되느냐..
그건 아닙니다. 모든과정에 예외가 있듯이 이것도 예외가 있습니다.

몇몇 종료 함수들을 사용하게 되면 __finally루틴으로 들어오지 않고 프로그램이 끝나게 됩니다.
( ExitProcess, ExitThread, exit .. )
소스코드와 결과를 보시겠습니다.

return부분을 ExitProcess함수로 바꾸었습니다.

결과를 보면 __finally루틴으로 들어오지 않고 종료가 된 것을 볼 수 있습니다.

결론입니다.
__try 루틴을 빠져나오는 경우 ( __finally 루틴 실행 함 )   : return, continue, break, goto, 예외발생
__try 루틴을 빠져나오는 경우 ( __finally 루틴 실행 안함) : ExitProcess, ExitThread, TerminateProcess, exit

상황에 맞게 적절히 종료 핸들러를 사용해 더욱 깔끔한 소스코드를 짜보세요 ^^

2. 예외 핸들러
예외 핸들러는 __try와 __except로 이루어져 있습니다.
__try{
      예외발생 루틴
}
__except(예외처리 방식){
      예외가 발생됬을 때 처리하는 루틴
}
__try 안에서 예외가 발생하면 예외처리 방식에 따라 해당 예외를 처리하게 됩니다.

예외처리 방식에 올 수 있는 경우의 수는 3가지 입니다.
EXCEPTION_EXECUTE_HANDLER : 예외가 발생하면 __try루틴의 나머지 부분을 실행하지 않고 예외처리 루틴으로 감
EXCEPTION_CONTINUE_EXECUTION : 예외가 발생한 지점으로 돌아가 다시 실행하도록 하는 방식
EXCEPTION_CONTINUE_SEARCH : 함수가 호출된 순서를 바탕으로 예외핸들러를 다시 찾아서 예외처리 해라

보통 많이 쓰이는 것은 위 2가지 이고 마지막은 잘 쓰지 않습니다.
먼저 각각의 경우를 소스코드를 짜서 보여드리도록 하겠습니다.
EXCEPTION_CONTINUE_SEARCH 경우는 잘 쓰지 않으므로 설명은 따로 하지 않겠습니다.

ㄱ. EXCEPTION_EXECUTE_HANDLER

위 소스코드와 크게 다른 것은 없습니다. try에서 예외를 발생시켰을 때와 안시켰을 때의 결과를 보도록 하겠습니다.

예외발생 안시켰을 때


예외발생 시켰을 때


예외를 발생시키면 __try에서 남은 코드를 실행 시키지 않고 바로 예외처리 루틴으로 가게 되는 것을 볼 수 있습니다.

ㄴ. EXCEPTION_CONTINUE_EXECUTION

소스코드가 약간 복잡합니다.

출력 결과를 본 후에 설명을 하도록 하겠습니다.

처음에 5와 0을 입력 했더니 예외가 발생해서 Func함수로 들어왔습니다. (GetExceptionCode는 뒤에서 설명하겠습니다.)
해당 예외가 정수를 0으로 나눴을 때 발생한 예외이므로 if문 안으로 들어오게 됩니다.
안에서 입력받는 수가 두개의 정수를 다시 입력 받는게 아니라 뒤에 들어온 수만 입력을 받고 있습니다.

여기서 궁금하신 분이 계실 것입니다. 두 수를 전부다 입력 받아도 되겠지..라고 생각하신 분들이 계실 것입니다.
제가 테스트를 해보았습니다.

Func함수 내부를 살짝 바꾸었습니다. 두 수를 입력 받도록 되어 있습니다. 출력 결과를 보도록 하겠습니다.

마지막 결과를 따르면 Result가 3이 나와야 할 탠데 결과는 5가 나왔습니다.
첫번째 값은 계속 넣어도 무용지물인지에 대해 알아본 결과

예외가 발생한 이후에 나눗셈을 할 때 첫번째 수는 처음 입력한 수를 특정 메모리에 넣어두고 
정상적인 나눗셈을 수행할 때 처음 입력했던 값을 EAX레지스터로 옮긴다음에 두번째 수와 나눗셈을 수행하게 됩니다.
( 메모리에 넣어둔 값을 EAX로 옮기는 과정은 커널영역에서 하는 것 같습니다. )

이 부분은 이해하기가 어려우므로 그냥 그런다고 넘어가시면 됩니다.
쫌더 쉽게 말해보면 두 수를 나눌 때 처음 입력 받은 수는 특정 메모리에 저장되어 있다가 
다시 나눗셈을 수행할 때 가져와서 두번째 수와 나눗셈을 수행한다는 것입니다.
아래그림을 보시면 어느정도 이해가 되실 것입니다.


이정도면 이해가 되셨을꺼 같으니 결론을 내보면 EXCEPTION_CONTINUE_EXECUTION 옵션은 예외가 발생한 지점으로 다시 가서 코드를 실행하라는 뜻이됩니다.

위에서 설명하겠다고 한 GetExceptionCode입니다.
GetExceptionCode은 함수가 아닌 메크로 입니다. 예외가 발생했을 때 어떠한 예외가 발생했는지 알려주는 메크로 입니다.
많은 경우의 수가 있는데
위 링크로 가시면 볼 수 있습니다.

이러한 예외처리 방법을 코드상에서 많이 볼 수 있는데 알고있으면 좋을것 같아서 한번 써보았습니다.
그리고 이러한 예외처리 방법을 사용한 안티리버싱 기법도 있습니다.


반응형
반응형


  1. Structured Exception Handling
  2. Termination Handling
  3. Exception Handling
  4. Stack Unwind
    1. Local Unwind
    2. Global Unwind
  5. Unhandled Exception
  6. First and Second Chance Exception
  7. 링크



1 Structured Exception Handling

  • 윈도우즈에서 제공하는 예외 처리 방식이다. (사실 실제 구현은 컴파일러에서 이루어진다.) 
  • C++ 예외와는 다른 것이다. 
  • 윈도우즈 상에서는 C++ 스탠다드 라이브러리도 내부적으로 SEH를 이용한다. 
  • C++ 예외 처리는 당연히 C++에서만 사용할 수 있으나, SEH는 언어 중립적이기 때문에 다른 언어에서도 사용 가능하다. 
  • Termination Handling과 Exception Handling으로 분류할 수 있다. 


2 Termination Handling

    __try { // Guarded code } __finally { // Termination handler }
    finally 블록 안의 안의 코드는 try 블록 안에서 무슨 짓을 하든 반드시 실행된다. try 블록 안에서 return을 해도, goto를 해도, longjump 명령을 직접 호출해도, 결국은 실행된다. 좀 더 자세하게 말하자면, return이나 goto를 하기 직전에 finally 블록 안의 코드가 실행된다. (exit, abort, ExitProcessTerminateThread 등을 통해 프로세스나 스레드가 종료되는 경우는 예외다. 이런 경우에는 finally 블록의 코드가 실행되지 않는다.) 

    try 블록 안에서 return, goto, longjump 등을 사용하는 것은 자제하는 것이 좋다. 반환값 문제 때문에 컴파일러가 추가적인 코드를 만들어내기 때문이다. 이 코드의 양은 CPU마다 틀려지는데, 수백에서 수천 사이클까지 걸리는 경우가 있다. 그러므로 자주 사용하는 코드에다가 집어넣어 놓으면 프로그램의 성능이 심각한 수준까지 떨어질 염려가 있다. 

    코드의 흐름이 자연스레 finally 블록까지 흘러가는 경우(return 등을 사용하지 않는 경우), 오버헤드는 거의 없다. x86 계열의 CPU에서 마이크로소프트 컴파일러를 사용한 경우, 단 하나의 명령어를 실행할 뿐이다. 

    일반적으로 가장 좋은 방법은 try 블록 안에서 return, continue, break, goto 문 등을 쓰지 않는 것이다. 이들은 try 블록 바깥 쪽으로 빼내줘야 한다. 그래도 어쩔 수 없이 try 블록을 빠져나가고자 한다면 __leave 키워드를 사용하면 된다. 
    bool some_function(const char* param) {
    	 bool bOK = false;
    	 char* pBuffer = NULL; ... 
    	__try { 
    		pBuffer = new char[100];
    		 if (pBuffer == NULL) { 
    			// return false; 
    			// 여기서 false를 리턴할 것이 아니라, __leave를 사용한다.
    			__leave; 
    		}
    		 bOK = true; 
    	} 
    	__finally { 
    		if (pBuffer) 
    			delete [] pBuffer; 
    	} 
    	return bOK; }
    __leave 키워드를 사용하면, 코드의 흐름(instruction pointer)이 try 블록이 끝나는 곳(__finally 바로 앞의 괄호)으로 이동한다. 그 다음 finally 블록 안의 코드가 자연스레 실행된다. 위에서도 언급했듯이 자연스러운 이동은 성능에 영향을 거의 주지 않는다. 


3 Exception Handling

    __try { // Guarded code }
     __except (EXCEPTION_EXECUTE_HANDLER) // Exception filter 
    { // Exception handling code }
    except 부분은 C++ 예외 처리 구문의 catch와 비슷해 보이지만, 다르다. C++ 예외 처리에서는 이 부분에 예외의 종류 밖에 들어갈 수 없지만, SEH에서는 exception filter라고 불리는 C 구문(expression)이 들어간다. exception filter 구문은 계산을 거친 후, 최종적으로 세 가지 값 중의 하나가 되어야 한다. 

    • EXCEPTION_CONTINUE_EXECUTION (-1) 
        예외를 무시하고, 예외가 발생한 지점에서부터 프로그램을 계속 실행한다. 예를 들어 10 / i 에서 i가 0이라서 예외가 발생한 경우, 예외 처리 필터가 이 값이라면, 다시 10 / i부터 실행한다는 말이다. 
    • EXCEPTION_CONTINUE_SEARCH (0) 
        except 블록 안의 코드를 실행하지 않고, 상위에 있는 예외 처리 핸들러에게 예외 처리를 넘긴다. 
    • EXCEPTION_EXECUTE_HANDLER (1) 
        except 블록 안의 코드를 실행한 후, except 블록 아래의 코드를 실행한다. 

    이 세가지 값을 이용해서 예외 처리 코드를 샘플로 만들어 보자면 다음과 같다. 

    • try 블록 안에서 예외가 발생한 경우, 그 예외가 ACCESS_VIOLATION일 경우에는, exception 블록 안의 코드를 실행하고, 다른 예외인 경우에는 상위에 있는 예외 처리 핸들러에게 통제를 넘기는 코드. (GetExceptionCode 함수는 try 블록 안에서 발생한 예외의 종류를 반환하는 함수다. 자세한 것은 MSDN을 참고하도록.) 
      __try { ... // compute something } 
    • __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
    •   EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    •  { cerr << "Access violation happened!" << endl; }
      
      
      
      
    • try 블록 안에서 발생한 예외에 대한 정보를 검사하는 필터 함수를 만든 후, 이를 exception filter 부분에서 실행해서 어떤 행동을 해야할 지를 판단하는 코드. (GetExceptionInformation 함수는 예외와 예외가 발생한 시점에서의 시스템에 대한 정보를 반환하는 함수다. 자세한 것은 MSDN을 참고하도록.) 
      DWORD decide_what_to_do(PEXCEPTION_POINTERS pExceptions)
    •  { // check exceptions ...
    • 	 return EXCEPTION_CONTINUE_EXECUTION;
    •  }
    •  __try 
    • { ... // compute something } 
    • __except(decide_what_to_do(GetExceptionInformation())) 
    • { ... }
      Exception Handling의 경우, Termination Handling과는 달리, try 블록 안에 return, goto 등이 있어도 코드 크기나 성능에 페널티가 없다. 


4 Stack Unwind

    4.1 Local Unwind

      try-finally 구문에서 try 블록 내부에 return, goto 등의 premature exit가 있을 경우 발생한다. finally 블록 실행 후, 값을 리턴해야하기 때문에, 컴파일러는 임시 변수를 생성해서, 리턴값을 저장한 후, finally 블록을 실행하고, 저장해둔 값을 리턴한다. 위에서도 나와있듯이 이런 코드가 꽤 비용이 크기 때문에 극구 피해야한다. 

    4.2 Global Unwind

      Global unwind는 try-except 구문에서 exception filter가 EXCEPTION_EXECUTE_HANDLER 값인 경우 발생한다. 동작을 요약하자면, EXCEPTION_EXECUTE_HANDLER로 판정된 try 블록 안의 모든 finally 블록을 제일 안쪽의 것부터 실행한 다음, 원래 try 블록의 except 블록 부분을 실행한다가 되겠다. 

      다음은 Programming Applications from Microsoft Windows에서 가져온 예제이다. 짐작하듯이 주석에 있는 번호는 실행 순서를 나타낸다. 
      void function1() 
      { 
       // 1. 여기서 뭔가를 처리 ...
        __try
        { 
       // 2. 다른 함수를 호출 function2();
        // 이 부분의 코드는 실행되지 않는다. ... 
       }
        __except ( /* 6. 필터 구문을 검사 */  EXCEPTION_EXECUTE_HANDLER)
        { // 8. Unwind가 일어난 후에, 예외 처리 핸들러가 실행된다.
        MessageBox(...); 
       } 
      } 
       
      void function2() 
      { // 3. 여기서 뭔가를 처리 ...
        __try { // 4. 뭔가에다 락을 건다.
        EnterCriticalSection(&C); // 5. 여기서 예외가 발생한다.
        int some = 10 / 0; 
       } 
       __finally 
       { // 7. 상위 함수의 exception filter 부분의 값이 
       // EXCEPTION_EXECUTE_HANDLER이기 때문에 Global unwind가 일어난다. 
       // 락을 푼다.
        LeaveCriticalSection(&C);
        } // 이 부분의 코드는 실행되지 않는다. }
      왜 실제로 예외가 발생한 finally 부분이 먼저 실행되지 않느냐고 할 수 있는데, 예외가 발생한 경우, finally 보다는 except를 먼저 찾아서 처리한다고 생각하면 된다. 왜 그런지는 아직까지 잘 이해가 가지 않는다. 어쨌든 중요한 것은 finally 부분은 반드시 실행이 된다는 점이다. 


5 Unhandled Exception

    예외가 발생해서 그걸 처리하는 try-except 부분을 차례대로 검사했는데, 모두가 EXCEPTION_CONTINUE_SEARCH를 반환한 경우를 Unhandled Exception이라고 한다. 즉 해당하는 예외를 처리할 핸들러가 하나도 없다는 말이다. 

    윈도우즈 상에서 모든 스레드는 Kernal32.dll에 있는 BaseProcessStart와 BaseThreadStart 함수를 통해 실행된다. 첫번째는 프로세스의 메인 스레드를 위한 것이고, 두번째는 추가적인 스레드를 위한 것이지만, 결국 똑같은 넘이다. 
    VOID BaseProcessStart(PPROCESS_START_ROUTINE pfnStartAddr) 
    {
      __try { 
      ExitThread((pfnStartAddr)()); 
     }
      __except(UnhandledExceptionFilter(GetExceptionInformation()))
      { 
     ExitProcess(GetExceptionCode()); 
     } 
    } 
    VOID BaseThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam)
     { 
     __try {
      ExitThread((pfnStartAddr)(pvParam)); 
     }
      __except(UnhandledExceptionFilter(GetExceptionInformation())) {
      ExitProcess(GetExceptionCode());
      } 
    }
    결국 Unhandled Exception이 발생한 경우, 시스템에서 이를 잡아서 UnhandledExceptionFilter 함수를 실행한다는 것을 알 수 있다. 이 함수는 사용자들에게 친숙한 다음 대화창을 표시한다. 

    crash.gif 

    여기서 "확인"을 누르게 되면 EXCEPTION_EXECUTE_HANDLER를 반환하고, global unwind를 일으켜, 결국 ExitProcess를 호출하게 한다. 이것이 확인을 누르면 프로그램이 종료되는 이유다. "취소"를 누른 경우, 시스템은 JIT(Just In Time) 디버거를 로드하게 된다. 

    모든 스레드의 주 루프를 손수 만든 try-except (EXCEPTION_EXECUTE_HANDLER) 구문으로 감싸면, 예외가 위의 함수까지 가지 않게 된다. 이는 위의 대화창을 표시하지 않고, 다른 행동을 할 수 있다는 말이다. 그러나 모든 스레드를 이런 식으로 감싸는 것보다는 SetUnhandledExceptionFilter 함수를 이용하는 것이 낫다. 
    LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ); 
    // TOP_LEVEL_EXCEPTION_FILTER 함수의 형식 
    LONG UnhandledExceptionFilter( STRUCT _EXCEPTION_POINTERS* ExceptionInfo );
    이 함수를 사용하는 예는 MiniDump 페이지를 참고하기 바란다. 


6 First and Second Chance Exception

    예외 핸들러를 설치한 경우, 예외가 발생하면 핸들러에서 그것을 잡아서 처리한 후, 실행을 계속한다는 개념은 예외 처리의 기본이다. 그런데 실행 중인 프로그램에 디버거가 붙어있는 경우에는 약간 다르다. 디버거가 붙어있는 상태에서의 예외 처리는 다음과 같은 순서로 이루어진다. 

    1. 디버거에서 첫번째로 예외가 발생한다. --> First Chance Exception 
    2. 프로그램 내부의 예외 핸들러에서 예외가 발생한다. 
    3. 디버거에서 두번째로 예외가 발생한다. --> Second Chance Exception 

    물론 첫번째로 디버거에서 예외가 발생했을 때, 프로그램 쪽으로 예외를 넘겨주지 않으면 거기서 끝이다. 또한 프로그램 내부에서 예외 핸들링을 제대로 하지 않은 경우에도 한번으로 끝이다. 이 경우는 원래 프로그램이 크래쉬되는 상황이라는 것은 두말할 나위 없다. 더 자세한 내용은 [WWW]INFO: First and Second Chance Exception Handling를 참고하시라. 


7 링크


출처 http://excel96.cafe24.com/moin.cgi/SEH

반응형
반응형

http://www.winapi.co.kr/

 

 

1.소개

스파이는 비주얼 C++과 함께 배포되는 개발 보조툴로 주로 윈도우에 대한 정보를 조사하고자 할 때 사용된다. 윈도우의 클래스 이름이나 스타일 또는 포함 관계를 조사하거나 윈도우로 전달되는 메시지를 감시하는 것이 주된 용도이며 이 툴을 사용하면 다른 프로그램의 구성이나 동작 방식에 대해 많은 것을 배울 수 있다. 이름 그대로 이미 만들어져 있는 윈도우의 정보를  몰래 살짝 들여다 보는 도구이다. 그다지 실용적이지는 않지만 스레드나 프로세스에 대한 감시 기능도 제공한다.

스파이가 제공하는 정보는 Win32 API의 표기법을 그대로 사용하므로 이 정보를 제대로 해석하려면 Win32 API에 대한 기본적인 이해가 필요하다. 예를 들어 윈도우 스타일은 WS_CHILD나 WS_VSCROLL 등으로 표기되는데 이 상수들이 어떤 의미를 가지는가를 알고 있어야 하며 윈도우 클래스의 각 멤버에 대한 이해도 필요하다. 클래스 바이트(cbClsExtra)나 인스턴스 핸들, 윈도우 프로시저같은 용어에도 거부감이 없어야 한다. 이 강좌를 읽고 있는 사람이라면 이런 기본적인 용어에 대해서는 잘 알고 있을 것이다.

비주얼 스튜디오의 모든 버전에 포함되어 있기 때문에 별도로 설치할 필요가 없으며 각 버전별로 기능상의 차이점도 거의 없으므로 한가지 버전에 대해서만 사용법을 익혀두면 된다. 이 강좌는 비주얼 스튜디오 .Net의 Spy++로 작성되었다. 비주얼 C++ 6.0에도 스파이가 있고 더 최신의 닷넷 2003에도 포함되어 있는데 사용 방법은 비슷하다.

시작 버튼을 눌러 프로그램 메뉴를 열고 비주얼 스튜디오 폴더의 Visual Studio .Net Tools를 선택하면 이 안에 Spy++이 등록되어 있으며 이 항목을 선택하면 스파이가 실행된다. 한번만 실행되는 프로그램이므로 이미 실행중이라면 실행중인 스파이로 포커스만 넘어간다. 자주 사용한다면 단축 아이콘을 만들어 놓는 것이 좋을 것이다. 스파이는 다음과 같이 생겼다.

MDI 형태로 되어 있으므로 여러 개의 뷰를 동시에 열어 놓을 수 있으나 실제 중요한 정보는 개별적인 대화상자를 통해 확인하기 때문에 MDI의 이점은 별로 없는 셈이다. 대체로 관심있는 뷰 하나만 열고 최대화해 놓고 많이 쓰는 편이다.

비주얼 C++ 6.0까지는 영문으로 되어 있었으나 7.0부터는 스파이도 한글화되어 메뉴나 대화상자의 캡션이 한글로 바뀌었다. 그러나 개발자들은 실제로 영문으로 된 전문 용어에 익숙해져 있기 때문에 번역된 캡션이 더 어색하게 느껴지기도 한다. 번역이 그다지 매끄럽지는 않지만 번역된 캡션을 보면 어떤 대상을 가리키는지 직관적으로 알 수 있는 정도이다. 예를 들어 "창 바이트"라는 말은 윈도우의 여분 바이트(cbWndExtra)라는 뜻이고 "창 프로시저"라는 말은 윈도우 프로시저의 번지라는 뜻이다. 개인적으로 이런 전문적인 프로그램은 한글화 하지 않는 것이 더 좋다고 생각한다.

타이틀 바 아래에 메뉴가 있고 그 아래에 툴바가 있으며 작업영역 아래에는 상태란이 배치되어 있어 전체적인 모양은 지극히 평범하다. 메뉴에는 스파이의 모든 명령들이 정리되어 있겠지만 대부분의 명령들이 툴바에 있으므로 이 버튼들에 대해서만 알아 두면 스파이의 모든 기능을 다 활용할 수 있다.

메뉴에 있는 명령 중 유일하게 실용성이 있는 명령은 메인 윈도우의 글꼴을 변경할 수 있는 보기/글꼴 명령밖에 없다. 디폴트 글꼴은 9포인트의 Sans Serif인데 굴림이나 바탕으로 변경할 수 있으며 글꼴의 크기도 크게 만들 수 있다. 다음은 툴 버튼에 대한 간략한 설명이다.

 

버튼

설명

 뷰를 보여준다.

프로세스 뷰를 보여준다.

스레드 뷰를 보여준다.

메시지 옵션 대화상자를 보여준다.

 찾기 대화상자를 띄운다.

메시지 기록을 시작하거나 잠시 중지한다.

메시지 옵션 대화상자를 보여준다.

지금까지 조사된 메시지 기록을 삭제한다.

조건에 맞는 프로세스스레드메시지를 검색한다.

다음 찾기

이전 찾기

 속성 대화상자를 보여준다.

새로 고침.

 

상태란은 선택된 메뉴나 툴바에 대한 간단한 도움말을 보여주는 정도의 기능밖에 없다. 겉으로 보이는 이런 것들 외에 화면 각 부분을 누르면 나타나는 팝업 메뉴가 있는데 이에 대해서는 관련 부분에서 따로 설명하기로 한다.

 


 

6.메시지 뷰

메시지 뷰는 윈도우로 전달되는 모든 메시지를 감시하여 어떤 메시지가 어떤 인수와 함께 전달되었는지를 보여준다. 프로세스나 스레드로 전달되는 메시지를 감시할 수도 있지만 주로 윈도우의 메시지를 감시하는 경우가 많다. 전달되는 모든 메시지를 순서대로 살펴볼 수 있기 때문에 디버깅과 분석시에 아주 큰 도움이 된다.

메시지 뷰를 열 때는 각 뷰의 팝업 메뉴에서 메시지 항목을 선택하면 된다. 예를 들어 메모장의 에디트 컨트롤로 전달되는 메시지를 보고 싶다면 창 뷰에서 에디트 컨트롤을 선택하고 팝업 메뉴에서 메시지 항목을 선택하면 된다. 또는 창 찾기 대화상자에서 찾기 도구를 메모장의 에디트에 떨어뜨린 후 대화상자 아래의 표시 항목을 메시지로 선택해도 된다.

 

메시지 기록이 시작되면 메시지 뷰가 열리며 여기에 해당 윈도우로 전달되는 메시지들이 순서대로 출력된다. 스파이는 메시지 감시를 위해 후킹을 사용하기 때문에 메시지를 감시하는동안에는 시스템의 전반적인 속도가 눈에 띄게 느려지는데 속도만 느려질 뿐 기능상의 문제는 없다. 윈도우로 전달되는 메시지를 일일이 감시하고 문자열로 바꾸어 출력하고 있으니 느려질 수밖에 없다. 다음은 메모장으로 전달되는 메시지들이다.

제일 왼쪽의 번호는 메시지의 일련 번호이며 두번째 칸의 16진수는 메시지를 받은 윈도우의 핸들이다. 세번째 P,R,S,s는 메시지가 전달된 방식을 나타내는 메시지 코드가 출력된다. 메시지 코드는 다음과 같다.

 

코드

설명

P

PostMessage 함수로 메시지 큐에 붙여진 메시지이다.

S

SendMessage 함수에 의해 윈도우 프로시저로 직접 전달된 메시지이다.

R

S 보내진 메시지를 처리한 결과이다메시지 처리 중에 다른 메시지를  보낼  있기 때문에 S R 중첩될  있다.

s

S 유사하되 보안상의 이유로  메시지의 처리 결과를 조사할  없다.

 

메시지 코드 다음에는 실제 전달된 메시지와 메시지의 인수들이 표시되는데 각 메시지별로 의미가 해석되어 있다. 예를 들어 WM_KEYDOWN이면 어떤 키가 눌러졌고 반복 회수는 얼마이며 스캔코드와 확장키의 상태 등이 표시되며 WM_CHAR이면 입력된 문자를 보여준다. wParam, lParam을 보여주는 것이 아니라 인수로 전달된 메시지의 논리적인 실제값을 보여주기 때문에 메시지의 의미를 파악하기가 쉽도록 되어 있다.

윈도우로 아주 많은 메시지가 전달될 뿐만 아니라 전달되는 속도가 대단히 빠르기 때문에 순식간에 수백개의 메시지가 전달된다. 그러다 보니 정작 관심있는 메시지가 너무 빨리 위로 스크롤되어 버리는 불편함이 있는데 스파이는 원하는 메시지를 자세히 살펴 볼 수 있도록 몇가지 장치를 제공한다.

우선 툴바의  버튼을 누르면 기록을 잠시 중지/재개할 수 있다. 살펴보고 싶은 메시지가 전달되었으면 메시지 기록을 일단 중지하고 목록을 살펴볼 수 있다.  버튼은 지금까지 작성한 모든 기록을 삭제하고 다시 기록을 시작하도록 한다.  버튼은 메시지 기록에 대한 몇가지 옵션을 지정하는 다음 대화상자를 보여 준다.

세 개의 페이지로 구성되어 있는데 이 대화상자에도 찾기 도구가 있으므로 대상 윈도우를 직접 변경할 수 있다. 뿐만 아니라 추가 창을 선택하면 관련있는 주변 윈도우로 전달되는 메시지도 같이 감시할 수 있다. 메시지 페이지에서는 기록 대상 메시지를 선택한다.

디폴트로 모든 메시지를 다 기록하도록 되어 있는데 여기서 관심있는 메시지만 선택하거나 불필요한 메시지는 선택 취소할 수 있다. 예를 들어 다른 메시지는 관심이 없고 키보드 관련 메시지만 보고 싶다면 Keyboard만 선택하면 된다. 또한 WM_MOUSEMOVE, WM_NCHITTEST 같은 메시지는 너무 자주 발생하므로 제외시킬 수도 있다. 출력 페이지는 메시지의 출력 형식을 지정한다.

파일에도 로그 옵션을 선택하고 파일명을 주면 메시지 기록을 텍스트 파일에도 작성해 주므로 조사가 끝난 후 파일을 열어서 볼 수 있다. 메시지 전달 속도가 너무 빠르기 때문에 화면으로 확인하기 힘든 메시지는 파일에서 정밀 검색하면 된다.

메시지 뷰가 보여 주는 정보는 아주 다양하게 활용된다. 우선 디버깅에 활용되는데 메시지가 전달되는 순서와 처리되는 과정을 자세하게 살펴 볼 수 있어 프로그램의 동작을 세밀하게 감시할 수 있다. 프로그램이 이상 동작을 한다면 그 시점이 언제인지를 스파이로 조사할 수 있으며 일단 시점이 파악되면 디버거로 해당 메시지를 집중 디버깅해 보면 된다. 또한 원치않은 메시지가 발생한다면 어떤 메시지에 의해 추가로 발생한 메시지인지, 그 순서는 어떻게 되는지를 알 수 있으며 SendMessage로 보낸 메시지를 확실히 수신했는지 확인할 수도 있다.

Win32 API를 처음 공부하는 사람에게 스파이는 또한 학습용으로도 아주 가치가 있는데 예를 들어 IME같이 메시지의 순서나 파생 관계가 복잡할 때 스파이를 활용하면 메시지의 발생 시기와 순서을 정확하게 알 수 있다.

 

반응형
반응형

http://idnch715.tistory.com/125

 

 

"도스창(명령 프롬프트)"에서 직접 또는, 배치 파일 속에서 디렉토리를 복사하는 방법입니다.

도스의 일반적인 COPY 명령에는 디렉토리 복사 기능이 없습니다. 파일만 복사할 수 있습니다. 그 외에도, 파일 속성을 복사할 수 없는 등의 제약이 아주 많습니다.

XCOPY 라는 외부 명령어로 디렉토리를 복사할 수 있습니다.

 

하위 디렉토리까지 포함, 모든 파일 복사 예제


 

xcopy d:\z\*.* d:\x\ /e /h /k

 

 

D드라이브의 Z디렉토리의 트리 구조를,
D드라이브의 X디렉토리로 전부 복사하는 예제입니다.


/e : 비어 있는 하위 디렉토리까지 복사
/h : 히든 파일과 시스템 속성의 파일까지 복사
/k : 파일 속성 복사. (이 옵션이 없으면, 읽기전용 등의 속성이 없어져 버림)

더 자세한 도움말은 xcopy /? 라고 하면 화면에 출력됩니다.

 
 
반응형

'프로그래밍(Programming) > 기타' 카테고리의 다른 글

xcopy 파일복사  (0) 2012.12.26
vs2008 에 OpenCV2.0 설치  (0) 2012.10.31
반응형

http://openarisu.tistory.com/191


다음 순서로 진행이 된다. 
알아두자.

1. WM_CLOSE (OnClose) 발생
2. DestoryWindow (DestoryWindow )  호출 
3. WM_DESTORY ( OnDestory) 발생

각 함수를 수정할려면
WM_CLOSE 메시지 선택시 OnClose()
DestoryWindow 재정의할 때 DestoryWindow()
WM_DESTROY 메시지 선택시 OnDestory() 함수를 작성할 수 있다.

소스 내용 보기.
void CTestDlg::OnClose()
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
    >> 이 부분에서 종료되는 윈도우를 제어할 수 있습니다.
    CDialog::OnClose();
}

BOOL CTestDlg::DestroyWindow()
{
    return CDialog::DestoryWindow();
}

void CTestDlg::OnDestory()
{
    CDialog::OnDestory();
}


참조 : http://yunhyeon.tistory.com/tag/DestroyWindow

반응형
반응형

http://blog.naver.com/mirzzz79/110013137412


MFC Single Document FrameWork

  - MFC 주요 클래스의 호출 순서는 다음과 같이 이루어지며,

     클래스 공유되어 사용되는 리소스 클래스를 포인터로 연결하여 사용할때

     소멸 순서에 의하 잘못된 포인터 참조를 막기위해, 리소스는 Document에

     생성하여 링크하는 것이 가장 효율적이며, 관리하기 좋다. 

 

## Construct CApp ##
CApp::CApp()      

CApp::InitInstance()

 

## Construct CDoc ##
CDoc::CDoc()      

 

## Construct CMainFrame ##
CMainFrame::CMainFrame()   
CMainFrame::PreCreateWindow(CREATESTRUCT& cs) 
CMainFrame::Create(LPCTSTR lpszClassName, ...)
CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
CMainFrame::OnWndMsg(UINT message, ...)
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

 

## Construct CView ##
CView::CView()      
CView::Create(LPCTSTR lpszClassName, ...)
CView::PreCreateWindow(CREATESTRUCT& cs)
CView::OnCreate(LPCREATESTRUCT lpCreateStruct)

 

## Document Restore ##
CDoc::OnNewDocument()  -> 내부 Pre Call - CDoc::DeleteContents()

## View Setting ##
CView::OnInitialUpdate()

CMainFrame::OnWndMsg(UINT message, ...)
CMainFrame::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
CView::OnDraw(CDC* /*pDC*/)

 

## Thread Setting ##
CApp::Run()

 

## Loop ##
whlie(true)
{
 CApp::OnIdle(LONG lCount)
 CApp::PreTranslateMessage(MSG* pMsg)
 CMainFrame::OnWndMsg(UINT message, ...)
 CMainFrame::PreTranslateMessage(MSG* pMsg)
 CMainFrame::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
 CView::OnDraw(CDC* /*pDC*/)
}

 

CMainFrame::OnClose()

 

## Document Release ##
CDoc::OnCloseDocument()  -> 내부 Post Call - CDoc::DeleteContents()

CMainFrame::DestroyWindow()
CMainFrame::OnDestroy()

 

## Destroy CView ##
CView::OnDestroy()
CView::~CView()      


## Destroy CMainFrame ##
CMainFrame::~CMainFrame()   

 

## Destroy CDoc ##
CDoc::~CDoc()

CApp::ExitInstance()

 

## Destroy CApp ##

 

 

by. mirz (2007.1)

반응형
반응형

http://mins79.tistory.com/entry/%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%9A%A9%EB%B2%95-MFC-ComboBox-%EC%98%88%EC%A0%9C

 

콤보박스를 어떻게 다루어야 하는지에 대하여 알아보겠습니다.

보통 사용한다함은?
1. 데이터를 추가한다.
2. 데이터를 삽입한다.
3. 데이터 하나를 지운다.
4. 데이터를 모두 지운다.
5. 부가정보를 첨부한다.
6. 현재 선택되어진 문자열을 읽어온다.
이정도 선에서 사용하게 됩니다.

우선 콤보박스를 빈 다이알로그에 하나 올리고 아이디를 IDC_COMBO1 이라고 하고 다음과 
같은 스타일로 샘플을 만들겠습니다.


다음은 CComboBox m_combo 로 컨트롤을 연결합니다.




다음으로 위에서 열거한 기능을 하나씩 버튼을 넣어가면 진행하여 보겠습니다.


1. 우선 그림처럼 버튼을 넣고, 그 버튼을 누르면 데이터를 추가합니다.

void CSssDlg::OnButton1() 
{
    m_combo.AddString("하나");
    m_combo.AddString("둘");
    m_combo.AddString("셋");
}


int CComboBox::AddString(LPCTSTR lpszString);
-------------------------------------------------
Parameters
   lpszString - NULL로 끝나는 문자열
Return Value
   추가된 아이템의 크기가 0보다 크다면 Zero-Based 인덱스가 리턴된다.
   만약 CB_ERRSPACE가 리턴된다면 데이터를 저장하기 위해 할당할 메모리가 모자라다.
Remark
   만약 생성시에 CBS_SORT 스타일을 넣었다면 정렬된 위치로 삽입되게 된다. 


2. 다음 그림처럼 버튼을 넣고, 그 버튼을 누르면 데이터를 2번째에 삽입한다.

void CSssDlg::OnButton2() 
{
   m_combo.InsertString(1, "삽입됨");
}

인덱스가 Zero-Based Index 이기 때문에 인덱스 1에다 넣으면 2번째 위치가 된다.

int CComboBox::InsertString(int nIndex, LPCTSTR lpszString);
--------------------------------------------------------------
Parameter
   nIndex - Zero-Based Index 이고, 만약 -1이면 마지막에 추가된다. 
   lpszString - NULL로 끝나는 문자열
Return Value
   현재 삽입된 위치의 인덱스가 리턴된다.
Remark
   AddString과는 달리 CBS_SORT 스타일이라 하더라도, 삽입위치는 변경되지 않는다.


3. 다음 그림처럼 버튼을 넣고, 그 버튼을 누르면 선택되어진 아이템을 삭제한다.

void CSssDlg::OnButton3() 
{
    int nIndex = m_combo.GetCurSel();
    if(nIndex == -1)
        return;
    m_combo.DeleteString(nIndex);
}

아무것도 선택되지 않았거나, 아이템이 하나도 없을 경우에 대한 에러처리를 해야한다.

int CComboBox::DeleteString(UINT nIndex);
----------------------------------------
Parameter
   nIndex - 0보다 크거나 같은 삭제할 인덱스
Return Value
   0이거나 0보다 큰값으로 현재 남아있는 아이템의 카운트를 리턴한다.
Remark
   당연한 이야기겠지만, 여러개의 아이템중에 중간에 것을 삭제하면 아래의 하위 아이템들의
   인덱스가 당연히 하나씩 줄어든다. 아이템을 인덱스로 관리할 경우 에러가 나거나 오동작
   할 수 있으므로 주의해야한다.


4. 다음 그림처럼 버튼을 넣고, 그 버튼을 누르면 데이터를 모두 지운다.

void CSssDlg::OnButton4() 
{
   m_combo.ResetContent();
}

루프를 돌며 하나씩 지워나갈 수도 있겠지만, 지원하는 함수가 있으니...

void CComboBox::ResetContent();
-----------------------------------
Remark
   루프를 돌면서 하나식 지우게 되면 에디트의 선택영역이 글자는 남아있게된다. 이 함수를 
   이용하게 되면 에디트와 리스트영역을 모두 초기화 시킨다.


5. 다음 그림처럼 버튼을 넣고, 그 버튼을 누르면 개별 아이템에 부가정보를 첨부한다.
첨부된 부가 정보를 보여주기 위하여 콤보박스 하단에 스태틱 컨트롤을 하나추가한다.
또한 아이템의 선택이 변경되었을 때마다 스태틱의 정보를 갱신해 주기 위하여 CBN_SELCHANGE
이벤트를 추가하고 핸들러에 부가 코드를 넣는다.

// 아래의 이벤트는 콤보박스에서 아이템을 선택을 변경하면 발생하는 이벤트이다.
void CSssDlg::OnSelchangeCombo1() 
{
    // 현재 선택되어진 아이템
    int nIndex = m_combo.GetCurSel();
    if(nIndex == -1)
        return;

    CString s;
    // 현재 아이템의 부가 정보를 읽어온다.
    // 여기서는 단순하게 숫자로 넣었지만, 포인터를 넣을 수 있으므로 모든 데이터를 다
    // 첨부할 수 있다.
    // 디비에서 사용자 정보 전체를 읽어와서 이름만 콤보박스에 넣는다면...
    // 나머지 정보를 구조체등에 넣은다음.. 그 포인터를 SetItemData()로 넣어두면
    // 언제든지 쉽게 접근할 수 있게된다.

    s.Format("0x%X", (UINT)m_combo.GetItemData(nIndex));
    SetDlgItemText(IDC_STATIC_OPTION, s);
}

선택되어진 아이템의 부가정보를 읽어와 숫자로 읽어온다음 문자열로 변환하여
해당 스태틱 컨트롤에 뿌려준다.

void CSssDlg::OnButton5() 
{
    int count = m_combo.GetCount(), i;
    for(i=0; i<count; i++)
        m_combo.SetItemData(i, (DWORD)rand());
}
콤보박스의 갯수를 세어, 부가정보로 랜덤한 숫자를 임시로 넣어본다.

int CComboBox::SetItemData(int nIndex, DWORD_PTR dwItemData);
------------------------------------------------------------------
Parameter
   nIndex - 제로베이스 인덱스
   dwITemData - 아이템에 넣을 부가정보의 포인터, 데이터를 넣을 경우는 DWORD로 타입 캐스팅
       하여 넣으면 된다. 
Return Value
   현재 아이템의 제로베이스 인덱스
Remark
   만약 new 등을 이용해 할당한 것이라면 수동으로 delete 해주어야 한다.


6. 다음 그림처럼 버튼을 넣고, 그 버튼을 누르면 선택된 아이템의 캡션을 읽어온다.

void CSssDlg::OnButton6() 
{
    int nIndex = m_combo.GetCurSel();
    if(nIndex == -1)
        return;

    CString s;
    m_combo.GetLBText(nIndex, s);
    AfxMessageBox(s);
}

선택되어진 아이템의 인덱스를 구한 후, 아이템의 문자열을 읽어와 메시지박스로 뿌려준다.

void CComboBox::GetLBText(int nIndex, CString& rString) const;
----------------------------------------------------------------
Parameter
   nIndex - 제로베이스 인덱스
   rString - 읽어올 문자열을 저장할 객체.


그 외에도 콤보박스에서 제공되는 함수나 기능들은 좀더 다양하게 있지만 그렇게
자주 쓰이거나 하지는 않는다. 

다음 장에서 콤보박스의 이벤트를 다루며 몇몇 다른 함수들의 기능도 살펴보자.




 

반응형
반응형

view클래스::OnInitialUpdate()
{

 
 CComboBox * pWnd=(CComboBox*)(GetDlgItem(IDC_COMBO1));
  //->InsertString((CComboBox*)(::GetDlgItem(m_hWnd,IDC_COMBO1))->GetCount(), str);

 
 CString str;
 str.Format(L"첫번째아이템");
 pWnd->InsertString(pWnd->GetCount(), str);

 

 

...

}


반응형
반응형

다른것은 동일한데 새로운 사용자 정의 클래스에서

 

doc 클래스와 view 클래스를 include 한다 이때 순서가 중요한데

 

doc클래스 다음에 view 클래스를 include 해야한다

 

 

하지만 뷰클래스에 위에 설명한 클래스를 포함하려면 에러가 나는데

이럴거면 차라리 뷰클래스 아래 클래스를 작성하고 뷰클래스를 그대로 상속 받기만 해도 상속이 되며

 

사용자 정의 클래스를 뷰 클래스 상단에 선언문만 작성해 놓고 쓰면 에러를 피할 수 있다

반응형
반응형

단점 실시간으로 이미지에 선을 그리고 렌더링하는것을 반복하기에는 부적합하다

because 너무느리다

http://roter.pe.kr/263

MFC에서 더블버퍼링 사용하기.
이걸 왜 지금까지 안올려놨었지 -.-?;;

일단 제일 중요한건 헤더 파일에
CBitmap m_Bitmap;
를 선언 하는 것.
이 비트맵에 객체를 생성하고 이것저것 해줄 것임.

우선 아래와 같이 Bitmap에 그림을 그려줌.

void CDlgXXX::MakeMemBitmap(void)
{
	CClientDC dc(this); //실제 dc
	
	CBitmap* pOldBmp; //oldbmp

	CDC MemDC; //메모리DC
	
	m_Bitmap.DeleteObject(); //기존꺼 지워줌
	m_Bitmap.CreateCompatibleBitmap(&dc, 500, 200); //새로 만들어줌
	MemDC.CreateCompatibleDC(&dc); //memDC도 새로 만들어줌
	pOldBmp = MemDC.SelectObject(&m_Bitmap); //memDC의 비트맵 선택
	
	MemDC.MoveTo(0,0); 
	MemDC.LineTo(500,200); //memDC에 그린다.(비트맵 위에 그려진다)
	MemDC.SelectObject(pOldBmp); //oldbmp 선택
	MemDC.DeleteDC(); //memDC를 지운다.
}
 
void CDlgXXX::OnPaint()
{
	CPaintDC dc(this); // device context for painting	
	CDC MemDC;
	
	CBitmap* pOldBmp;

	MemDC.CreateCompatibleDC(&dc);
	pOldBmp = MemDC.SelectObject(&m_Bitmap);
	
	
	dc.BitBlt(0,0,500,200, &MemDC, 0,0,SRCCOPY);
	

	MemDC.SelectObject(pOldBmp);
	MemDC.DeleteDC();
}
 

반응형
반응형

http://ryumin13.tistory.com/129

 

mfc를 쓰다보면, CString으로 editbox의 값을 입력 받았다가, 숫자로 변환하여 쓰는 경우가 많다. 그럴때 숫자로 변환하는 방법이다.
(물론 다른 방법도 있다. float 일때 이렇게 사용된다. )

CString strValue;
GetDlgItemText( IDC_EDIT1, strValue);
float fValue = _tstof( strValue );

 

반응형
반응형

 CCmdUI 클래스 : 사용자 인터페이스 갱신  MFC 라이브러리

2009/02/11 10:17

복사http://blog.naver.com/origin26/40061989342

■ CCmdUI 클래스

。기능

- 사용자 인터페이스 갱신과 관련된 기능을 수행하며 ON_UPDATE_COMMAND_UI 매크로로 연결되는 이벤트 처리기에 사용한다.

- 연결된 이벤트 처리기는 ON_COMMAND로 이미 등록되어 있는 이벤트 상태에 변경이 있을 때 이를 업데이트 시킨다.

 

- 연결된 이벤트 처리기는 이 클래스의 인스턴스 포인터를 매개변수로 넘겨받는다.

- 이벤트명이 ID_BEGIN이라면 이를 갱신하는 이벤트 처리기는 OnUpdateBegin()이 된다.

 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

     . . .

     ON_UPDATE_COMMAND_UI( ID_BEGIN, OnUpdateBegin)

     ON_UPDATE_COMMAND_UI( ID_END, OnUpdateEnd)

 END_MESSAGE_MAP()

 

 void CCmdUIView::OnUpdateBegin(CCmdUI *pCmdUI)

 {

   pCmdUI->Enable(!m_bStart) ;

 } 

 void CCmdUIView::OnUpdateEnd(CCmdUI *pCmdUI)

 {

   pCmdUI->Enable(!m_bStart) ;

 }

 

。주요 멤버변수 : 갱신할 사용자 인터페이스의 이벤트 ID를 나타내는 UNIT 형의 m_nID가 있다.

。주요 멤버 함수

 멤버 함수 기능 
 Enable BOOL형 매개변수를 받아 사용자 인터페이스를 활성화/비활성화 시킴.
 SetText 사용자 인터페이스의 텍스트를 변경시킴.
 SetCheck int형 매개변수를 받아 체크 표시를 하거나 없앰.
 SetRadio SetCheck 함수와 비슷한 기능. 단, 체크 표시대신 점이 찍힘.

 

------------------------------------------------------------------------------------------

 

- 우선 다음과 같은 이벤트 처리기가 정의되어 있다고 가정한다.

 BEGIN_ MESSAGE_MAP(CCmdUIView, CView)

      ...

      ON_COMMNAD( ID_BEGIN, OnBegin )

      ON_COMMAND( ID_END, OnEnd )

 END_MESSAGe_MAP()

 

 void CCmdUIView::OnBegin()

 {

     m_bStart = TRUE ;

 }

 

 void CCmdUIView::OnEnd()

 {

     m_bStart = FALSE ;

 }

 

 

■ Enable 함수

- 메뉴 항목을 상황에 다라 활성화 시키거나 비활성화 시킨다.

 

。상태변수 만들기

- 활성화인지 비활성화 인지의 상황을 기억하는 상태 변수가 필요하다.

 class CCmdUIView : public CView

 {   ...

     BOOL m_bStart ;

 }

 

- 상태 변수를 클래스 생성자 함수에서 초기화 해 준다.

 CCmdUIView::CCmdUIView()

 {  ...

     m_bStart = FALSE ;

 }

 

。사용자 인터페이스 갱신 메세지 처리기 등록  

- ON_UPDATE_COMMAND_UI로 등록한다.

 BEGIN_ MESSAGE_MAP(CCmdUIView, CView)

      ...

      ON_UPDATE_COMMNAD_UI( ID_BEGIN, OnBegin )

      ON_UPDATE_COMMNAD_UI( ID_END, OnEnd )

 END_MESSAGe_MAP()

 

。메세지 처리기 활성/비활성 상태 제어

- Enable 함수를 호출하여 매개변수로 TRUE(활성화) 또는 FLASE(비활성화)를 넘긴다.

- 이벤트 처리기에 넘겨지는 매객변수 pCmdUI에는 메뉴 항목에 대한 정보가 담겨 있다.

- CCmdUI 클래스의 멤버 함수들을 호출하면 해당 메뉴 항목을 제어할 수 있다.

 void CCmdUIView::OnUpdateBegin(CCmdUI *pCmdUI)

 {

     pCmdUI->Enable(!m_bStart) ;

 }

 void CCmdUIView::OnUpdateEnd(CCmdUI *pCmdUI)

 {

     pCmdUI->Enable(!m_bStart) ;

 }


반응형

'프로그래밍(Programming) > MFC&API' 카테고리의 다른 글

더블버퍼링  (0) 2012.11.01
CString 을 float 로 변환  (0) 2012.11.01
EditBox 가 CString 일때 비활성화(회색으로) 시키기  (0) 2012.11.01
UpdateData 함수  (0) 2012.11.01
스크롤바 기능, 사용하기  (0) 2012.11.01
반응형

 

해당 다이얼로그에 OnInitDialog

를 추가 시킨후

 

bool 값을 미리 판정 받아

 

OnInitDialog(){

//이 안에서

    GetDlgItem(IDC_XCOUNT_EDIT)->EnableWindow(mbshow);

 //적용 시키면 된다

}


반응형
반응형

UpdateData 함수를 이용한 데이터 전송
UpdateData 함수는 매개변수를 이용하여 양방향 전송을 제어합니다.
아래의 그림에 보인 바와 같이 UpdateData 함수의 매개변수로 TRUE를 주면
사용자가 컨트롤에 입력한 값이 Value형 멤버 변수로 전송되고,
UpdateData 함수의 매개변수로FALSE를 주면 Value형 멤버 변수에 설정되어 있는 값이
컨트롤로 전송되어 이 값이 화면에 출력 됩니다.

※  CDialog 클래스에서 기본적으로 호출하고 있는 UpdateData 함수
CDialog 클래스에서는 프로그래머들의 편의를 위해, 기본적으로 UpdateData 함수를 두 번 호출해 주고 있습니다.
OnInitDialog 함수 안에서 UpdateData(FALSE)를 호출해주고, OnOK 함수 안에서 UpdateData(TRUE)를 호출해줍니다.
CDialog 클래스는 왜 이러한 일을 해 주고 있을까요?

  • 대화상자 시작 시 UpdateData(FALSE) 호출
    OnInitDialog 함수는 대화상자를 초기화 하기 위해 호출되는 함수입니다.
    이때, UpdateData(FALSE)가 호출되면, Value형 멤버 변수에 설정된 값이 컨트롤로 전송되어 화면에 나타나게 됩니다.
    즉, 대화상자가 화면에 나타나는 순간에 Value형 멤버 변수에 설정된 초기값이 화면에 출력되는 것이지요.
  • 대화상자 종료 시 UpdateData(TRUE) 호출
    OnOK 함수는 입력을 마치고 대화상자가 종료될 때 호출되는 함수입니다.
    이때, UpdateData(TRUE)가 호출되면, 사용자가 컨트롤에 입력해 놓은 값이 Value형 멤버 변수에 저장됩니다.

※ 주의
대화상자를 처리할 때 주의할 점은 사용자가 컨트롤에 입력한 값과 이 컨트롤에 연결된 Value형 멤버 변수에
저장된 값이 항상 같은 상태로 유지되는 것은 아니라는 점입니다. 즉, 사용자가 컨트롤에 어떤 값을 입력하면
컨트롤에 입력된 값은 변경되지만, 이 값이 바로 Value형 멤버 변수에 반영되는 것은 아니라는 것입니다.
UpdateData(TRUE)를 호출하고 난 다음에야 비로소, 컨트롤에 입력된 값이 Value형 멤버 변수에 저장됩니다.
물론, OnOK 함수에서 UpdateData(TRUE)가 호출되고 있으므로 확인 버튼을 눌러 대화상자가 종료된 후에는
컨트롤에 입력되었던 값이 Value형 멤버 변수에 저장된 상태가 됩니다.
하지만, 만약 그 전에 컨트롤에 입력된 값을 Value형 멤버 변수에 반영되도록 하고 싶으면 UpdateData(TRUE)를 명시적으로 호출해 주어야 합니다.


반응형
반응형

http://ospace.tistory.com/tag/%EC%8A%A4%ED%81%AC%EB%A1%A4%EB%B0%94

 


 

GetScrollPos => int GetScrollPos(HWND hWnd, int nBar);
설명 : 스크롤 바 컨트롤의 현재 값을 조사한다. 이 값은 스크롤 바 썸의 위치이다. 스크롤 바 메시지인 M_HSCROLL, WM_VSCROLL 메시지는 HIWORD(wParam)으로 현재 위치를 전달해 주기 때문에 16비트 범위의 값 이상을 표현할 수 없지만 이 함수를 사용하면 32비트 범위의 스크롤 값을 조사할 수 있다.
 
SetScrollPos => int SetScrollPos(HWND hWnd, int nBar, int nPos, BOOL bRedraw);  
설명 : 스크롤 바위 현재 위치, 즉 스크롤 바의 값을 설정한다. 통상 이 함수는 WM_HSCROLL, WM_VSCROLL 등의 스크롤 바 메시지 처리 루틴에서 스크롤 바의 위치값을 변경하기 위해 호출한다. 범위를 지정하는 nPos는 32비트의 정수이나 메시지로 전달되는 스크롤 바 위치는 16비트값이기 때문에 위치값은 16비트로 제한된다. 그러나 메시지의 인수를 참조하지 않고 GetScrollInfo 등의 함수로 스크롤 바의 위치를 직접 조사하면 32비트의 스크롤 위치값을 지정할 수도 있다.


인수 설명 : 
hWnd : 스크롤 바 컨트롤의 핸들. 이 값의 의미는 두번째 인수 nBar에 따라 달라진다.

nBar : 위치를 설정할 스크롤 바를 지정한다. 다음 세가지 값중의 하나를 가진다.
          SB_CTL 별도의 스크롤 바 컨트롤이며 hWnd는 스크롤 바 컨트롤의 핸들을 나타낸다. 
          SB_HORZ 표준 수평 스크롤 바이며 hWnd는 스크롤 바를 가진 윈도우의 핸들이다. (int 0)
          SB_VERT 표준 수직 스크롤 바이며 hWnd는 스크롤 바를 가진 윈도우의 핸들이다. (int 1)

nPos : 스크롤 바위 새로운 위치를 지정한다. 이 위치는 반드시 스크롤 바위 범위내에 있어야 하므로 값을 변경할 때 범위 내부인지를 점검한 후 값을 변경해야 한다.

bRedraw : 위치를 변경한 후 스크롤 바를 다시 그릴 것인지를 지정한다. 실행중에 위치를 변경할 경우 이 값을 TRUE로 지정하여 썸을 다시 그리도록 해 주어야 한다. 그러나 최초 스크롤 바 초기화시에는 다시 그릴 필요가 없으며 또한 실행중에라도 스크롤 바위 범위와 위치를 동시에 변경할 때는 둘 중 한 함수에서만 다시 그리기를 지정하면 된다. 이 경우 통상 SetScrollRange에서만 bRedraw를 TRUE로 설정하며 SetScrollPos의 bRedraw는 FALSE로 지정한다.


 

 

 

[컨트롤이야기] 아무도 말해주지않은 스크롤바 기능

작성자: Ospace (ospace114 at naver.com)http://ospace.tistory.com

스크롤바는 상당히 많이 사용하고 있는 컨트롤 중에 하나이다. 내용을 한 화면에 표시하지 못할 경우 그 일부를 표시하고 나머지 내용은 스크롤 바로 상하, 혹은 좌우로 이동하면서 볼 수 있게 한다.
또는 일정 정수 구간 값을 이동하면서 원하는 지점의 정수 값을 가져올 수도 있다.

먼저 스크롤 바의 기본적인 이야기를 하고 후반에 좀더 깊이 다루겠다.

Note: 예제 코드는 거의 없기에 간단하게 스크롤바를 작성하는 강좌를 보고 읽는게 이해하기 쉽다. 스크롤바에 대한 실사용을 보려면 아래 기타강좌를 참고하시길 바란다.



스크롤바 들어가기


사용자 삽입 이미지

Fig 1. Scroll Bar (from Windows XP)


위의 그림은 Windows XP에 있는 스크롤 바이다. 그전 스크롤바보다 이쁘게 변했다. ^^;
MS에서는 이렇게 스킨을 어떻게 했길래 선택적으로 바뀔 수 있지. 컨트롤 스킨 변경하려면 수많은 코드와 삽질을 해야만 되는데.. OTL

아래는 실제 스크롤 바에 구성요소들이다.

사용자 삽입 이미지

Fig 2. Scroll Bar 구성요소



스크롤바는 많이 사용해서 각 기능이야 대충 알고 있지만, 다시 대충 살표보자.

좌우에 삼각형 모양의 버튼이 보인다. 이는 좌후로  1 발자국(step)씩 움직인다. 이는 스크롤바 전체 값 범위에서 실제 1값을 의미의한다.
예를 들어 스크롤바 값 범위가 1~100 혹은 1~1000이든 상관없이 무조건 1을 의미한다.

가운데 홀로 떨어진 스크롤박스가 보인다. 이는 MSDN의 스크롤바 설명을 참조했다. 이를 이용해 값을 찾아간다. 좌우측에 빈 페이지가 보인다.

스크롤바의 정보를 가져오는 API로 GetScrollInfo 함수가 있다. 그리고 정보를 설정하는 API는 SetScrollInfo 함수가 있다.

스크롤바는 100% 수동적인 컨트롤이다. 이말은 모든 부분을 프로그래머가 제어해줘야한다.
예를 들어 가운데 스크롤박스를 움직이면 끝나는 것이 아니라. 그때 스크롤바 위치를 얻고, 해당 값을 다시 스크롤바에 갱신하고 화면을 다시 그리게 한다는 의미이다.주의하길 바란다!

스크롤바 값은 정수형이다. 실수는 사용할 수 없다. 사용하려면 값변환을 통해서 사용해야 한다. 최대 최소값을 지정하지 않으면 기본 범위는 0~100을 가진다. 일단 정확히 지정해주는게 좋다.

예를 들어 문서를 불러와서 표시하려 한다. 총 줄수가 150개라고 하면, 스크롤바 값 범위는 0~150으로 설정한다. 이건 고정된 값은 아니다. 스크롤바 범위는 300, 450도 가능하고 200도 가능하다.
단지 스크롤바 1스텝이 라인 1줄에 해당하는 형태로 일치시키기 위해서이다.

이렇게 최대 최소 값을 지정하는건 그다지 큰 문제가 없고 다른 사이트에서 많이 다루는 예제이다. 


스크롤바 깊게 들어가기


지금은 스크롤바 페이지에 대해서 보도록 하겠다. 페이지는 스크롤바 가운데 있는 스크롤상자 크기에 대한 이야기이다. 스크롤상자는 때에 따라서 커지고 작아지기도 한다. 손오공 여의봉처럼 마음대로 커지고 마음대로 작아지는 놈일까?
그렇지 않다. 사용 목적이 있기 때문에 크기가 그에 따라 변경이된다.

스크롤바 크기는 페이지 크기이다. 한페이지에 들어가는 값 개수이다. 어차피 정수이니 한페이지에 들어가는 정수값 크기라고 보면 된다.

페이지 크기라고 하면 감이 안잡힌다. 예를 들어 책을 살펴보는게 쉽게 이해할 수 있다.
책에는 방대한 양의 글자들이 들어가 있다. (물론 그림, 사진 등도 있다^^;) 모든 내용을 하나의 종이메 모두 담지 못했기에 페이지 단위로 나눠서 표시한다.

예를 들어, 총 1234줄의 내용이 있고 한페이지에 들어가는 줄수는 100줄이라고 가정하면 총 페이지 수는 얼마가될까?

답은 13 페이지
마지막 12페이지를 꽉채우고 34줄이 남지만 한 페이지는 반으로 나눌 수는 없기에 1페이지로 만들어서 넣는다. 추가로 표지, 목차, 속지, 인지 등을 포함하면 더 늘어날 수 있지만 ㅡ.ㅡㅋ

마찬가지로 컴퓨터 화면도 방대한 내용을 한화면에 모두 표시할 수 없기에 페이지 단위로 나눠서 표시한다. 책과 다른 점은 컴퓨터는 연속적으로 페이지를 볼 수 있다.

앞의 책의 예를 일반 텍스트 문서라고 가정해서 스크롤바 설정을 해보자.

최대 최소 값 범위: 0~1234
페이지크기(스크롤박스 크기): 100


너무 쉬어 보인다. 내가 설명을 잘해서인가? ㅋㅋㅋ

그러나 주의할 점이 있다. 바로 스크롤박스가 움직일 수 있는 최대값이 스크롤바 최대값과는 틀리다.
이는 스크롤박스 크기에 따라 가변적이기에 주의해야한다.

사용자 삽입 이미지

Fig 3. Scroll Bar 값들

위 그림은 스크롤바에서 사용되는 값을 표시하였다.
스크롤박스 왼쪽 경계가 현재 값이다. (Current Position)
스크롤바 양쪽 버튼을 제외한 영역이 스크롤바 전체 값 범위이다.(MAX Range Value)
그리고, 양쪽 버튼과 스크롤박스 크기를 제외한 나머지 영역이 스크롤박스가 움직일 수 있는 범위이다.(MAX Scroll Pos)

여기서 중요한 값이 MAX Scroll Pos이다. 현재 위치(Current Position)이 MAX Scroll Pos값을 넘을 수 없다. 단, 최소값은 항상 0으로 가정한다.

0 <= Current Position <= MAX Scroll Pos

그럼 MAX Scroll Pos을 구하는게 중요하다.

MAX Scroll Pos = MAXRangeValue - (Page Size - 1)

Page Size에서 -1은 당연히 Page Size 왼쪽 경계까지 값 범위이기 때문이다. 이를 앞에 책의 예를 이용해서 다시 스크롤바 설정을 해보자.

최대 최소 값 범위: 0~1234
페이지크기(스크롤박스 크기): 100
스크롤박스 이동 범위: 0 ~ 1135




스크롤바 전문가 과정

좀더 스크롤바를 깊게 들어가자. 지금 부터 조금 머리 아파질 수 있으니, 지금 머리가 조금 아프신 분들은 창문가서 밖같 하늘 한번 구경하자.

지금 다를 내용은 크게 두가지 이다. 하나는 프로그램 크기(resize)와 데이터 변경되는 경우와 다른하나는 스크롤을 좀더 세밀하기 하기 위해 스크롤바 최대 최소 범위를 변경하는 경우이다.


프로그램 크기와 데이터 변경

먼저 프로그램 크기와 데이터가 변경되는 경우를 살펴보자.
프로그램 크기가 변경되는 의미는 내용이 나타나는 화면 크기가 바뀌었다는 의미이고 스크롤 바에서는 한 화면에 표시되는 크기를 가리키는 스크롤박스 크기가 달라졌다는 의미이다.

앞의 책의 예를 보면 한페이지에 표시할 수 있는 줄수가 100줄에서 130줄 혹은 50줄로 커지거나 작아졌다는 의미이다.
일단 내용 변경이 없다면 스크롤바 최대 최소 값 범위은 변경되지 않고 페이지 크기가 변경되었고, 즉, 스크롤박스가 이동할 수 있는 범위가 변경되었다는 의미이다.

책의 예제에서 한페이지(한화면)에서 표시할 수 있는 줄수가 100줄에서 130줄로 변경되었다면 스크롤바 설정을 살펴보자.

스크롤바 최대 최소 값 범위: 0 ~ 1234
페이지크기(스크롤박스 크기): 100 -> 130 (변경)
스크롤박스 이동 범위: 1234 - (130 - 1) = 1103 (변경)
페이지수: 10 페이지 (이는 스크롤바 설정 값은 아니다.)


그리고 데이터가 변경되었다면 어떻게 될까?
일단 스크롤바 최대 최소 값 범위가 변경된다. 페이지 크기는 고정이지만, 스크롤 박스 이동 범위도 바뀌게 된다. 즉, 전체 크기가 변경되었으므로 이동가능한 범위도 변경되었다는 의미이다. 그럼 마찬가지로 앞의 책의 예로 계산해보자.
가정은 데이터 량이 1234줄에서 1500줄로 늘어낳고 한 페이지 크기는 130줄로 계산해보자.

스크롤바 최대 최소 값 범위: 0 ~ 1500 (변경)
페이지크기(스크롤박스 크기): 130
스크롤박스 이동 범위: 1500 - (130 - 1) = 1371 (변경)
페이지수: 12 페이지 (이는 스크롤바 설정 값은 아니다.)


화면 크기 혹은 데이터 크기 변경은 각각 페이지 크기 변경 혹은 스크롤바 최대 값 변화가 따로 생기지만 스크롤박스 이동 범위는 둘 다 새로 계산해야 된다.


스크롤바 정밀도 조절하기

데이터 크기와 스크롤바 크기가 일치하지 않은 경우를 살펴보자.
앞에서는 텍스트 한줄이 스크롤바 한스텝과 일치한다. 스크롤바에서 3값이 움직이면 텍스트에서 3줄이 움직인다.

간혹 1 스텝 이동이 1/2 줄 이동이나 1 스텝 이동이 2줄 이동으로 할 경우도 있다.

사용자 삽입 이미지

Fig 4. 1스텝 이동시 반줄 이동


이 그림은 1 스텝 이동은 반 줄 이동하는 예를 보여둔다. 즉 2 스텝 이동해야 한 줄이 이동된다는 의미이다. 즉 한 스텝 이동하면 글자 반정도 크기만 움직이고 화면 경계에 있다면 반은 보이고 반은 가려서 보이지 않게된다. 한 스텝이 글자 반 정도 움직이는 느린 스크롤이 된다.

사용자 삽입 이미지

Fig 5. 1스텝 이동시 2줄 이동



이 그림은 1 스템 이동이 2줄 이동하는 예이다. 즉, 반 스텝 이동이 한줄 이동이지만 반 스텝 이동은 없다. 스크롤 바는 정수 값만 사용하기 때문이다.
한스텝 이동은 2줄이 한꺼번에 움직이므로 빠른 화면 스크롤을 볼 수 있다.

그러면 위와 같은 경우 스크롤바 값 설정은 어떻게 될 것인다.
간단하게 계산하기 위해서 텍스트 줄수는 100줄이고 한화면 표시되는 페이지 크기는 10라고 하자.


1스텝에 1/2줄 이동

먼저 한 스텝에 반 줄 이동하는 예를 보자.
즉, 한줄이 2스텝을 차지하므로 총 100줄이므로,

100줄 x 2 스텝 / 줄 = 200 스텝

결국 스크롤바 값 범위가 0 ~ 200를 가진다. 좀더 생각을 하면 앞에서 스크롤바는 정수값만 사용한다고 했지만, 위의 값의 범위는 0~100줄은 0.5줄 단위까지 잘라서 얻을 수 있다는 의미이다.
페이지 크기가 10는 스템 수가 아닌 화면에 나타나는 줄 수 이다. 그러면 페이지 크기는

10줄 x 2 스텝 / 줄 = 20 스텝

페이지 크기는 20스텝이 된다.
그러면 스크롤박스 최대 이동 가능한 값이 계산된다.

스크롤박스 최대 이동 값 = 200 - (20 - 1) = 181

스크롤박스 최대 이동 값은 181이 된다.


1스텝에 2줄 이동

다음으로 1스텝이 2줄 이동하는 예를 살펴보자. 앞의 계산 법의 확인일 뿐이다.
앞의 계산 법에 의해서 단위 줄에 변하는 스텝 값은 1/2이 된다.

스크롤바 최대값: 100줄 x 1/2 스텝/줄 = 50 스텝
페이지 크기: 10줄 x 1/2 스텝/줄 = 5 스텝
스크롤박스 최대 이동 값: 50 - (5 - 1) = 46


계산 방법은 동일하다. 이부분은 텍스트를 예로 들어서 설명했지만, 그래픽 처리에서 상당히 유용하리라 생각한다.

 

기타강좌:
스크롤바 강좌: http://www.winapi.co.kr/win32lec/lec7/lec7-5-1.htm

반응형
반응형

hci2-lecture5-ch5[1].pdf


비클라이언트 영역 메세지

함수, 메세지

반응형
반응형

툴바를 주석처리해야 메세지가 제대로 들어온다

반응형
반응형

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=820288&ref=820288

Feature Pack sample 중에 RibbonGadgets 라는 sample이 있습니다.

(아래 그림 참조) 리본바에서 color를 지정하고 나서 어떻게 색상 값을 받아와야 할지 모르겠네요?

 

 

 

 

<페널에 CMFCRibbonColorButton 추가>

 

bNameValid = strTemp.LoadString(IDS_RIBBON_PEN3);
 ASSERT(bNameValid);
CMFCRibbonColorButton* pBtnPen3 = new CMFCRibbonColorButton(ID_OBJECT_PEN3, strTemp, 2);
 pBtnPen3->EnableAutomaticButton(_T("&Automatic"), RGB(0, 0, 0));
 pBtnPen3->EnableOtherButton(_T("&More Colors..."), _T("More Colors"));
 pBtnPen3->SetColumns(10);
 pBtnPen3->SetColorBoxSize(CSize(17, 17));
 pBtnPen3->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
 pBtnPen3->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
 pBtnPen3->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
 pPanelObject->Add(pBtnPen3);

 

<ID_OBJECT_PEN3 메뉴 버튼 에서>

void CMainFrame::OnObjectPen3()
{
 // TODO: Add your command handler code hee

// 여기서 처리를 어떻게 해야 하는지요?

// 요거 저거 해도 안되는군요...

CMFCColorButton m_wndColor;

 CString str;
 COLORREF color = m_wndColor.GetColor();
 str.Format(_T("%d,%d,%d"), GetRValue(color), GetGValue(color), GetBValue(color));
 SetOutput(str);
}

 

void CMainFrame::OnUpdateObjectPen3(CCmdUI *pCmdUI)
{
 // TODO: Add your command update UI handler code here
}

 

시원한 답변 부탁드립니다.

이 글에 답변 등록하기
[채택답변] 상콤한 답변 -_-
0
2010-03-18 오전 1:12:12
 질문자 인사 :답변 갑사합니다.
처음에는 안되서 왜 그런가 했는데..
제가 SDI라서 CMDIFrameWndEx를 CFrameWndEx로 변경하니 
잘 됩니다..
정말 감사합니다.
  오새롬 (diebuster)  오새롬님께 메시지 보내기오새롬님을 내 주소록에 추가합니다.오새롬님의 개인게시판 가기번호: 820292  

    CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar(); 
    ASSERT_VALID(pRibbon); 


    CMFCRibbonColorButton* pColor = DYNAMIC_DOWNCAST( CMFCRibbonColorButton, pRibbon->FindByID(ID_OBJECT_PEN3));
    // Get the selected color 
    COLORREF color = pColor->GetColor();

 

 [답변]상콤한 답변 -_-2010-03-17 오후 11:58:36
오새롬 (diebuster)  오새롬님께 메시지 보내기오새롬님을 내 주소록에 추가합니다.오새롬님의 개인게시판 가기번호: 820292  추천:0  

    CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar(); 
    ASSERT_VALID(pRibbon); 


    CMFCRibbonColorButton* pColor = DYNAMIC_DOWNCAST( CMFCRibbonColorButton, pRibbon->FindByID(ID_OBJECT_PEN3));
    // Get the selected color 
    COLORREF color = pColor->GetColor();

 

이 글에 답변 등록하기
         [답변]에러가 발생합니다.2010-03-18 오전 12:44:55
김정곤 (fdsdasom)  김정곤님께 메시지 보내기김정곤님을 내 주소록에 추가합니다.김정곤님의 개인게시판 가기번호: 820297  추천:0  

늦은시간인데 이렇게 답변 주셔서 감사합니다.

 

님께서 말씀 하신 방법을  적용 했습니다. 색을 선택하면 에러가 발생합니다.

 

디버깅 해 보니  CXX0030: Error: expression cannot be evaluated  이런 에러가 발생하네요!

 

그리고 저는 SDI에서 하고 있는데요 CMDIFrameWndEx* 이게 사용 가능 한건가요?

 

void CMainFrame::OnObjectPen3()
{

CString str;

 CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar(); 
 ASSERT_VALID(pRibbon); 


 CMFCRibbonColorButton* pColor = DYNAMIC_DOWNCAST( CMFCRibbonColorButton, pRibbon->FindByID(ID_OBJECT_PEN3));


 // Get the selected color 
 COLORREF color = pColor->GetColor();


 str.Format(_T("%d,%d,%d"), GetRValue(color), GetGValue(color), GetBValue(color));
 SetOutput(str);


}

 

소스를 보면 color가 크게 두가지 정도로 분류가 됩니다.

 

한가지는 펼처진 경우 보여지는 색상이구요, 다른 한가지는 other나 more 를 선택했을 때 나오는 ColorDlg입니다.

 

이둘을 같이 사용 하고 있는데 둘 중에 어떤것이 선택 되었는지도 알 수 가 없습니다. 이 것도 알 수 있는 방법이 없을 까요?

이 글에 답변 등록하기
                 [답변]CFrameWndEx2010-03-18 오전 1:33:30
오새롬 (diebuster)  오새롬님께 메시지 보내기오새롬님을 내 주소록에 추가합니다.오새롬님의 개인게시판 가기번호: 820299  추천:0  

CMFCRibbonBar* pRibbon = ((CFrameWndEx*) AfxGetMainWnd())->GetRibbonBar(); 


반응형
반응형

MFC에서 Doc/View 구조가 아닌 프로젝트를 생성하여, MainFrame에서 View클래스의 포인터를 얻기 위해 GetActiveView()함수를 사용하니 NULL을 반환

그냥, 
View.cpp 파일에서 전역변수로 선언하고 OnCreate시에 자기를 할당하고, MainFrame에서는 extern으로 받아서 사용하니 동작됨. 하지만, 좀 더 안전이 보장되는 방법을 알아야 할 필요성이 있음

Example.
MainView.cpp
CMainView * pMainView;
int CMainView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
pMainView = this;
}


MainFrm.cpp
extern CMainView * pMainView;

// 함수내에서
pMainView->SetTranslationDirection(Y, m_bTranslation[Y]);




알아냄. CMainFrame class내에 view의 객체가 존재함 -_-;
저작자 표시 비영리
if(/MSIE [0-6]\./.test(navigator.userAgent)){for(var i=0;i<2;i++){var el=document.getElementById('ccl-icon-23-'+i);el.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+el.src+'",sizingMethod="image")';el.src='http://cfs.tistory.com/static/admin/form/s.gif';}}
 [출처 : http://chaoskcuf.com]

1. 개요 

MFC 9.0 Beta 버전에 포함된 Office 2007 스타일의 Ribbon Bar를 만드는 방법을 알아본다. 
(Application Wizard가 자동으로 생성하는 코드에 대한 이해를 목적으로 한다.)

 

2. 프로젝트 생성


  ProjectStyleSetting 
[그림 1 Application Type]

a) [그림 1]과 같이 Project Style을 Office로 선택하고 마음에 드는 Style Thema를 선택한다. 
(여기서 주의할 점이 있는데 Enable visual style switching 체크를 해제하게 되면 컴파일 에러가 나게 되는데, 물론 쉽게 에러나는 곳을 고칠 수 있으나 성가신 사항이므로 일단 체크를 하자. 컴파일 에러에 관한 내용은 다음 기회에 포스팅할 예정이다.)


ProjectUIFeatures 
[그림 2 User Interface Features]

b) [그림 2] 와 같이 User Interface Features의 옵션을 선택하는 부분에서 우리는 Ribbon Bar를 사용하여야 하기 때문에 User a ribbon 라디오 버튼에 체크하자. (뭐 기본 선택사항이니 가만히 두어도 된다)


 ProjectAdvancedFeatures 
[그림 3 Advanced Features]

c) [그림 3]에 보면 Advanced docking panes 옵션을 보면 5가지를 추가로 선택할 수 있다. 
위의 3개의 체크 박스는 Visual Studio Style의 프로젝트를 만들때 흔히 쓰일 듯한 옵션이다. 
4번째의 Navigation pane은 쉘 폴더 트리뷰와 달력 뷰가 샘플로 들어가는 옵션인데 일단 지금은 Ribbon Bar에 집중하기 위해서 일단 체크를 해제하도록 한다. 5번째의 Caption bar는 Ribbon bar 밑에 나오는 녀석으로 사용자에게 간단한 메세지를 출력해주는 기능을 하는 것으로 예를 들면 IE에서 보안설정으로 파업차단, ActiveX  설치시 삑 하고 나타나는 영역이라고 생각하면 되겠다.

d) 여기까지 했다면 Finish 버튼을 클릭하면 프로젝트를 생성할 수 있는데, 바로 빌드를 해보면 [그림 4]와 같이 정말 Office 2007스러운 미려한 디자인의 프로그램을 만날 수 있다.

SampleUI 
[그림 4 샘플]

 

3. Application Wizard가 생성한 코드 이해하기


a) CMainFrame의 OnCreate 이해 하기

MFC 8.0 이하의 버전에서는 MDI 프로젝트에서 CMainFrame 클래스는 CFrameWnd를 상속받았었다. 그러나 리본바를 사용하기 위해서는 CFrameWnd 클래스 대신에 이의 확장 버전인 CMDIFrameWndEx 클래스를 상속받고 있다. 아래의 코드는 Wizard가 자동으로 생성해주는 코드인데 MFC 8.0 이하 버전과의 차이점을 중심으로만 살펴보기로 하겠다.

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 

    if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1) 
        return -1; 
    // set the visual manager and style based on persisted value 
    OnApplicationLook(theApp.m_nAppLook); 

    CMDITabInfo mdiTabParams; 
    mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // other styles available... 
    mdiTabParams.m_bActiveTabCloseButton = TRUE;      // set to FALSE to place close button at right of tab area 
    mdiTabParams.m_bTabIcons = FALSE;    // set to TRUE to enable document icons on MDI taba 
    mdiTabParams.m_bAutoColor = TRUE;    // set to FALSE to disable auto-coloring of MDI tabs 
    mdiTabParams.m_bDocumentMenu = TRUE; // enable the document menu at the right edge of the tab area 
    EnableMDITabbedGroups(TRUE, mdiTabParams); 

    m_wndRibbonBar.Create(this); 
    InitializeRibbon(); 

    if (!m_wndStatusBar.Create(this)) 
    { 
        TRACE0("상태 표시줄을 만들지 못했습니다.\n"); 
        return -1;      // 만들지 못했습니다. 
    } 

    CString strTitlePane1; 
    CString strTitlePane2; 
    strTitlePane1.LoadString(IDS_STATUS_PANE1); 
    strTitlePane2.LoadString(IDS_STATUS_PANE2); 
    m_wndStatusBar.AddElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE1, strTitlePane1, TRUE), strTitlePane1); 
    m_wndStatusBar.AddExtendedElement(new CMFCRibbonStatusBarPane(ID_STATUSBAR_PANE2, strTitlePane2, TRUE), strTitlePane2); 

    // enable Visual Studio 2005 style docking window behavior 
    CDockingManager::SetDockingMode(DT_SMART); 
    // enable Visual Studio 2005 style docking window auto-hide behavior 
    EnableAutoHidePanes(CBRS_ALIGN_ANY); 

    // Create a caption bar: 
    if (!CreateCaptionBar()
    { 
        TRACE0("Failed to create caption bar\n"); 
        return -1;      // 만들지 못했습니다. 
    }

    // Enable enhanced windows management dialog 
    EnableWindowsDialog(ID_WINDOW_MANAGER, IDS_WINDOWS_MANAGER, TRUE);

    return 0; 
}

  • 처음 부분에 등장하는 생소한 함수가 보일 것이 바로 OnApplicationLook()라는 함수인데, 이 함수는 바로 Look & Feel을 선택할 수 있게 해주는 CMDIFrameWndEx 의 센스쟁이 멤버 함수이다. 파라미터로 넘어가는 thhApp.m_nAppLook 은 CMainFrame의 생성자에서 대입된다. 아래와 같이 정의된 값을 대입해보면서 스타일이 어떻게 변하는지 직접 느껴보기 바란다.
    • ID_VIEW_APPLOOK_WIN_2000
    • ID_VIEW_APPLOOK_OFF_XP
    • ID_VIEW_APPLOOK_WIN_XP
    • ID_VIEW_APPLOOK_OFF_2003
    • ID_VIEW_APPLOOK_VS_2005
    • ID_VIEW_APPLOOK_OFF_2007_BLUE
    • ID_VIEW_APPLOOK_OFF_2007_BLACK
    • ID_VIEW_APPLOOK_OFF_2007_SILVER
    • ID_VIEW_APPLOOK_OFF_2007_AQUA

EnableMDITabbedGroups  
[그림 5 예전 MDI 방식]

  • MDI 형식의 프로젝트이기 때문에 여러개의 문서를 어떤 식으로 표시를 해줄 것인지를 결정하는 함수가 EnableMDITabbedGroups() 이다. 첫번째 파라미터를 FALSE로 넘기면 Tab 방식으로 문서를 정렬하는 방식이 아닌 [그림 5]와 같이 예전 MDI 방식으로 사용할 수 있다. 
    두번째 파라미터로 넘기는 CMDITabInfo 클래스는 아래와 멤버 변수를 public으로 가지고 있다.

class CMDITabInfo 

public: 
    CMDITabInfo(); 
    void Serialize(CArchive& ar);

    CMFCTabCtrl::Location m_tabLocation;    // Tab에 위치를 아래에 둘지 위의 둘지 선택 (기본 위) 
    CMFCTabCtrl::Style    m_style;                // Tab Look & Feel 선택 (아래 참조)

    BOOL m_bTabIcons;                              // Tab에 아이콘을 표시할 것 인지 
    BOOL m_bTabCloseButton;                     // Tab에 닫기 버튼을 표시할 것 인지  (m_bActiveTabCloseButton 가 FALSE 일 때)

    BOOL m_bTabCustomTooltips; 
    BOOL m_bAutoColor;                             // 새로운 문서가 추가될 때 마다 Tab의 색상이 바뀔것 인지 
    BOOL m_bDocumentMenu;                     // 문서가 많이 열렸을 때 좌우 스크롤을 할지 Menu에 표시할 지       
    BOOL m_bEnableTabSwap;                    // 드래그 앤 드랍으로 탭의 위치를 변경할 수 있게 만들지 
    BOOL m_bFlatFrame;                             // Frame 의 모습 
    BOOL m_bActiveTabCloseButton;            // 활성화된 Tab에 닫기 버튼이 표시되게 할 지 Tab영역 오른쪽 가장자리에  표시할 지 
    int  m_nTabBorderSize;                          // Frame Border의 굵기 
};

  • CMdITabInfo의 m_style이라는 멤버 변수는 아래와 같은 값을 가질 수 있다.
    • STYLE_3D
    • STYLE_FLAT
    • STYLE_FLAT_SHARED_HORZ_SCROLL
    • STYLE_3D_SCROLLED
    • STYLE_3D_ONENOTE       
    • STYLE_3D_VS2005       
    • STYLE_3D_ROUNDED                     
    • STYLE_3D_ROUNDED_SCROLL
  • InitializeRibbon() 함수에 리본바를 구성하는 모든 코드들이 속해있다. (기본적으로 Wizard가 샘플로 만들어 놓은 함수이다)

 

b) Main Category 부분 구성하기

MainPanel(desc) 
[그림 6 Main Category의 구성]

MFC 9.0과 같이 나온 미려한(?) 디자인의 MFC이 아이콘이 속해있는 버튼이 보이는가? 그 버튼을 누르면 위의 [그림 6]처럼 Main Category라는 익숙한 창이 나타나게 되는데 일단 MainCategory를 뛰워주게 하는 이 Application Button이라고 부르는 녀석을 먼저 살펴보도록 한다. 

CMainFrame는 멤버 변수로 CMFCRibbonApplicationButton class의 객체를 m_MainButton라는 이름으로 가지고 있다. 이 버튼의 이미지는 Bitmap파일의 리소스 아이디를 SetImage함수를 통해 전달해 주면 된다. 

그리고 Alt 키를 누르면 각각의 Ribbon Element들이 가지는 단축키들이 표시되는데, 이 단축키를 세팅해주는 방식 두가지가 있다.

m_MainButton.SetText(_T("\nf"));  // Element의 이름과 단축키를 동시에 설정하는 방법 
m_MainButton.SetKeys(_T("f"));      // 단축키 값만을 설정하는 방법


그런데 한가지 의문점이 든다. SetText의 문자열이 개행문자로 시작하는 부분이다. 
CMFCRibbonApplicationButton의 멤버함수(정확히는 CMFCRibbonBaseElement의 멤버함수) SetText 함수는 단축키와 표시될 이름을 동시에 설정하는 함수이다. 단, 위와 같이 '\n' 개행문자를 구분자로 표시될 이름과 단축키가 한 문자열로 전달되어야 한다. m_MainButton에 SetText를 하는 것은 약간 이례적인 경우인데, Application Button(m_MainButton)은 [그림 6]을 보다시피 문자열로 표현되는 부분이 없다. 그래서 SetText함수를 사용하여

m_MainButton.SetText(_T("MainButton!\nf"));


위와 같이 코딩하여도  '\n' 앞의 문자열 MainButton은 쓰여질 곳은 없기 때문에 굳이 넣지 않아도 된다
이제 의문이 해소되었는가? 
아직도 이상하다고 생각되면 그냥 SetKeys함수를 사용하여 그 의미를 명확하게 하자.

참고로 사실 Application Wizard가 생성해주는 코드에 저 부분이 들어있어서 설명해주고 싶었다. 
ApplicationButton의 경우 이상하다고 느낄지는 모르겠지만 예를 들어 다른 Ribbon Element 들을 만들때 생성자로

CMFCRibbonButton* pBtnPaste = new CMFCRibbonButton(ID_EDIT_PASTE, _T("Paste\nV"), 0, 0);


와 같이 두번째 파라미터로 문자열 값을 넣었을 때 생성자 내부에서 CMFCRibbonBaseElement의 SetText함수를 호출하게 되어 있어서 그 Element는 Paste라는 이름을 가지게 되고 단축키는 V를 가지게 된다. 
주의할 점은 소문자를 넣어도 Alt를 눌렀을 때의 모든 단축키의 모습은 아래 그림과 같이 대문자로 나온다는 것이다.

Keys 
[그림 7 단축키 표현 방식]

마지막으로 버튼이라면 마우스가 오버 했을 때 툴팁을 뛰워주야하지 않겠는가? 그래서 그 툴팁 텍스트를 설정하는 부분이 바로

m_MainButton.SetToolTipText(_T("File"));


SetToolTipText 함수를 사용하는 부분이다.

이렇게 하면 Button에 대한 속성은 거의 다 정해준 것 같다. 
그러나 여기까지는 그냥 버튼을 하나 생성시켜서 메모리 어느 공간에 있을 뿐이다. 
이 버튼이 ApplicationButton이다!! 라고 설정을 시켜주어야 한다.

OnCreate 함수에서 Create 시켜주었던 RibbonBar 객체가 생각나는가? 그 RibbonBar에다 이 버튼이 Application이고 버튼 크기는 얼마였으면 좋겠다라고 등록시켜주는 함수가 있다.

m_wndRibbonBar.SetApplicationButton(&m_MainButton, CSize (45, 45)); //가로 45px, 세로 45px 크기로 ApplicationButton으로 등록


위의 코드처럼 SetApplicationButton이라는 함수인데, 만약에 위와 같이 m_MainButton을 RibbonBar에 저 함수를 통해 등록하지 않으면 어떻게 될까?

WithoutAppButton 
[그림 8 Application Button이 없는 리본바]

[그림 8] 처럼 ApplicationButton이 없는 UI가 나타난다. 
경우에 따라  ApplicationButton이 없는 경우를 선호할 때는 CMFCRibbonApplicationButton 을 설정하고 RibbonBar에 등록하는 부분을 주석처리하면 그 뿐인 것이다.

길게 길게 ApplicationButton에 대해서 설명을 했다. 
그렇다면 이번에는 [그림 6] 처럼 MainCategory에 New Open 처럼 항목을 집어 넣는 부분을 살펴보자. 
일단 MainCategory는 좀 특이하다. 
RibbonBar에 항상 나타나 있는 것이 아니라 ApplicationButton을 통해서 나타나는 것도 그렇고, 기본적으로 MDI 프로그램에 꼭 필요한 항목들만 들어 있다. 그래서인지 RibbonBar에서는 AddMainCategory 함수가 따로 존재한다. 
(뒤에 보면 알겠지만 그냥 AddCategory 함수가 있다. AddCategory는 여러 카테고리를 추가할 수 있지만, AddMainCategory는 당연히 한번만 호출 되어서 하나의 MainCategory만 존재해야 한다.)

CMFCRibbonMainPanel* AddMainCategory( 
   LPCTSTR lpszName,                           // 메인카테고리의 이름 
   UINT uiSmallImagesResID,                   // 작은 이미지 리소스 아이디 
   UINT uiLargeImagesResID,                   // 큰 이미지 리소스 아이디 
   CSize sizeSmallImage=CSize(16, 16) ,  // 작은 이미지 하나의 크기 
   CSize sizeLargeImage=CSize(32, 32)   // 큰 이미지 하나의 크기 
);


너무나 당연한 이야기지만, 리소스에 포함된 이미지는 파라미터로 넘겨주는 크기의 이미지 조각을 연속적으로 붙여놓은 하나의 이미지여야한다.

CMFCRibbonMainPanel* pMainPanel = m_wndRibbonBar.AddMainCategory(_T("File"), IDB_FILESMALL, IDB_FILELARGE);

그런데 여기서 질문.

  1. 메인 카테고리 이름이라고 준 File 이라는 문자열이 Application을 눌러봐도 나오는 부분이 없는 것 같다
  2. MainCategory창에는 전부 큰 이미지(Large Icon)만 보이는데 굳이 작은 이미지를 넣을 필요가 있는가?

차근 차근 위의 질문에 대한 답을 찾아보자. 
정답은 QAT(Quick Access Toolbar)의 지원때문이라고 간단히 말할 수도 있겠다.

CustomizeQAT 
[그림 9 QAT]

Office UX에서 사용자가 가장 자주 쓰는 기능을 ApplicationButton 옆에 보이는 QAT로 모아서 편리하게 쓸 수 있게끔 하는 것이 있다. 
그 옆에  아래로 향하는 화살표 부분을 클릭하면 QAT를 Customize할 수 있는 메뉴가 나타난다.

QATMenu

반응형
반응형

http://zeroone.tistory.com/tag/Ribbon

////////////////////////////////////////////////////////////////////////////////////

 

 

 

 

 

 

출처 - http://zeroone.tistory.com/entry/How-To-%EA%B8%B0%EC%A1%B4-MFC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-Ribbon-UI-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0

 

기존 MFC Scribble Sample에 VS2008 Feature Pack에 포함된 MFC의 Ribbon UI를 적용해 보겠습니다.

Visual C++ 2008 Feature Pack Download
Visual C++ 2008 Feature Pack Documentaion

우선 기존 Scribble Sample을 가져 와서
 VS 2008 로 Open 합니다.
\Microsoft Visual Studio 9.0\Samples\1033\AllVCLanguageSamples\C++\MFC\ole 에 위치해 있습니다.

1.
 afxcontrolbars.h 헤더 추가
우선 리본을 적용하기 위해서 헤더를 포함하여야 합니다. 
stdafx.h 파일을 열어 상단에 afxcontrolbars.h 를 include합니다.

#ifndef WINVER
#define WINVER 0x0600
#endif
#include <afxcontrolbars.h>


2008에서 부터는 WINVER가 Default로 Define되어 있지 않습니다.  따라서 WINVER를 명시적으로 선언하지 않으면 Warning을 표시하고 Default로 0x0600 (Vista)로 선언됩니다. 

class CScribbleApp : public CWinAppEx
{
scribble.cpp 를 열어 다음을 추가 합니다.

LoadStdProfileSettings();  // Load standard INI file options (including MRU)
SetRegistryKey(_T("MFCNext\\Samples\\Scribble2"));
SetRegistryBase(_T("Settings"));

기존 Scribble프로젝트 에서는 ini방식을 사용하므로 자동으로 저장되는 프로그램설정을 위해 레지스트리를 사용하도록 변경합니다.

3. MainFrame 클래스 변경
mainfrm.h를 열어 CMDIFrameWnd를 CMDIFrameWndEx로 변경합니다.

class CMainFrame : public CMDIFrameWndEx
{

상속클래스가 변경되었으니 mainfrm.cpp를 열어 모든 CMDIFrameWnd를 CMDIFrameWndEx로 변경하여야 겠지요?  변경합니다.  
CMDIFrameWnd를 CMDIFrameWndEx로 한번에 Replace하는것이 빠르겠지요..

변경되는 코드 모두 펼치기


4. ChildWnd 클래스 변경 하기
childfrm.h를 열어 CMDIChildWnd을 CMDIChildWndEx로 변경합니다.

class CChildFrame : public CMDIChildWndEx
{

childfrm.cpp를 열어 모든 CMDIChildWnd를 CMDIChildWndEx로 변경합니다.

변경되는 모든 코드


5. CToolBar, CStatusBar, CMenuBar
mainfrm.h을 열어 CToolBar는 CMFCToolBar로 CStatusBar는 CMFCStatusBar로 변경하고 CMenuBar는 삭제하도록 합니다.  리본을 적용하면 CMenuBar는 사용하지 않습니다.

protected:  // control bar embedded members
    CMFCStatusBar  m_wndStatusBar;
    CMFCToolBar    m_wndToolBar;
    HICON m_hIcon;

mainfrm.cpp를 열어 변경된 클래스의 함수를 적용하여 줍니다.  SetBarStyle -> SetPaneStyle로 GetBarStyle -> GetPaneStyle로 적용합니다. 

    // TODO: Remove this if you don't want tool tips
    m_wndToolBar.SetPaneStyle(m_wndToolBar.GetPaneStyle() |
        CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

또한 DockControlBar를 DockPane으로 변경합니다.

DockPane(&m_wndToolBar);


컴파일이 될것입니다.  실행하면 기존과 동일하게 동작합니다.

6. Ribbon Bar 추가
mainfrm.h에 RibbonBar를 추가 합니다.

    CMFCRibbonBar                     m_wndRibbonBar;  // Ribbon bar for the application
    CMFCRibbonApplicationButton m_MainButton;       // The application button for the ribbon
    CMFCToolBarImages              m_PanelImages;     // Ribbon Panel Icons


7. 리본에서 사용할 아이콘 Import하기
리본을 테스트 하기 위해서 우선은 3가지 Bitmap이 필요로 합니다.

사용자 삽입 이미지


<- Main Application 버튼에 넣을 이미지  ( IDB_RIBBON_MAIN )

사용자 삽입 이미지


<- Large Panel Icon ( IDB_RIBBONLARGE )

사용자 삽입 이미지

<- Small Panel Icon ( IDB_RIBBONSMALL )

위와 같은 이미지를 리소스에 Import하여 주세요..

8. Ribbon Create하고 Main Application을 추가
이제 드디어 Ribbon을 추가 합니다. OnCreate 함수 상단에 다음의 코드를 추가 합니다.

    if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
        return -1;

    // Create the ribbon bar
    if (!m_wndRibbonBar.Create(this))
    {
        return -1;   //Failed to create ribbon bar
    }

Ribbon Bar가 생성되었습니다.  이제 Main Button을 등록합니다.

    // application button
    m_MainButton.SetImage(IDB_RIBBON_MAIN);
    m_MainButton.SetToolTipText(_T("File"));
    m_MainButton.SetText(_T("\nf"));

    // Attach it to ribbon
    m_wndRibbonBar.SetApplicationButton(&m_MainButton, CSize(45,45));

RibbonBar에 MainButton을 설정하였습니다.  컴파일을 하여 실행하면 아래와 같이 실행됩니다.

사용자 삽입 이미지


리본바가 나타납니다.  그런데 어딘가 이상하죠?  코드를 수정해 나가면서 점점 모습을 갖추어 갈것입니다. 

9. 메인 Category 추가 하기
메 인버튼을 클릭하면 나오는 Main Category을 등록합니다.  AddMainCategory인데 MainPanel을 리턴하는군요 ^__^;... 그다음 버튼들을 추가 합니다.  리본 메인 Panel안에 위치할 버튼들입니다.  보통 File 관련 메뉴들이 위치하게 되겠지요..  여기서 Command ID들은 기존 메뉴 또는 ToolBar에서 사용하는것을 그대로 사용하면 됩니다.  메인 Panel에 넣은 두개의 Bitmap으로 각 버튼의 큰아이콘과 작은 아이콘을 결정할수 있습니다.

    // Main Category
    CMFCRibbonMainPanel* pMainPanel = m_wndRibbonBar.AddMainCategory(_T("File"),                  IDB_RIBBONSMALL, IDB_RIBBONLARGE);
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_NEW, _T("&New"), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN, _T("&Open"), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_CLOSE, _T("&Close"), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE, _T("&Save"), 0, 0 ));
    pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS, _T("Save &As..."), 0, 0 ));

자, 컴파일 하고 실행해 볼까요?

사용자 삽입 이미지

메인 버튼을 클릭하면 메뉴가 나타납니다.  메인 Panel이 생겨났네요..

이제 Print 관련 버튼을 설정합니다.  Print관련 버튼은 새로운 Sub메뉴가 생겨나는 버튼이기 때문에 서브버튼을 넣습니다.

    // Add Print Button
    CMFCRibbonButton* pBtnPrint = new CMFCRibbonButton( ID_FILE_PRINT, _T("&Print"), 4, 4 );
    pBtnPrint->AddSubItem( new CMFCRibbonLabel(_T("Preview and print the document") ) );
    pBtnPrint->AddSubItem( new CMFCRibbonButton( ID_FILE_PRINT, _T("&Print"), 4, 4, TRUE ) );
    pBtnPrint->AddSubItem( new CMFCRibbonButton( ID_FILE_PRINT_PREVIEW, _T("Print Pre&view"), 6, 6, TRUE ) );
    pBtnPrint->SetKeys( _T("p"), _T("w") );
   
    // Add Print Button To Main Panel
    pMainPanel->Add( pBtnPrint );
    pMainPanel->AddSeparator();
    pMainPanel->Add( new CMFCRibbonButton(ID_FILE_CLOSE, _T("&Close"), 5, 5));

컴파일 해서 실행하면 아래와 같이 나타납니다.

사용자 삽입 이미지

Print 버튼이 들어갔습니다.  Label과 버튼 두개가 보이시죠?

이제 Recent File List컨트롤을 넣겠습니다. 

    // Add Recent File List & Exit Button
    pMainPanel->AddRecentFilesList( _T("Recent Documents") );
    pMainPanel->AddToBottom( new CMFCRibbonButton( ID_APP_EXIT, _T("E&xit"), 8));


사용자 삽입 이미지

Recent Document 영역이 생겼습니다.  추가 Exit 버튼도 넣었습니다.

9. Category 넣기
Ribbon 영역에 Category를 넣겠습니다.  Category에 Panel을 생성하고 Element들을 넣을수 있게됩니다.

    // Load Images for ribbon panels
    m_PanelImages.SetImageSize(CSize(16,16));
    m_PanelImages.Load(IDB_RIBBONSMALL);

    // Add a "Home" category to the ribbonbar
    CMFCRibbonCategory* pCategory = m_wndRibbonBar.AddCategory( _T("Home"), IDB_RIBBONSMALL, IDB_RIBBONLARGE );

    CMFCRibbonPanel* pPanelClipboard = pCategory->AddPanel( _T("Clipboard"), m_PanelImages.ExtractIcon(0) ) ;
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_PASTE, _T("Paste"), 1, 1 ) );
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_CUT, _T("Cut"), 2, 2 ) );
    pPanelClipboard->Add( new CMFCRibbonButton(ID_EDIT_CLEAR, _T("Clear"), 3, 3 ) );

m_PanelImages는 Panel에서 사용하게될 CMFCToolBarImages입니다.  Category를 넣고 거기에 Panel을 Add하고 Element들을 Add 하면 됩니다. 

사용자 삽입 이미지

어느 정도 모양이 갖추어 졌네요..  여기서 Visual Manager를 적용하면 Modern한 UI로 됩니다.

    // Set the default manager to Office 2007
    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
    CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_LunaBlue);


이제 Application Look이 적용되었습니다.

사용자 삽입 이미지

그리 어렵지 않게 기존 Scribble 프로젝트에 Ribbon UI 를 적용하였습니다.
툴바가 같이 나오네요..  툴바를 Create하는 구문을 Comment Out 하시면 나오지 않게 되겠죠?  이제 다음 포스트에서 리본에 여러가지 기능을 적용해 보겠습니다.


반응형
반응형

http://cafe.naver.com/opendori.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=25355

 

=================================================================================================

 

http://cafe.naver.com/cyberzone/401





스크롤바는 윈도우의 문서의 스크롤을 도와주는 컨트롤이다. 각 부분은 다음과 같은 명칭을 갖는다.

최근에는 스크롤바에의한 스크롤보다는 마우스 휠에의한 스크롤이 더 편리하게 여겨지고 있다.

스크롤바의 생성

스크롤 바는 두가지 방법으로 만들 수 있다. 첫 번째 방법은 window class에 WS_HSCROLL, WS_VSCROLL 스타일을 주어서 만드는 것이고, 둘째 방법은 CreateWindow 함수로 "scrollbar"라는 이미 등록되어 있는 WNDCLASS를 찍어내어 만든다.

스크롤바는 다음과 같은 스타일을 가질 수 있다.

스타일

설명

SBS_HORZ

수평 스크롤바

SBS_VERT

수직 스크롤바

SBS_BOTTOMALIGN

크기가 크더라도 일정한 크기로 아래에 붙여버림

SBS_TOPALIGN

크기가 크더라도 일정한 크기로 위에 붙여버림

SBS_LEFTALIGN

크기가 크더라도 일정한 크기로 왼쪽에 붙여버림

SBS_RIGHTALIGN

크기가 크더라도 일정한 크기로 오른쪽에 붙여버림

스크롤바의 메시지

스크롤 바 혹은 스크롤 윈도우는 WM_HSCROLL, WM_VSCROLL 메시지를 받는다. 각 경우 모두 동일하게 처리되며 인자들은 다음과 같다.

인수

설명

LOWORD(wParam)

스크롤 코드

HIWORD(wParam)

썸의 위치값이다. 이 값은 사용자가 썸을 드랙할 때만 세팅된다.

lParam

스크롤 바의 HWND, 표준 스크롤 바일 경우는 NULL

이들 메시지 처리 방법은 스크롤 코드인 LOWORD(wParam)을 기준으로 다음과 같이 한다.

스크롤 코드

처리 방법

SB_LINEUP

사용자가 위쪽 arrow를 눌렀다. 한 줄 위로 올려준다.

SB_LINEDOWN

사용자가 아래쪽 arrow를 눌렀다. 한 줄 아래로 내려준다.

SB_PAGEUP

사용자가 위쪽 shaft를 눌렀다. 한 페이지 위로 올려준다.

SB_PAGEDOWN

사용자가 아래쪽 shaft를 눌렀다. 한 페이지 아래로 내려준다.

SB_ENDSCROLL

스크롤이 종료되었다.

SB_TOP

제일 위쪽으로 스크롤 되었다.

SB_BOTTOM

제일 아래쪽으로 스크롤 되었다.

SB_THUMBTRACK

사용자가 썸을 드랙하고 있다. 변경된 스크롤 값에 맞게 되면을 다시 그린다.

SB_THUMBPOSITION

사용자가 썸을 드랙한 후 마우스를 놓았다. 변경된 스크롤 값에 맞게 화면을 다시 그린다.

제일 아래 두 코드는 상호 대체성이 있기 때문에 둘 중의 하나만 달아주면 된다.

만일 키보드를 지원하고 싶다면 아래 코드를 추가하라.

case WM_KEYDOWN:
	switch(wParam)
	{
	case VK_UP: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); break;
	case VK_DOWN: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); break;
	case VK_PRIOR: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0); break;
	case VK_NEXT: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0); break;
	case VK_HOME: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_TOP, 0), 0); break;
	case VK_END: SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_BOTTOM, 0), 0); break;
	}

스크롤바 관련 함수

  • BOOL SetScrollRange(HWND hwnd, int bar, int min, int max, BOOL redraw)

스크롤바의 범위는 표준 스크롤바의 경우는 0~100, 스크롤바 컨트롤의 경우에는 0~0이다. 이 값은 SetScrollRange 함수로 변경할 수 있다.

첫 번째 인자가 윈도우의 핸들일 경우 bar에는 SB_HORZ나 SB_VERT가 와야 한다. 첫 번째 인자가 스크롤바 컨트롤일 경우에는 SB_CTL이 와야한다.

만일 min==max이면 스크롤바는 숨겨진다.

스크롤바의 범위를 세팅할 때는 한가지 주의해야 할 점이 있다. 문서의 height와 같게 range를 설정하면 안된다는 것이다. 그 경우에는 현재 화면의 가장 위가 0이고 마지막 화면의 가장 위가 height가될 때 까지 스크롤 되므로, 맨 마지막에 한 화면 만큼의 빈 공간이 들어가게 된다.

  • BOOL GetScrollRange(HWND hwnd, int bar, LPINT lpmin, LPINT lpmax)

이 함수의 첫 번째 두 개의 인자는 위의 SetScrollRange와 같다. 나머지 두 인자는 정수값을 얻어올 주소이다.

  • int SetScrollPos(HWND hwnd, int bar, int pos, BOOL redraw)

이 함수는 스크롤바의 현재 위치를 세팅해 준다. 기존값이 리턴된다.

  • int GetScrollPos(HWND hwnd, int bar)

스크롤바의 현재 위치를 얻어온다.

다음은 Win32에서 추가된 스크롤바 함수들이다.

  • int SetScrollInfo(HWND hwnd, int bar, LPSCROLLINFO lpsi, BOOL redraw)

이 함수는 위의 많은 일들을 한번에 처리하는 함수이다. 세 번째 인자는 다음 구조체로 설정한다.

typedef struct tag SCROLLINFO
{
	UINT cbSize;
	UINT fMask;
	int nMin;
	int nMax;
	UINT nPage;
	int nPos;
	int nTrackPos;
} SCROLLINFO;
typedef SCROLLINFO FAR* LPSCROLLINFO;

cbSize에는 sizeof(SCROLLINFO)를 대입해 주면 된다.

fMask에는 설정할 값을 지정한다. 다음 값들중의 하나이다.

설명

SIF_DISABLENOSCROLL

범위가 0이 되더라도 스크롤바를 숨기지 않고 사용 금지 시킨다.

SIF_PAGE

nPage로 페이지의 크기를 정한다.

SIF_POS

nPos값으로 위치를 정한다.

SIF_RANGE

nMin, nMax값으로 range를 설정한다.

SIF_ALL

모든 플래그의 조합

nPage에 관한 것이 새로 추가된 것으로 썸의 크기를 결정하는데 사용하는 한 페이지의 크기를 말한다.

SetScrollInfo 함수는 nTrackPos를 사용하지 않는다.

  • BOOL GetScrollInfo(HWND hwnd, int bar, LPSCROLLINFO lpsi)

스크롤바에 관한 모든 정보를 한번에 얻어온다. nTrackPos 맴버는 SB_THUMBTRACK 메시지에서 드래그 중의 썸의 위치를 넘긴다.

  • BOOL ShowScrollBar(HWND hwnd, int bar, BOOL show)

이 함수는 스크롤바를 보이거나 보이지 않게 한다.

  • BOOL EnableScrollBar(HWND hwnd, int bar, UINT arrow)

이 함수는 스크롤바를 보이거나 보이지 않게 한다. arrow에는 다음 값들이 올 수 있다.

arrow 값

설명

ESB_DISABLE_BOTH

모든 버튼을 금지

ESB_DISABLE_DOWN

아래쪽 버튼을 금지

ESB_DISABLE_LEFT

왼쪽 버튼을 금지

ESB_DISABLE_LTUP

왼쪽, 위 버튼을 금지

ESB_DISABLE_RIGHT

오른쪽 버튼을 금지

ESB_DISABLE_RTDN

오른쪽, 아래쪽 버튼을 금지

ESB_DISABLE_UP

위쪽 버튼을 금지

ESB_ENABLE_BOTH

모든 버튼을 허가

반응형
반응형

http://cafe.naver.com/opendori/4949




Scrolling credits using CStatic

 

 
Download 
source file or demo project.

This static subclass is based on the Scrolling credits dialog by Mark Findlay. I have made some modifications to enable the use of resource strings, and added some functionality to make the background look more professional. By implementing the functionality through a CStatic subclass it is no longer dependant on a dialog and can more easily be used in different circumstances.

The control lets you scroll text and bitmaps in an like you see in movies. It will continue to loop the text for as long as it is active. The speed of the scrolling can be set by the programmer. The control has the following features:

  • The text/bitmap sequence can be set using a character string or through am ID to a string table entry.
  • The text/bitmap sequence is formatted with different colours and fonts through using special characters in the text. The mapping between the special characters and given colours and fonts can be set by the programmer 

    NB! The bitmaps are given as quoted bitmap resources (ID as "IDB_BITMAP" instead of just IDB_BITMAP).
  • The background can be given a special colour or a background bitmap can be set. 

    NB! While bitmaps in the text/bitmap sequence are restricted to 16 colours, the background bitmap have no such restriction.) 

    If a solid colour background is used, it can be given a gradient to black or white, left-to-right or vice-versa.
  • The background of the bitmaps in the text/bitmap sequence can be made transparent to allow for non-square shapes. By setting a flag, the parts of the bitmaps that have the standard dialog colour (RGB(192,192,192)) will be transparent. 

    NB! There is a slight difference in how this functionality is implemented when using a background image instead of colour. Because of the way the addition of a background image is implemented all parts of the text/sequence that have the standard dialog colour will be transparent, not only the bitmaps. Also, when the transparent colour is _not_ set, all parts of the text/bitmap sequence that match the otherwise not active background colour, will be transparent as well. So, to disallow transparency when using a background image, set the background colour so an unused colour. 

    NB! Because there is several bitblt's involved when using a background image, the scrolling is slowed down considerably. But it does look good!! (If anyone can find ways of speeding up this process, please contact me!)
  • If not scrolling is started, a still picture of the text/bitmap sequence is displayed (That's how the figure was created). 

    Beware of the following differences between this implementation and the one of Mark Findlay:
  • Instead of an array of strings, this control uses a single string. This is to allow the use of resource strings. 

    A delimiter character (standard '|') is given to mark the beginning of a new line.
  • The special character denoting "normal" text has been removed. A line without any special character will be formatted according to the "normal text" rules.
  • Several of the default special characters have been changed, This was necessary because the string table resources did not understand all the original escape sequences.

To use CCreditStatic a member variable must be added to the dialog:

protected:
CCreditStatic m_static;

In OnInitDialog the static control is subclassed and the credit text is added. Optionally a background image can be added:

char *pArrCredit = { "NETBAS FOR WINDOWS NT\t||Copyright (c) 1998|"
        "Test Data AS|All Rights Reserved||"
        "BITMAP1^|||"    // this is a quoted bitmap resource 
        "Project Lead\r||Kjetil Kvamme|||"
        "Technical Lead\r||Kjetil Kvamme|||"
        "Engineering Lead\r||Paul K. Tonder|||"
        "Product Lead\r||Tom Rotting|||"
        "Engineering\r||Paul K. Tonder,  Rolf T. Wold,  Sigbjorn Helset|"
        "Reidar Ognedal,  Kjetil Kvamme, Arne Bakken|||"
        "BITMAP2^|||"  // this is a quoted bitmap resource 
        "QA\r||Mary Hech,  Sam Bamnm,  Ron Fonn,  Steve Waeve|"
        "Igor Borisnoff,  FellaB |||"
        "Documentation\r||"
        "Arvid Molnvik,  Joanne Hone,  Annette Fune|||"
        "Technical Program Office\r||Burf Murphy, Foll Roller||||"
        "Systems Support\r||Bendy Land|||"
        "Administrative Support\r||Donna Fonna|||"
        "* * * * * * * * *\t|||"
        "BITMAP3^||"
        "Project Manager\r||Dwain Kinghorn|||"
        "Engineering\r||"
        "Hank Bank,  Ray Fay,  Bill Sill,  Mark Dark,  Peter Leter|"
        "Lev Bef|||Quality Assurance\r||"
        "Biff Bin||||"
        "BITMAP4^|||||"
        };

BOOL CMyDialog::OnInitDialog()
{
        CDialog::OnInitDialog();

        m_static.SubclassDlgItem(IDC_DISPLAY_STATIC,this);
        m_static.SetCredits(pArrCredit);
        // m_static.SetCredits(IDS_CREDITS);  // Use with string resource
        m_static.SetSpeed(DISPLAY_FAST);
        m_static.SetColor(BACKGROUND_COLOR, RGB(0, 0, 255)); // Background Colour
        m_static.SetTransparent(); // Set parts of bitmaps with RGB(192,192,192) transparent
        m_static.SetGradient(GRADIENT_RIGHT_DARK);  // Background goes from blue to black from left to right
        // m_static.SetBkImage(IDB_BITMAP1); // Background image
        m_static.StartScrolling();
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX Property Pages should return FALSE
}

Note: Keith Rule was kind enough to fix a number of resource leaks that can bring the App down on Windows95. The fixes have mostly been to select the original GDI objects back into the device context.

The example project shows one use of the control. A Credits dialog is displayed when the user double-click in the view window. In addition to showing the basics for using the control, the project also shows how cycling of background images can be implemented. The background image is periodically switched (every 5 seconds). This background image cycling management is implemented in the dialog box rather than in the control itself. The background image is switched through repeated calls to the BkImage method of the CCreditStatic object.

 

반응형
반응형

http://cafe.naver.com/bc6783232/1347




MFC 강의 - 4 컨트롤 다루기 -버튼


일단 처음은 대화상자 기반으로 만듭니다.(컨트롤을 만들고 배치하기 편하기 때문에...)
1.
처음에 생성되는 버튼들을 전부 지웁니다.

도구상자에 있는 버튼을 클릭해서

이렇게 가운데 하나를 배치하고 아래에 세 개를 배치합니다.

배튼 한 개씩 클릭해서 옆에 있는 속성창의 caption과 ID를 수정합니다.
순서는 달라고 되니까 ID와 CAPTION이 일치하도록 해주세요.

제목 바꾸기 - IDC_BUTTON_TITLE
숨기기        - IDC_BUTTON_SHOW
사용하지 못하게 함 - IDC_BUTTON_DISABLE

그 다음 MFC 클래스 마법사를 실행하면 (오른쪽 클릭 후 클래스 마법사항목 선택)
개체 ID와 메시지라는 항목이 나옵니다.
메시지 항목은 왼쪽의 클릭된 객체의 메시지(버튼이 클릭되었을 경우라던가...)입니다.
우리가 만들었던 버튼들 중 IDC_BUTTON_TITLE를 빼고 전부 BN_CLICKED메시지를 클릭하여 처리기를 추가합니다.
이렇게 하면 버튼들이 클릭되었을 때(이벤트) 운영체제에서 해당 버튼이 클릭 되었다는 메시지(BN_CLICKED)를 보내는 처리기(함수)를 설정해 주는 것 입니다.



코드 창을 보면 클래스의 메소드 3개가 추가되어있는 것을 확인할 수 있습니다.

그럼 우선 OnClickedButtonDisable()이란 함수를 수정해 보도록 하겠습니다.
"사용하지 못하게 함"이라 써져 있던 버튼이 클릭되어 있을 때 실행되는 메소드입니다.

void CMFC4Dlg::OnClickedButtonDisable()
{
//현재 버튼이 어떤 상태인지를 기억하기 위한 변수를 선언합니다. 함수가 종료더라도 상태
//은 기억되야 하므로 정적변수로 선언합니다.
//처음 실행될 때의 상태는 사용할 수 있으므로 true로...
static bool bEnable = true;
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
//누르면 상태가 바뀌어야 하므로 !연산자을 한 자기 자신을 대입합니다.
bEnable = !bEnable;
//GetDlgItem()은 해당 ID인 컨트롤인 클래스의 주소를 반환합니다. 클래스의 메
//소드를 이용하여 컨트롤의 상태를 조절할 수 있습니다.
//컨트롤 클래스의 메소드인 EnableWindow()는 bool변수를 인수로 가지며,
//true일 경우 버튼을 사용할 수 있게, false일 경우 버튼을 사용불가로 만듭니
//다.
GetDlgItem(IDC_BUTTON_TAGET)->EnableWindow(bEnable);
if(bEnable)
{
//SetWindowText()메소드는 버튼의 텍스트를 설정하는 메소트입니다.

GetDlgItem(IDC_BUTTON_DISABLE)->SetWindowText(_T("사용하지 못하게
                함"));
}
else
{
GetDlgItem(IDC_BUTTON_DISABLE)->SetWindowText(_T("사용하게 함"));
}
}
다음은 "숨기기"라 써져있던 버튼이 클릭되었을 때 실행되는 메소드를 수정해 보겠습니다.
OnClickedButtonShow이란 메소드입니다.

void CMFC4Dlg::OnClickedButtonShow()
{
static bool bShow=true;
bShow = !bShow;
GetDlgItem(IDC_BUTTON_TAGET)->ShowWindow(bShow);
if(bShow)
{
GetDlgItem(IDC_BUTTON_SHOW)->SetWindowText(_T("숨기기"));
}
else
{
GetDlgItem(IDC_BUTTON_SHOW)->SetWindowText(_T("보이기"));
}
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
}
내용은 거의 같습니다. 다만 EnableWindow(bEnable)이 아닌  ShowWindow(bShow)인데
인수가 true면 보이는 상태로 false면 보이지 않는 상태로 변경합니다.

이제 제목 바꾸기 라는 버튼이 클릭되었을 때 실행되는 메소드를 수정해 보겠습니다.
OnClickedButtonTitle이란 메소드 입니다.


void CMFC4Dlg::OnClickedButtonTitle()
{
static bool bTitle =true;
bTitle = !bTitle;
if(bTitle)
{
GetDlgItem(IDC_BUTTON_TAGET)->SetWindowTextW(_T("바뀌었다."));
}
else
{
GetDlgItem(IDC_BUTTON_TAGET)->SetWindowTextW(_T("실험체"));
}
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
}
참고로 버튼(컨트롤)의 상태를 변경하는 메소드가 Window라고 써져있는 이유는
사실 컨트롤들은 일종의 윈도창입니다. 자세한 것은 인터넷에 검색해 보시길...

반응형
반응형

http://blog.naver.com/intencelove?Redirect=Log&logNo=20102281965



DE: MSVS2005 - dialog based

갑자기 슬라이더 컨트롤을 사용할 일이 생겼서 오랜만에 사용하다 보니 헷갈리는 부분이 있어, 조금 헤맸습니다. 그래서 이렇게 잊어 버리지 않기 위해 포스팅을 해요!!

 

 

Dialog에 slider control을 붙인다.

위의 그림은 defualt값이 아니라 속성을 추가 하여 준것입니다. (orientation, point 2개의 속성 추가)

 

그리고 slider bar의 ID를 IDC_SLIDER_* 로 설정한 후 (* 표시는 사용자의 임의로 정합니다.)

멤버 변수를 control type인 CSliderCtrl 로 해준다.

멤버변수의 추가는 우선 슬라이더 컨트롤에서 마우스 오른쪽 키를 누른다. 그럼 아래의 그림처럼 속성이 보일 것입니다.

 

6.0을 사용하시는 분은 ctrl + w (class wizard 단축키)를 통해 추가 하시면 될 것같습니다.

그럼 아래와 같은 그림을 통해서 추가 하시면 여러분의 헤더파일에 CSliderCtrl m_ctrlSlider라고 생길 거예요^^

 

그리고 여러분의 *.C 파일에 OnInitDialog()에 아래 부분의 소스를 추가 해주시면 됩니다.

혹시나 slider bar의 인자들이 궁금하시다면 아래 포스팅을 참조 하세요^^

http://blog.naver.com/intencelove/20102277196 

 // slider control
 m_ctrlSlider.SetRange(0, 255); // slider 전체 크기
 m_ctrlSlider.SetPos(100);  // slider 초기 위치 
 m_ctrlSlider.SetTicFreq(10); // slider 눈금 간격
 m_ctrlSlider.SetSelection(40, 200);// slider focus range

 

그리고 나서 슬라이더가 이동했을때 발생하는 이벤트

OnNMReleasedcaptureSlider를 추가해주셔야 합니다. 다시 한번 슬라이더 컨트롤로 이동(리소스뷰)에서 슬라이더 컨트롤을 누르면 (2005의 경우 오른쪽에 아래그림과 같이 화면이 나타 납니다.)

6.0같은 경우 class wizard에서 이벤트 메시지를 추가해주면 될것같아요

 

 

그리고 난 후 슬라이더의 현재위치를 알기 위해 추가된 함수에 코딩을 하면 됩니다.

 

void CImageDlg::OnNMReleasedcaptureSliderThreshold(NMHDR *pNMHDR, LRESULT *pResult)
{
      m_ctrlSlider.GetPos(); //현재 슬라이더의 위치를 가져 옴
      *pResult = 0;
}

반응형
반응형

WS_CAPTION 만 수정해서는 원하는 결과를 얻을수없다.

  • 타이틀바 보이기
    • ModifyStyle(0, WS_CAPTION, SWP_FRAMECHANGED);
  • 타이틀바 감추기
    • ModifyStyle(WS_CAPTION | WS_BORDER, 0);

API를 사용한다면

GetWindowLong 함수와 SetWindowLong 함수를 사용하여 스타일을 변경하고

SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);

를 호출해주면되겠다.

반응형
반응형

 written by http://www.winapi.co.kr



2-3-나. 커서 바꾸기

예제의 윈도우위에 마우스 커서를 위치시키면 화살표 모양의 커서가 나타난다. 이 커서가 사용되는 이유는 WndClass에서 커서를 지정하는 멤버가 다음과 같이 정의되어 있기 때문이다.

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

hCursor 멤버는 윈도우가 기본적으로 사용할 커서를 지정하며 LoadCursor 함수는 커서를 읽어오는 함수이다.

HCURSOR LoadCursor( HINSTANCE hInstance, LPCTSTR lpCursorName ); 

첫번째 인수 hInstance는 커서를 가지고 있는 프로그램의 인스턴스 핸들이되 윈도우즈가 제공하는 디폴트 커서를 사용하려면 이 인수를 NULL로 지정하면 된다. 두번째 인수 lpCursorName은 사용하고자 하는 커서의 이름을 지정한다. 윈도우즈가 디폴트로 제공하는 커서에는 다음과 같은 종류가 있다.

설명
IDC_ARROW화살표 모양
IDC_CROSS십자 모양
IDC_IBEAMI자 모양
IDC_NO원안에 빗금이 쳐진 모양
IDC-WAIT모래시계 모양

LoadCursor 함수의 두번째 인수로 이 값들을 지정해보고 다시 컴파일하여 커서를 직접 변경해 보도록 하자. 윈도우즈가 제공하는 디폴트 커서외에 자신이 직접 커서를 만들어 사용하는 방법도 있는데 이 방법은 5장에 가서 알아보도록 하자.


목록 보기  다음 강좌           

 

 

 

LoadCursor(NULL,IDC_ARROW);

::SendMessage(pView->m_hWnd, WM_SETCURSOR ,1,0);

 

 

 

BOOL CSTool_mapv10MFCView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
 // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
  
 if(m_hCursor){
  ::SetCursor(m_hCursor);
  return TRUE;
 }

 return CView::OnSetCursor(pWnd, nHitTest, message);
}

 

 

 

 

 

 

 

 

커서종류

IDC_ARROW

표준 화살표 커서

IDC_IBEAM

I 모양의 문자열 삽입 커서

IDC_WAIT

모래 시계 커서

IDC_CROSS

십자 모양 커서

IDC_UPARROW

위쪽 화살표 커서

IDC_SIZE

윈도우의 크기를 조정할 때 사용하는 커서

IDC_ICON

파일을 드래그할 때 사용하는 커서

IDC_SIZENWSE

좌상단, 우하단 화살표 커서

IDC_SIZENESW

좌하단, 우상단 화살표 커서

IDC_SIZEWE

수평 크기 조절 커서

IDC_SIZENS

수직 크기 조절 커서

 

 

 


반응형
반응형

http://blog.naver.com/donkey612?Redirect=Log&logNo=70045525967

 

 

 

 

CMenu  m_ContextMenu;  //반대 메뉴버튼

CMenu* GetContextMenu(){ return &m_ContextMenu; }

 

 

 

RECT ClientRect;
   POINT Point={0,0};
   ::GetClientRect( m_hWnd, &ClientRect );
   ::ClientToScreen( m_hWnd, &Point );
   ::GetCursorPos( &Point );
   CSTool_mapv10MFCView* view=((CSTool_mapv10MFCView*)((CMainFrame*)AfxGetMainWnd())->GetActiveView());
   view->GetContextMenu()->GetSubMenu( RIGHTMENUINDEX )->TrackPopupMenu(
    TPM_LEFTALIGN | TPM_RIGHTBUTTON,Point.x+ClientRect.left,Point.y + ClientRect.top
    ,view->GetParentFrame());


반응형
반응형


BOOL CSDICtrlApp::InitInstance()

{

    // 생략

    // 메뉴를 표시하지않음

    m_pMainWnd->SetMenu(NULL);

    // 창 하나만 초기화되었으므로 이를 표시하고 업데이트합니다.

    m_pMainWnd->ShowWindow(SW_SHOW);

    m_pMainWnd->UpdateWindow();


    return TRUE;

}

 

 

 

// 메인 프레임에서 메뉴 되돌리기

HMENU hMenu = ::LoadMenu(theApp.m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));

::SetMenu(m_hWnd, hMenu);


반응형

+ Recent posts