MFC의 Picture Control을 사용을 하다보면 

저기에 내가 원하는 픽셀을 넣고 싶을 경우가 있다.

예를 들어 툴을 만들때에 동적인 Teuxtre를 미리보기 형식으로 다이얼로그에 넣을 때 말이다

그럴경우에 대한 경우에 한가지 방법은 (사실 이 방법밖에 알아내지 못했다.)

Picture Control을 만들고 Picture Control의 윈도우 핸들을 가지고 비트맵을 생성을 하고 

그에 대한 픽셀 데이터를 가지고 온다. 그리고 Picture Control에 생성한 비트맵을 지정해준다.

그리고 나서 내가 원하는 텍스처나, 랜더 타겟의 비트맵을 얻어와서 앞서 생성한 비트맵의 픽셀 

데이터에 넣어주면 된다. NDL을 사용할 경우는 랜더타겟의 픽셀을 가지고 오는 과정에서 LockReck을

했을 경우에 실패를 하게 되는데 정확한건 아니지만 POOL_DEFAULT로 되어 있을 경우에 실패를 하지 

않나 싶다. 엔진에서 픽셀을 함부로 접근하지 못하게 하기 위해서 그런듯 하다.

그런 경우에 굳이 나처럼 랜더타겟을 보여주고 싶으면, 임의의 섭페이스를 만들고

랜더타겟의 섭페이스를 임의의 섭페이스로 복사를 한다. 이 임의의 섭페이스는 접근 가능한

섭페이스기에 LockReck을 이용하여 접근을 하여 원하는 데이터를 뽑아 올수 있지만

퍼포먼스를 보장을 못한다. 그렇기에 특정 이벤트가 들어올 경우에만 갱신을 하고 영역 자체를

작게 잡으면 실시간은 무리더라도 특정 이벤트시에 갱신만 해준다면 나름(?) 사용이 가능하다.

// 섭페이스 복사
D3DXLoadSurfaceFromSurface(
pDestSurface,   // 대상 섭페이스
NULL, // 색상파렛트인데.. 모름
pDestRect, // 대상의 복사 될 영역
pSrcSurface, // 복사할 섭페이스
NULL, // 색상파렛트인데.. 모름
pSrcRect, // 복사할 섭페이스의 역역
Filter, // 필터는 DX도움말 참조
ColorKey // 컬러키라는데...모름
);

여러개의 윈도우 위치(multiple-window-position)를 위한 메모리를 할당하고 구조체에 Handle을 리턴한다.
여러개의 윈도우를 재배치 할때는 화면의 껌뻑임을 줄이기 위해 DeferWindowPos 함수를 사용한다.

 

사용방법은 메모리를 할당 한 후 사용하고 해제한다.

 

1.BeginDeferWindowPos(메모리 할당)

 

HDWP BeginDeferWindowPos(
  int nNumWindows   // number of windows
);
여러개의 윈도우 위치(multiple-window-position)를 위한 메모리를 할당하고 구조체에 Handle을 리턴한다.

 

 

2.DeferWindowPos

 

HDWP DeferWindowPos(
  HDWP hWinPosInfo,      // handle to internal structure
  HWND hWnd,             // handle to window to position
  HWND hWndInsertAfter,  // placement-order handle
  int x,                 // horizontal position
  int y,                 // vertical position
  int cx,                // width
  int cy,                // height
  UINT uFlags            // window-positioning flags
);


열거된 여러개의 윈도우 위치(multiple-window-position)를 업데이트한다. 
업데이트된 구조체의 핸들을 리턴한다.

hWinPosInfo : 한개이상의 윈도우에 대한 크기, 위치정보를 포함한 multiple-window-position 구조체 핸들
              이 구조체는 비공개 구조체로 BeginDeferWindowPos에 의해 리턴되거나 최근에 콜한 DeferWindowPos에 의해 리턴된다.
hWnd : handle to window to position
hWndInsertAfter : placement-order handle(SetWindowPos 참조)
x,y : 위치
cx, cy : 크기
uFlag : window-positioning flags(SetWindowPos 참조)

 

리턴값 : 업데이트된 구조체

 

3.EndDeferWindowPos(메모리 해제 및 변경)

 

BOOL EndDeferWindowPos(
  HDWP hWinPosInfo   // handle to internal structure
);

한번의 리플레쉬로 한개이상의 윈도우의 위치,사이즈를 동시에 변경한다.

< 윈도우의 변경 >

- BOOL MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight,  BOOL bRepaint);
윈도우의 위치, 크기를 동시에 변경하는 가장 기본 적인 함수


- BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlag);
윈도우의 위치, 크기, Z순서를 변경(바로 앞에 있을 윈도우의 핸들값을 주거나 HWND_TOP, HWND_BOTTOM..등의 값도 줄 수 있다 )할 수 있으며 크기 변경 및 이동에 몇가지 옵션(uFlag)을 줄 수 있다.
!!!!!개별 윈도우의 위치나 크기, Z순서를 바꿀때~


- HDWP BeginDeferWindowPos(int nNumWindows);
HDWP DeferWindowPos(HDWP hWinPosInfo, HWND hWnd, HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags);
BOOL EndDeferWindowPos(HDWP hWinPosInfo);
!!!!!여러개의 윈도우를 일괄 조정 한다.( 따라서 화면 깜박임이 덜하고, 재배치 속도가 빠르다.)



- BOOL SetWindowPlacement(HWND hWnd, CONST WINDOWPLACEMENT *lpwndpl);
BOOL GetWIndowPlacement(HWND hWnd, WINDOWPLACEMENT *lpwndpl);
윈도우의 위치, 크기, 최대, 최소 상태를 한꺼번에 조사 및 변경 할 수 있다.
(최대화 된 메모장을 다시 원래대로 복구해 보면, 최대화 되기 전의 노멀 좌표(자기 자신의 좌표)로 정확하게 찾아간다. 이것은 시스템이 윈도우의 노멀 좌표를 기억하고 있기 때문이다.)

우선 Dialog Based기반으로 한 프로젝트에서 해본다.
트레이 아이콘을 만들기 위해서는 우선 헤더에 사용자 메시지를 추가해야 한다.

#define  UM_TRAYICON  WM_USER+7

 

class Login : public StandardDialog
{

...

}

그리고 헤더 메시지맵에 추가한다.

// Implementation
protected:

 // Generated message map functions
 //{{AFX_MSG(Login)
 afx_msg void OnConfirm();
 virtual void OnCancel();
 afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
 virtual BOOL OnInitDialog();
 afx_msg void OnExit();
 afx_msg void OnClose();
 afx_msg void OnLathe();
 afx_msg void OnDestroy();
 afx_msg void OnExit2();
 afx_msg void OnShow();
 afx_msg void OnMymenuMsg();
 //}}AFX_MSG

//이곳은 자동으로 생성되는 코드가 아닌 사용자가 직접 정의해주는 부분이다.

 LONG TrayIconShow(WPARAM wParam,LPARAM lParam); //<--메시지 맵 추가 


 DECLARE_MESSAGE_MAP()
};

다음으로 cpp파일부분의 메시지 맵에 추가한다.

BEGIN_MESSAGE_MAP(Login, StandardDialog)
 //{{AFX_MSG_MAP(Login)
 ON_BN_CLICKED(IDC_CONFIRM, OnConfirm)
 ON_WM_SETCURSOR()
 ON_BN_CLICKED(IDC_EXIT, OnExit)
 ON_BN_CLICKED(IDC_CLOSE, OnClose)
 ON_BN_CLICKED(IDC_LATHE, OnLathe)
 ON_WM_DESTROY()
 ON_COMMAND(ID_EXIT2, OnExit2)
 ON_COMMAND(ID_SHOW, OnShow)
 ON_COMMAND(ID_MYMENU_MSG, OnMymenuMsg)
 //}}AFX_MSG_MAP
 ON_MESSAGE(UM_TRAYICON,TrayIconShow)  //<--추가 부분
END_MESSAGE_MAP()

 

특정버튼을 클릭했을떄 트레이 아이콘이 만들어진다면

그 함수부분에 다음과 같이 코딩한다.

void Login::OnOK()

{

    ShowWindow(SW_HIDE);

    NOTIFYICONDATA nid; //<--NOTIFYICONDATA 구조체를 사용

    nid.cbSize = sizeof(nid);

    nid.hWnd = m_hWnd;    //현재 다이얼로그의 윈도우 핸들

    nid.uID = IDI_MYICON;   //아이콘의 리소스ID

    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;

    nid.uCallbackMessage = UM_TRAYICON; //우리가 만든 메시지

    nid.hIcon = AfxGetApp()->LoadIcon(IDI_MYICON);

    lstrcpy(nid.szTip,"트레이아이콘"); // 툴팁

    // taskBar상태영역에 아이콘 추가,삭제,수정할때 시스템에 메시지 전달
    Shell_NotifyIcon(NIM_ADD,&nid); //<--중요부분

    SendMessage(WM_SETICON,(WPARAM)TRUE,(LPARAM)nid.hIcon);

}

그리고 위의 헤더에서 정의했던 TrayIconShow함수를 구현한다.

여기서는 오른족 마우스를 트레이 아이콘에 클릭했을경우 메뉴가 나타나게 한다.

LONG Login::TrayIconShow(WPARAM wParam, LPARAM lParam)
{
    if(lParam == WM_RBUTTONDOWN) //오른쪽 마우스 클릭시
    {

       //메뉴를 로드한다.
        CMenu menu, *pMenu;

        CPoint pt;

        menu.LoadMenu(IDR_MYMENU);

        pMenu = menu.GetSubMenu(0);

        GetCursorPos(&pt);

        pMenu->TrackPopupMenu(TPM_RIGHTALIGN,pt.x,pt.y,this);
    }

 //트레이 아이콘을 더블클릭했을때 윈도우가 보여지게 한다.

  if(lParam == WM_LBUTTONDBLCLK)
  {
     ShowWindow(SW_SHOW); //윈도우를 보여준다.
   }
    return 0L;
}

//OnDestroy()함수에서 트레이아이콘을 파괴한다.

void Login::OnDestroy() 
{
 StandardDialog::OnDestroy();
 CDialog::OnDestroy();

    // TODO: Add your message handler code here
    if(m_bLoad)
    {

        NOTIFYICONDATA nid;

        nid.cbSize = sizeof(nid);

        nid.hWnd = m_hWnd;
  
        nid.uID = IDI_MYICON;

        Shell_NotifyIcon(NIM_DELETE,&nid);//<-중요부분
    }

 // TODO: Add your message handler code here
}

//닫기 버튼을 클릭하면 WM_CLOSE메시지가 발생하며 OnClose()함수가 호출되어진다.

void Login::OnClose() 
{
 // TODO: Add your control notification handler code here
 ShowWindow(SW_HIDE); //닫기 버튼을 클릭했을때 윈도우를 숨긴다.
}

//메뉴 클릭시 함수구현은 따로 해주어야한다.

만약 Dialog Base기반이 아닌 Single Document나 Multi Document기반으로 했을때는

CMainFrame클래스에서 트레이 아이콘을 설정한다. 예를 보여주지!!

우선

CMainFrame의 헤더위헤 메시지 추가

#if !defined(AFX_MAINFRM_H__D76C111C_99ED_4DD1_8FE2_D3BAE04F60E7__INCLUDED_)
#define AFX_MAINFRM_H__D76C111C_99ED_4DD1_8FE2_D3BAE04F60E7__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define  UM_TRAYICON  WM_USER+7 //TrayIcon 메시지 정의

//트레이 아이콘 생성
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

    ...................................................................................

   ...................................................................................

    m_bLoad = TRUE;
    NOTIFYICONDATA nid; //<--NOTIFYICONDATA 구조체를 사용

    nid.cbSize = sizeof(nid);

    nid.hWnd = m_hWnd;    //현재 다이얼로그의 윈도우 핸들

    nid.uID = IDR_MAINFRAME;   //아이콘의 리소스ID

    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;

    nid.uCallbackMessage = UM_TRAYICON; //우리가 만든 메시지

    nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    lstrcpy(nid.szTip,"주차관리 시스템(버전1.1)"); // 툴팁

    // taskBar상태영역에 아이콘 추가,삭제,수정할때 시스템에 메시지 전달
    Shell_NotifyIcon(NIM_ADD,&nid); //<--중요부분

    SendMessage(WM_SETICON,(WPARAM)TRUE,(LPARAM)nid.hIcon);

 return 0;

}

헤더의 메시지맵에 다음을 추가

// Generated message map functions
protected:
 //{{AFX_MSG(CMainFrame)
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnDestroy();
 afx_msg void OnClose();
 afx_msg void OnWindowShow();
 afx_msg void OnWindowHide();
 afx_msg void OnWindowClose();
 //}}AFX_MSG
 LONG TrayIconShow(WPARAM wParam,LPARAM lParam); //<--메시지 맵 추가 

 

cpp에도 다음을 추가

// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
 //{{AFX_MSG_MAP(CMainFrame)
 ON_WM_CREATE()
 ON_WM_DESTROY()
 ON_WM_CLOSE()
 ON_COMMAND(ID_WINDOW_SHOW, OnWindowShow)
 ON_COMMAND(ID_WINDOW_HIDE, OnWindowHide)
 ON_COMMAND(ID_WINDOW_CLOSE, OnWindowClose)
 //}}AFX_MSG_MAP
 ON_MESSAGE(UM_TRAYICON,TrayIconShow)  //<--추가 부분

위의 헤더에 선언했던 TrayIconShow함수 구현

LONG CMainFrame::TrayIconShow(WPARAM wParam, LPARAM lParam)
{
    if(lParam == WM_RBUTTONDOWN) //오른쪽 마우스 클릭시
    {

       //메뉴를 로드한다.
        CMenu menu, *pMenu;

        CPoint pt;

        menu.LoadMenu(IDR_MAINFRAME);

        pMenu = menu.GetSubMenu(1);

        GetCursorPos(&pt);

        pMenu->TrackPopupMenu(TPM_RIGHTALIGN,pt.x,pt.y,this);
    }

 //트레이 아이콘을 더블클릭했을때 윈도우가 보여지게 한다.

  if(lParam == WM_LBUTTONDBLCLK)
  {
     ShowWindow(SW_SHOW); //윈도우를 보여준다.
   }
    return 0L;
}

 

트레이 아이콘은 리소스를 차지 하기 때문에 나중에 파괴해 주어야 한다.

void CMainFrame::OnDestroy() 
{
 CFrameWnd::OnDestroy();
 // TODO: Add your message handler code here
 
 if(m_bLoad) //트레이 아이콘이 되어있다면
    {
        //리소스 해제 
        NOTIFYICONDATA nid;
  
        nid.cbSize = sizeof(nid);

        nid.hWnd = m_hWnd;
  
        nid.uID = IDR_MAINFRAME;

        Shell_NotifyIcon(NIM_DELETE,&nid);//<-중요부분
    }
}

 


 

 

Report 형식의 CListCtrl 에 자료 넣기

  • 1. 컬럼을 추가한다.
  • 2. Item을 추가한다.
  • 3. SubItem을 추가한다.

컬럼을 추가해야, 컬럼에 텍스트를 설정해 넣을 수가 있다. 컬럼 추가는 다음과 같이 한다.

          CListCtrl l;
          l.InsertColumn(0, "Control...", LVCFMT_LEFT, 100);
          l.InsertColumn(1, "HI...", LVCFMT_LEFT, 100);
          

Item을 추가해야, sub item을 추가할 수 있게 된다. Item은 0번부터 시작을 하고, sub item은 1번부터 시작을 한다. 우선 Item은 다음과 같이 추가한다.

          l.InsertItem(0, "first"); 
          l.InsertItem(1, "second"); 
          

subitem은, item의 index를 zero-based로 적고, subitem의 index는 1-based로 한다. 즉, item이 subitem의 index가 0번이라고 가정한다.

          l.SetItemText(0,1,"child of first");
          

이상을 정리하면 다음과 같다.

          +---------------------+---------------------+----------------------+
          |  InsertColumn(0, )  |  InsertColumn(1, )  |  InsertColumn(2, )   | 
          +---------------------+---------------------+----------------------+
          |    InsertItem(0, )  | SetItemText(0,1, )  |  SetItemText(0, 2, ) |
          +---------------------+---------------------+----------------------+
          |    InsertItem(1, )  | SetItemText(1,1, )  |  SetItemText(1, 2, ) |
          +---------------------+---------------------+----------------------+
          |    InsertItem(2, )  | SetItemText(2,1, )  |  SetItemText(2, 2, ) |
          +---------------------+---------------------+----------------------+
          |    InsertItem(3, )  | SetItemText(3,1, )  |  SetItemText(3, 2, ) |
          +---------------------+---------------------+----------------------+

+ Recent posts