오랜만에 만져보니 다 까먹어서 기억 나는 게 전혀 없다. 기억이 정말 거의 리셋되었으므로 겸사겸사 다시 해보는 중이다. 우선 버튼 조작부터 까먹었으므로 버튼 조작부분부터 적어볼까 한다. 앞으로도 헷갈리는 게 있으면 간간히 적을 것이다.


1. 버튼 추가하기

우선 버튼을 하나 추가해 주었다.

ID와 설정도 내가 원하는 대로 적당히 바꾸어 주었다.


2. OnClick 리스너 추가하기

id를 통해 객체를 선언해 주고, 리스너를 설정해 준다. 이 때 설정과 동시에 생성할 수도 있고 외부 함수를 만들어놓고 xml에서 onClick속성에 함수 이름을 적어서 처리하는 것도 가능하다. 주석처리한 부분에 원하는 동작을 넣으면 된다.


3-1. 동작 예시 - 액티비티 전환

2에서 적었던 코드의 주석 처리 부분에 위와 같이 적어준다. Intent객체는 외부 앱, 액티비티 실행 등 다양한 용도로 쓰인다. 자세한 내용은 http://developer.android.com/reference/android/content/Intent.html를 참고하자. 여기서 EditorActivity.class는 전환 액티비티의 클래스이므로 상황에 맞게 적당히 바꾸어 주어야 한다.

버튼 클릭 시 액티비티가 전환된 것을 알 수 있다.


3-2. 동작 예시 - 토스트 출력

이하 동문. 참고로 토스트는 유저와 상호 소통이 불가능하고 일정 시간이 지나면 사라져버린다. 다이얼로그와는 차이가 있으니 헷갈리지 않도록 주의.

다음과 같은 토스트를 볼 수 있다.


이 외에도 다양한 동작을 수행할 수 있다.

'Programming > Android' 카테고리의 다른 글

[Android] Decompile  (0) 2016.12.25

 기본적으로는 리소스 뷰에서 다이얼로그의 설정을 적당히 바꾸면 항상 위 설정과 프로그램 투명도를 바꿀 수 있긴 하다. 하지만 프로그램 내에서 자유롭게 설정을 바꿀 수 있게 하려면 다음과 같은 방법을 취하면 된다.

 

 

1. topmost(항상 위)

 

 체크박스로 TOPMOST를 설정 및 해제하는 예시이다. SetWindowPos를 이용하여(앞에 '::'를 붙여야한다.) HWND_TOPMOST를 설정해주고, 해제할 때에는 HWND_NOTOPMOST를 설정해주면 간단하게 오케이! 뒤의 SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW는 창을 움직이지 않고, 사이즈를 변경하지 않으며, 창은 띄우라는 의미로 저렇게 설정하였는데 더 축약시켜서 보기좋게 쓰는 방법이 있을 거라고 본다.

 

 

2. 투명도 조절

 

 투명도 조절은 Layered window만 가능하도록 되어있다. 그러므로 윈도우의 스타일을 수정해 주어야 한다. 해당 스타일은 GWL_EXSTYLE부분에 있으므로 SetWindowLong과 GetWindowLong을 잘 조합하여 설정해 준다.

 

 Layered window로 스타일을 바꿔 주었다면 SetLayerdWindowAttributes를 통해 투명도 설정이 가능하다. 두번째 인자는 컬러 키를 이용한 투명화를 해야할 때 사용되는데, 필자는 전체 창의 투명도를 바꿔야 하므로 NULL로 지정했다. 세번째 인자는 투명도 값이며 0~255의 범위를 가진다. 네번째 인자는 전체 창 투명도를 조작할 지, 컬러키 투명도를 조작할 지 플래그를 지정한다.

 

적당히 값을 넣어주면 다음과 같은 화면을 볼 수 있다.

 

 

 

예전에 현재 프로그램의 투명도를 바꿔 VS위에 겹쳐놓고 업무시간에 딴짓할 때 쓰는 프로그램을 짰던 기억이 새록새록하다.

 

 

참고자료

MSDN, "SetWindowPos function". http://msdn.microsoft.com/ko-kr/library/ms633545.aspx

MSDN, "Layered Windows". http://msdn.microsoft.com/en-us/library/ms997507.aspx

MSDN, "SetLayeredWindowAttributes function". http://msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx

새벽동안 꽤나 고생했던 문제이다. 생각보다 해결은 쉽게 되었다.....

제목은 저렇게 거창하게 적혀있지만 실제론 게임에서 자주 사용되는 상황이기에 정리해 보았다.

여기서 잠깐 "나는 삼각비나 삼각함수를 모른다!" 하는 사람은 위키피디아, "삼각함수" 항목을 참고해도 좋다.


이 문제의 조건은 다음과 같다.


1. 점 A와 B가 존재한다. 예를 들어 A는 기준점, B는 가려하는 위치라고 생각해보자. (위치는 가변적이다.)

2. 점 A와 B를 직교선으로 이어 직각 삼각형을 만든다.

3-1. 각도 구하기인 경우 x, y, r(빗변, 피타고라스의 정리로 도출)이 모두 주어지는 상황이다.

3-2. x, y 좌표 구하기인 경우 각도와 r(빗변)이 주어지는 상황이다.


그림으로 나타내면 이런 느낌이라고 할 수 있다.



첫번째 문제인 x, y 좌표를 알 때 각도를 구해보도록 하자.

우선 위의 조건에서 라는 사실을 이미 알고 있다. 그럼 우리가 알아야 하는 값은 θ이다.

tanθ를 아는데 θ값을 구하려면 탄젠트의 역함수를 취하면 된다. 아크탄젠트라고도 한다.

수식으로 나타내면 이렇게 될 것이다. 

사실 수식이 다소 틀렸을 수도 있으나 애교로 봐주면 감사하겠다. 필자는 중학생 때 부터 쭉 수포자이며 수학을 공부한 적이 없다.


아무튼, 이제 우리는 아크탄젠트를 구해야 한다. 이는 math.h를 인클루드했을 시 몇개의 아크탄젠트 함수를 사용할 수 있다.

필자는 여기서 상당히 막혔다. 왜냐면 atan과 atan2의 차이를 몰랐기 때문이다. 애꿎은 삽질 덕분에 해가 뜨는 것을 보았다.(구라까는 거 아니다.)

생각해보면 당연하다. atan은 tanθ값을 넣는다. 나같은 수포자가 있을 것 같아 이해를 돕자면 다음의 두 경우를 생각해 보자.


case 1. x 거리가 -1이고 y 거리가 -1이면 tanθ 값은 1이 된다.

case 2. x 거리가 1이고 y 거리가 1이면 tanθ 값은 1이 된다.

∴ 두 경우 다 같은 각도를 갖는다(사실 좌표계를 배제하면 틀린 말은 아니다)


뭔가 이상하지 않은가!? 나는 이걸 눈치채는 데에 무려 장장 네시간이 걸렸다. 앞서 말했듯이 난 중학생 때 부터 쭉 수포자이다.

그래서 사분면의 위치, 파라미터의 음수값을 고려한 함수가 atan2이다. y 값과 x 값을 파라미터로 갖는 함수이다.

일단 우여곡절 끝에 우리는 atan2 함수의 반환값으로 라디안 값을 얻게 되었다. 이 값에 를 곱해주면 Degree값이 된다.

코드로 나타내면 이런 느낌일 것이다.


 m_fDegree = atan2f( (float)B.y - A.y, (float)B.x - A.x ) * 180 / 3.1415f;


자, 이렇게 우리는 각도를 얻었다!

이제 각도와 빗변을 알 때 x, y의 좌표를 구할 일이 남았다. 이 문제는 코사인과 사인만 있으면 바로 해결된다.

이건 그나마 정말 쉽다. x의 거리 부터 구해보도록 하자.



써놓고 굉장히 뿌듯했다. 딱 봐도 아 그렇군! 싶지 않은가?

특히 1차원적인 사고 및 하나를 알려주면 하나만 아는 필자에게는 굉장히 알아보기 쉬운 수식이다.

"약분해서 r이 떨어지면 x 거리만 남으니까 이렇게 x 거리를 구하겠군!"

같은 원리로 y의 거리를 구하는 것은 다음과 같다.



이러한 원리를 이용하여 앞에서 쓴 코드에 덧붙여보도록 하자.

각도는 자유로 정한다. 단, 파라미터로 들어가는 각도는 라디안임에 주의한다. 빗변의 길이는 10으로 예를 들자.

참고로 코사인과 사인 함수도 math.h에 포함되어 있으니 math.h를 인클루드했는 지 확인하기 바란다.


 m_iXDist = cos( m_fDegree ) * 10;

 m_iYDist = sin( m_fDegree ) * 10;


위의 코드로 얻은 거리 값에 현재 위치 값을 더하면 "특정 각도로 원하는 값 만큼 이동"이 된다!


이러한 각도 구하기 및 좌표 구하기를 적용하는 사례는 다양한 곳에 이용될 수 있다.

FPS 게임에서 마우스 이동으로 카메라를 회전시키는 것도 가능할 것이고, 원하는 각도로 총을 쏘는 것도 가능하다.

딱히 더 할 말이 없으므로 글을 마친다.

자잘한 설명은 생략하고 깔끔하게 적는다!

콘솔 어플리케이션처럼 기본 아이콘이 제공되지 않는 프로그램에 한하며 MFC 등은 적용 방식이 다르다!



1. 프로젝트 폴더 내이든 어디든 일단 변경하고픈 아이콘을 준비한다


2. 리소스파일->추가->리소스(R)... 클릭


3. 아이콘 가져오기


4. 컴파일



끝.

거두절미

예시는 벡터


std::vector<템플릿> 변수1;

for( std::vector<템플릿>::iterator 변수2 = 변수1.begin(); 변수2 != 변수1.end(); 변수2++ )

{

    *변수2.작업();

}


자세한 설명은 생략한다.

정말 자주 쓰는 디자인 패턴 중 하나인 싱글톤 패턴이다. 개인적으로 디자인 패턴 중에서는 제일 구현도 쉽고 활용도도 높지 않나 한다.

웬만한 객체지향 언어는 지원이 되므로 어떤 형식을 가지는지 이해하면 타 언어(Java 등)에서도 활용 가능하다.

 'static'으로 생성된 객체의 특징인 "프로그램이 실행 시 함께 할당되며(일반적으로), 프로그램 종료까지 메모리에서 해제되지 않는다"는 점을 이용하며,

단 하나의 객체만 만들고 실행 내내 해당 객체만 불러오는 특징이 있다. 그렇기 때문에 보통 프로그램 내에서는 매니저 클래스로 많이 사용된다.

 사용되는 예시는 다음과 같은 형식이다. 사용 시에는 Singleton::Instance->함수() 등 다양한 방법이 있다


class Singleton

{

public:

static Singleton* Instance()

{

if( !m_pInstance ) // 인스턴스 할당

m_pInstance = new Singleton;


return m_pInstance;

}


private:

Singleton()

{

//초기화

}


~Singleton()

{

// 인스턴스 자체는 new로 생성하기 때문에 자동 삭제된다

};


static Singleton* m_pInstance;

};


#include <iostream>


using namespace std;


class Root

{

public:


virtual void Function() = 0;

};


class Node1 : public Root

{

public:


void Function()

{

cout << "나는 자식 1이당~~~"  << endl;

}

};


class Node2 : public  Root

{

public:


void Function()

{

cout << "나는 자식 2이당~~~"  << endl;

}

};


int main()

{

int i;

Root * Test = 0;


cin >> i;


switch( i )

{

case 1:

Test = new Node1();

break;

case 2:

Test = new Node2();

break;

}


Test->Function();


delete Test;


return 0;

}

참고 : http://msdn.microsoft.com/ko-kr/library/7sx52ww7.aspx



TRACE 매크로

 비주얼 스튜디오 내 콘솔 창에서 확인할 수 있게 하는 매크로. 매크로이지만 뒤에 세미콜론(;)이 붙는다.

Debug빌드 시에만 출력되며, Release로 빌드하면 해당 부분이 사라진다.




스레드 내부에 TRACE 매크로를 위와 같이 사용해 보았다.

printf 거의 동일하게 사용되는 것을 알 수 있다.




출력 창에 이렇게 나오게 된다.

 리스트 컨트롤은 목록 형식의 컨트롤로, 리스트박스와 약간 다른 점이 있습니다. 예를 들어 상단에 열 제목을 추가하는 등의 동작이 가능합니다. 이번에는 리스트 컨트롤을 사용하는 방법에 대해 알아보겠습니다.




우선 대화상자에 리스트 컨트롤을 선택하고 적당하게 배치합니다.



Properties에서 View 항목을 Report로 바꾸어 줍니다.




바꾸어 주었으면 열의 헤더가 생긴 것을 확인할 수 있습니다.




리스트 컨트롤을 선택하고 우측 마우스를 클릭하여 변수 추가를 선택해 줍니다.




멤버 변수 추가 마법사에서 원하는 변수 이름을 적고 '마침'버튼을 클릭합니다.




그러면 DoDataExchange 함수에 빨간 박스와 같은 코드가 작성된 것을 볼 수 있습니다.



이후 InitDialog 함수에서 아래 코드와 같이 작성합니다.



// 헤더 설정

LV_COLUMN m_lCol; // 열의 헤더 부분을 담당합니다.


m_lCol.mask = LVCF_TEXT | LVCF_WIDTH; // 변경할 부분을 마스킹하여 설정합니다.


m_lCol.pszText = "테스트1"; // 출력될 문자열입니다.

m_lCol.cx = 100; // 출력될 가로 폭입니다.

m_cList.InsertColumn( 0, &m_lCol ); // 열의 번호와 구조체의 주소를 넘깁니다.


m_lCol.pszText = "테스트2";

m_lCol.cx = 100;

m_cList.InsertColumn( 1, &m_lCol );


// 값 삽입

LV_ITEM m_lItem;


m_lItem.mask = LVIF_TEXT;


m_lItem.pszText = "아이템1";

m_lItem.iItem = 0;

m_lItem.iSubItem = 0;

m_cList.InsertItem( &m_lItem );


m_lItem.pszText = "아이템2";

m_lItem.iItem = 1;

m_lItem.iSubItem = 0;

m_cList.InsertItem( &m_lItem );


// 비어 있는 열의 값 추가(2번째)

m_lItem.pszText = "아이템3";

m_lItem.iItem = 0;

m_lItem.iSubItem = 1;

m_cList.SetItem( &m_lItem );


m_lItem.pszText = "아이템4";

m_lItem.iItem = 1;

m_lItem.iSubItem = 1;

m_cList.SetItem( &m_lItem );




컴파일하면 이렇게 리스트가 뜨는 것을 볼 수 있습니다.

+ Recent posts