minjeong-oh
기록
minjeong-oh
전체 방문자
오늘
어제
  • 분류 전체보기 (207)
    • ML & Neural Net (3)
    • ◼️GNN (1)
    • ◼️시계열 (1)
    • ◼️추천시스템 (0)
    • ◼️수학 (3)
    • Data Engineer (2)
    • ◼️Spark (1)
    • ◼️Kafka (1)
    • ◼️Elestic Search (0)
    • ◼️Redis (0)
    • ◼️ClickHouse (1)
    • Programming Language (4)
    • ◼️SQL (0)
    • ◼️React (0)
    • ◼️Git (1)
    • ◼️Python (1)
    • ◼️C++ (33)
    • ◼️Fortran 99 (2)
    • ◼️OpenGL (7)
    • ◼️MFC (35)
    • ◼️Flutter (46)
    • ◼️Kotlin (1)
    • ◼️Android (1)
    • ◼️Java (1)
    • ◼️C (4)
    • Development (0)
    • ◼️디자인패턴 (0)
    • ◼️네트워크 (2)
    • ◼️인증 (1)
    • Computer Science (4)
    • 알고리즘 문제풀이 (12)
    • SQL 고득점 Kit 문제풀이 (8)
    • 취업준비 (0)
    • Notion 정리 글 (1)
    • Article Scrap (12)
      • Careerly - Q&A (7)
      • Careerly - Post (2)
    • 기타 등등 (16)

블로그 메뉴

  • 글쓰기
  • 홈
  • 태그
  • 방명록
  • 편집

공지사항

인기 글

태그

  • 이차원구조체배열포인터
  • OpenGL회전
  • 19년식그램SSD장착
  • mfc
  • hello테마
  • GSLB
  • 19년식그램램장착
  • AI배워야하나
  • 이것이C++이다책참고
  • kafka구축
  • SpringBootSwagger
  • NextJSSwagger
  • 그램업그레이드
  • 리눅스파티션
  • API문서정리
  • 그램풀스팩업그레이드
  • 인공지능개발자
  • 티스토리폰트배경색없애기
  • 구조체매개변수
  • 구조체배열포인터

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
minjeong-oh

기록

◼️MFC

[MFC] 기본 개념

2024. 2. 15. 19:44

1. CWnd 클래스

더보기

● MFC = Microsoft Foundation Class

: 마이크로 소프트사가 만든 c++기반의 윈도우 라이브러리, 객체 지향적인 구조를 갖는다.

 

● CWnd 클래스

: MFC에서 모든 윈도우 클래스의 기본 클래스

 

● 상속관계

CObject > CCmdTarget > CWnd

CCmdTarget: MFC의 메시지맵과 관련된 코드가 구현된 클래스

 

 

● View에 새로운 윈도우를 보이게 하는 법

: View.h에 CWnd를 멤버 변수로 선언하고 View.cpp의 OnCreate함수내부에서 CWnd의 Create함수를 이용하여 생성한다. (Edit 형태 or Button형태)

 

● 부모 윈도우 설정 방법

- 윈도우의 부모 윈도우 설정 (CWnd.SetParent(부모윈도우)) //부모윈도우가 NULL이면 바탕화면에 윈도우생성

 

2. MFC 코드의 기본 구조

더보기

● 기본적인 SDI 화면 구성

- CMainFrame(기본 프레임윈도우) - CFrameWnd를 상속 받은 것
- CToolBar(도구모음)
- CStatusBar(아래의 상태표시줄)
- Menu(메뉴)
- CCreateDemoView(하얀 화면)
- CWnd( 사용자가 선언한 멤버변수. 새로운 윈도우)

● 기본적으로 생성되는 클래스

- Doc : CDocument 상속
- App: CWinApp 상속
- View: CView 상속 (BaseView설정을 CView로 했을 때)
- MainFrm : CFrameWnd상속

*App과 Doc클래스는 우리눈에 보이는 윈도우 클래스가 아니라
각각 응용프로그램 자체와 문서를 객체화한 클래스이다.

● CMainFrame

- SDI 최상위 프레임 윈도우
- CFrameWnd를 상속받아 만든다
- 도구 모음과 상태표시줄을 자식 윈도우로 갖고 cpp onCreate에서 생성 및 docking한다.

● CFrameWnd

- 프레임(Frame)이 있는 윈도우가 가져야할 기본기능을 정의한 클래스
- 부모윈도우가 없는 최상위 윈도우가 될 수 있는 윈도우
- 상속관계 : CObject> CCmdTarget>CWnd>CFrameWnd


● CWinApp 클래스

- 상속관계 : CObject>CCmdTarget> CWinThread > CWinApp
- CWinThread를 상속받은 걸보아도 알 수 있듯 이 클래스는 응용프로그램 자체를 객체화한 클래스이다.
- 가상함수: InitInstance(), ExitInstance(), Run()

* 프로그램 시작과 동시에 메모리를 할당한다든지 시스템 리소스를 할당받아야 한다면 이런 코드는 InitInstance에 넣고 메모리나 시스템 리소스를 반환하는 코드는 ExitInstance에 넣는 것이 보편적

- App.cpp파일에 CWinApp클래스를 상속받은 클래스가 전역 객체 theApp으로 생성되어있다.
- theApp객체의 생성은 프로그램의 실행을 의미
- InitInstance()에서 Doc, CMainFrame, View를 순차적으로 생성함


● CDocument 클래스

- 상속관계: CObject> CCmdTarget> Document
- 문서를 관리하는 역할
- 가상함수: OnNewDocument()
L SDI응용프로그램이 실행되면 반드시 한번 실행된다. 처음 문서를 처리하는 객체를 생성하면 아무런
내용이 없는 빈문서(새파일)를 열도록 하고 있기 때문
- 대표적 함수: OnOpenDocument(), OnCloseDocument(), OnSaveDocument()
* 메모장 프로그램이 대표적인 SDI 문서형식의 응용프로그램이다.(Base Class를 CEditView로 설정하면 메모장과 같은 윈도우가생성된다.)

●빈번하게 사용하는 MFC전역함수

-AfxMessageBox(): 메시지 상자의 출력
-AfxGetMainWnd(): 최상위 프레임 윈도우의 포인터 반환
-AfxGetInstanceHandle(): 응용프로그램의 인스턴스 핸들 반환

●CDocument의 SetModifiedFlag(BOOL)메서드

-문서가 변경되었음을 설정/해제하는 역할
(문서가 변경되었는데도 저장을 하지 않고 종료하는 경우 문서의 내용이 사라지지 않게 저장을 유도하는 장치)


● MFC 동작 원리

1. 모든 윈도우가 CWnd클래스를 상속받아 만들어진다.
2. 개발자는 윈도우의 함수를 다시 재정의 하여 사용
3. 이 함수를 특정 메시지에 대응하도록 메시지 맵을 이용하여 연결
4. 특정 메시지가 발생
5. 재정의한 함수 호출(재정의된 상위계층의 함수를 명시적으로 호출)
6. MFC의 코드와 우리가 작성한 코드 모두가 동작하게 됨

● 메시지 맵

- 특정 메시지가 발생했을 때 어떤 함수를 호출해야하는지 명시하는 매크로의 집합체

3. MFC 코드의 흐름

더보기

● CWinApp클래스를 상속받은 App클래스에서 InitInstance()가 호출되는 과정

1. 프로그램 실행 초기에 App생성자 호출
2. _tWinMain()이 호출
3. AfxWinMain()이 호출 > 여기서 InitInstance() 호출

● 메시지 처리

- CWinApp 클래스의 Run()함수가 호출되어 MFC응용프로그램의 메인 메시지 루프가 작동한 이후의 상황
- 보통은 메시지 핸들러 함수를 등록하여 처리하는 것이 일반적
- 직접 메시지를 발생시키는 경우도 있음(PostMessage, SendMessage)


● 메시지를 처리하는 방법


- 메시지 핸들러 함수 등록
- 부족한 경우 WindowProc()함수를 재정의하여 처리
- 메시지를 필터링 하고 싶다면 PreTranslateMessage() 함수 재정의
- PostMessage(): 메시지 큐에 메시지 추가하는 함수
- SendMessage(): 메시지 핸들러 함수를 호출하는 함수

4. 키보드 입력

더보기

● 키보드 메시지

- WM_KEYDOWN: SYSTEM키를 제외한 모든 키를 누르면 발생 - 핸들러함수: onKeyDown()
- WM_KEYUP
- WM_SYSTEMDOWN : Alt키 또는 F10키를 누르면 발생 - 핸들러 함수: onSysKeyDown()
- WM_SYSTEMUP


● WM_CHAR

1. 문자키(ASCII코드의 문자에 해당하는 값)를 누르게되면 제일먼저 WM_KEYDOWN메시지가 발생
2. TranslateMessage()함수를 거쳐서 WM_CHAR메시지로 전환

- 메시지 루츠에서 WM_KEYDOWN메시지를 분석한 수 ASCII코드 문자에 해당하는 키보드 입력이면 추가로 발생하는 메시지.
- WM_KEYDOWN, WM_CHAR 메시지 연이어 발생
- WM_CHAR의 메시지 핸들러 함수: onChar()

*굳이 onChar함수를 이용하지 않고 keydown메시지의 핸들러 함수를 이용해서 처리해도 되지만 그렇게하면 OnKeyDown()함수의 길이가 너무 커질 수 있으믈 특수키의 입력과 문자키의 입력을 구분하여 처리하는 것이 바람직


● WM_SYSCHAR

- WM_CHAR와 마찬가지로 TranslateMessage()함수가 생성
- Alt+문자키 입력 조합의 경우 발생 ex) Alt+s


● CString 클래스

- MFC가 제공하는 거의 유일한 문자열 처리 클래스
- 유니코드 문자열을 처리하고 일반 멀티 바이트 문자열을 처리하는 코드나 함수를 따로 분리하지 않아도 됨
(C보다 훨씬간단)
- 더하기 연산자나 할당 연산자가 정의되어 있음
- 문자열처리에 필요한 메모리를 알아서 관리 >> 메모리 할당/해제 코드 작성 필요x
(char배열을 사용하는 처리보다는 CString 클래스를 활용하는 것이 여러모로 유익)

*enter키를 예전에는 return키라고 부름 (남아있는 흔적 \r)

 

5. 마우스 입력

더보기

● 마우스 메시지

- WM_MOUSEMOVE
- WM_LBUTTONDOWN/WM_LBUTTONUP
- WM_LBUTTONDBCLK
- WN_MOUSEWHELL

● 더블클릭에서 발생하는 메시지

- WM_LBUTTONDOWN>WM_LBUTTONUP>WM_LBUTTONDBCLK>WM_SBUTTONUP

● 윈도우를 다시 그리는 OnPaint()

- WM_PAINT 메지시의 핸들러함수
- RedrawWindow()함수를 호출하면 내부에서 WM_PAINT메시지를 발생시킴.
(그러므로 윈도우를 업데이트해서 다시그리고싶으면 RedrawWindow()함수를 호출하면됨)

 

● 마우스 이벤트를 추적하는 방법

- Drag& Drop을 실행했을 때 윈도우 바깥에서 마우스버튼 UP을 해도 윈도우로 다시 돌아오면 외부에서 UP한 것을 인식하지 못했기 때문에 계속해서 마우스 Down되어있다고 인식을한다.
이를 해결하기위한 이벤트 추적방법이 아래 두가지가 있다.


방법1. SetCapture() >ReleaseCapture()
- 응용프로그램 자신이 직접 마우스를 점유하고 계속 마우스 메시지를 수신하여 경계를 벗어났는지 검사
- 윈도우 영역을 벗어나더라도 계속해서 마우스 메시지를 수신함
- 자신의 윈도우를 넘어 바탕화면이나 다른 프로그램으로 드래그 앤 드롭이 가능한 경우 캡쳐방법이 최선
- 이 방법은 드래그 앤 드롭에 사용하는 것으로 한정!
(특정 윈도우가 마우스를 선점하여 놓아주지 않으면 운영체제 입장에서는 큰 부담으로 작용하기 때문)
- 사용법: *LButton이 눌러질 때* SetCapture()함수를 사용하고, 떼어질때 ReleaseCapture()로 캡쳐를 품
- 부작용: 드래그하고 윈도우 밖에서 드롭을 할 경우 윈도우에서 아예 사라진 상태가 됨

방법2. _TrackMouseEvent() 함수 사용
- 운영체제에 자신의 윈도우를 등록하여 마우스가 자신의 영역을 벗어나면 메시지(WM_MOUSELEAVE)를
수신하여 경계가 벗어났음을 판단. (마우스를 캡쳐할 필요x(점유안함),오동작 가능성줄어듬)

 

사용법:

 

1) 마우스가 움직일 때( onMouseMove (WM_MOUSEMOVE 메시지의 핸들러함수)에서) 함수 사용

if(m_bTrack==FALSE){
  TRACKMOUSEEVENT MouseEvent;
  ::ZeroMemory(&MouseEvent, sizeof(MouseEvent));

  MouseEvent.cbSize =sizeof(MouseEvent);
  MouseEvent.dwFlags =TME_LEAVE;     //메시지를 수신하도록 함 
  MouseEvent.hwndTrack =m_hWnd;     //CWnd클래스의 멤버. 윈윈도우 객체의 핸들
  MouseEvent.dwHoverTime =0;

  m_bTrack::_TrackMouseEvent(&MouseEvent);  //TRUE를 반환하면 추적시작
}

 

2) 마우스가 윈도우에서 벗어날 때( onMouseLeave(WM_MOUSELEAVE 메시지의 핸들러함수)에서) 함수 사용

  TRACKMOUSEEVENT MouseEvent;
  ::ZeroMemory(&MouseEvent, sizeof(MouseEvent));

  MouseEvent.cbSize =sizeof(MouseEvent);
  MouseEvent.dwFlags =TME_CANCEL;     //이벤트 추적을 멈추라는 메시지 
  MouseEvent.hwndTrack =m_hWnd;   

  ::_TrackMouseEvent(&MouseEvent);  //TRUE를 반환하면 추적시작

  m_bTrack =FALSE;

 

* WM_MOUSEHOVER
: 마우스 포인터가 윈도우 영역으로 돌아오는 순간에 한번만 발생
dwFlags에서 TME_HOVER 옵션을 사용할 때 이 메시지를 수신할 수 있음

*WM_MOUSEMOVE메시지를 마우스가 해당 윈도우에서 움직이면 계속 발생

 

기타 명령어

더보기

해당 윈도우의 두 좌표정보(모니터 스크린 기준)을 알아온다.

- GetWindowRect(Rect*)
: Cwnd 클래스의 멤버, 모니터 기준 좌표를 RECT구조체로 알아내는 함수

스크린 기준좌표를 클라이언트 뷰 기준의 좌표로 환산

- ScreenToClient(CPoint*)
: CWnd클래스의 멤버. POINT 구조체로 전달받은 좌표를 특정 윈도우 기준 좌표로 변환

자식 윈도우의 위치를 변경된 새좌표로 이동

- SetWindowPos(const CWnd * pWndInsertAfter, int x, int y, int cx, int cy, UNIT nFlags)

▷pWndInsertAfter: 윈도우가 겹쳐있을 때 어떤 것이 위이고 아래일 지 결정하는 값
-value: &Cwnd::wndTop(or wndBottom, wndTopMost,wndNoTopMost)
▷x,y: 클라이언트 뷰 기준의 변경할 왼쪽 위 좌표
▷cx,cy: 새로 설정할 윈도우의 폭과 넓이
▷nFlags: 함수의 종작을 변경하거나 다른 인자를 적용/무시 하는 것

CPoint ptChild
CRect Rect;

m_wndChild.GetWindowRect(&Rect);  //Rect구조체에 m_wndChild(CWnd)윈도우의 모니터 기준 좌표를 반환
ptChild.x = Rect.left;
ptChild.y = Rect.top;             //왼쪽 위의 좌표를 CPoint에 저장

ScreenToClient(&ptChild);        //스크린 기준좌표를 클라이언트 뷰 기준의 좌표로 환산

m_wndChild.SetWindowPos(&CWnd::wndTop, ptChild.x,ptChild.y,0,0,
                       SWP_SHOWWINDOW|SWP_NOZORDER|SWP_NOSIZE);

 

윈도우의 텍스트 변경
- Cwnd.SetWindowText(CString)

윈도우의 텍스트 가져오기
- Cwnd.GetWindowText();


system키와 조합이되어서 눌렀는지 확인하는 방법

- 시스템키와 특정 키가 조합이되었는지 ::GetKeyState()로 16비트(WORD)정보를 얻어낼 수있다.
*GetKeyState의 반환값이 음수이면 눌러졌다고 판단하기도함
* 메시지 핸들러에서만 사용가능
(OnSysKeyDown함수에서 해야 됨. 이 함수가 실행됐다는 건 이미 시스템키(alt)가 눌러졌다는 것이기 때문)

1) WORD wResult = ::GetKeyState(VK_SPACE) //스페이스키가 눌러졌는지 확인해본다.
(16비트정보- 상위 8비트: 눌러졌는지, 하위 8비트: 토글 키가 눌러졌는지)
2) BYTE byHigh =HIBYTE(wResult) //상위바이트 알아내기
3) if(byHigh & 0x01) //상위바이트의 1번비트가 1이면 SPACE키가 같이 눌러진거임. 조건문 동작

4) wResult =::GetKeyState(VK_CAPITAL) //caps lock키가 눌려졌는지 검사
5) BYTE byLow = LOBYTE(wResult) //토클키가 켜졌는지 확인
6) if(byLow & 0x01) //하위 바이트의 1번키트가 1이면 키가 눌려진 상태

 


메시지 핸들러 외부에서 키가 눌러졌는지 확인하는 방법
- ::GetAsynckeyState() 사용


윈도우 종료
- AfxGetMainWnd()->SendMessage(WM_CLOSE)

 

 

화면의 원하는 위치에 Text출력 (OnPaint()함수 내부)

-CPaintDC dc(this)로 화면의 dc가 주어진다.
-dc.TextOust(10,10,CString); //10,10좌표에 CString이 출력된다.


자식 윈도우에서 일어나는 마우스 동작을 부모 윈도우에게 알리는 방법

- Create에서 SS_NOTIFY 설정을 추가한다.

'◼️MFC' 카테고리의 다른 글

[MFC] 윈도우에서 제공하는 캡쳐기능을 사용하여 캡쳐하고, 캡쳐한 파일을 원하는 위치에 저장 시키기  (0) 2024.02.15
[MFC] 다이얼로그 상하좌우로 창크기 늘릴수 있도록한다.  (0) 2024.02.15
[MFC] visual studio 2015 MFC 상단 메뉴바에 하위메뉴 추가  (0) 2024.02.15
[MFC] 마우스 위치의 윈도우 핸들값 얻기  (0) 2024.02.15
[MFC] UpdateData(true), UpdateData(false)  (0) 2023.11.29

    티스토리툴바