본문 바로가기
C & C++/C & C++

[TIP] MFC Tip 4

by izen8 2011. 5. 24.
반응형

<워크스페이스에서 프로젝트 합치기>

A의 다이얼로그 리소스를 복사합니다...

> A.rc 파일을 F가 열린 VC에 drag&drop 합니다...

A.rc가 열리면서 A의 리소스가 보입니다... 원하는 리소스(다이얼로그)를 F의 리소스 탭으로 복사한뒤 A.rc를 닫습니다...
(혹시 이 과정 중간에 A.rc가 수정되었더라면 저장하지 마세요...)

새로 추가한 다이얼로그 클래스 등록합니다.

> 클래스 위저드(ctrl+w)를 열면 새로운 다이얼로그 등록할꺼냐고 물어봅니다...
A에서 사용하던 클래스 이름 그대로 등록합니다... (ex... CADlg)

project A의 CADlg 소스를 복사합니다.

> 프로젝트를 닫습니다.

F의 디렉토리에 보면 새로 만든 A의 파일 두개 (ADlg.cpp, ADlg.h)가  보입니다...

이 파일을 project A에서 사용하던 파일로 덮어 씌웁니다...

F.ncb도 지워줍니다...

dsw 파일 더블 클릭해서 프로젝트를 다시 열면 됩니다...


<분할윈도우의 크기고정>

분할 윈도우의 크기 조절을 못하게 할때, 보통은 상속을 통해서 합니다만 간단히, 빨리, 쉽게 하시려면 다음처럼 해보십시요.

 

1. View에 WM_KILLFOCUS 메세지 핸들러를 만드시고,

2. ReleaseCapture(); 를 추가하시면 끝납니다.

 이렇게...

 

void CTestView::OnKillFocus(CWnd* pNewWnd)
{
    CView::OnKillFocus(pNewWnd);
    // TODO: Add your message handler code here
    ReleaseCapture();
}

 
<CFileDialog  확장방법>

 Project에 Dialog 박스를 추가합니다...

(추가한 Dialog의 ID : IDD_DIALOG_MY_FILE로 가정)

원하는 컨트롤을 몇개 올려 놓고 

추가한 Dialog 의 Properties....

Style : Child

Clip siblings <- Check;

3D-look <- Check;

Control <- Check;

 클래스 위저드 실행(ctrl + w)하여

새로운 클래스를 만들때

Base class : CFileDialog

로 하여 클래를 새로 만듭니다.

(새로만든 클래스명이 CMyFileDialog로 했다고 가정) 

CMyFileDialog::CMyFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,

        DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :

        CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)

{

    m_ofn.hInstance         = AfxGetInstanceHandle();

    m_ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_DIALOG_MY_FILE);//확장할 Dialog ID

    m_ofn.Flags             = dwFlags | OFN_EXPLORER | OFN_ENABLETEMPLATE |

                  OFN_ENABLEHOOK | OFN_HIDEREADONLY;

                  //Flags엔 다른건 몰라도 OFN_EXPLORER와 OFN_ENABLETEMPLATE는

                 //꼭 넣어 주세요..

}


이제 내가 만든 FileDialog를 호출할려면

#include "MyFileDialog"

 void CDlgTestDlg::OnButton()
{
    CMyFileDialog Dlg(TRUE)//CFileDialog 함수와 동일

    if(Dlg.DoModal() == IDOK){
    }
}

 

이렇게 하면 내가 확장하고픈 Dialog가 CFileDialog화면의 아래에 붙어서 나타 납니다.

 


<MDI 나 SDI에서 뷰를 숨기는 법>


SDI 구조는 기본적으로 항상 Document 만드시 존재한다고 가정하고 있습니다.

따라서 View도 하나 이상 반드시 존재하구요.

그러니 SDI 구조에서 최초에 빈 문서가 열리는 걸 막으려면 다양한 삽질을 해야 합니다.

 

쉽게는 뷰가 열리자 마자 OnInitialUpdate에서 EnableWindow(FALSE)를 해버리는 방법이 있겠죠.

그러니까 최초에 열리는 빈 문서 뷰에 대해서는 뷰를 디스에이블 시켜버리고

메인 프레임이나 도큐먼트에서도 명령 처리를 안하게 하는 겁니다.

이거 말고도 무궁무진한 삽질이 존재할테니 나름대로 연구해보세요.

 

MDI인 경우에는 정말 쉽습니다.

App 클래스의 InitInstance 메서드에 보면

 

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

 

if (!ProcessShellCommand(cmdInfo))

    return FALSE;

 

이런 내용이 있는데, 처음 두 줄을

 

CCommandLineInfo cmdInfo;

cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing

ParseCommandLine(cmdInfo);

 

이렇게 바꿔주면 됩니다.

 

위의 님은 mdi 일때는 child frame 을 아예 표시 않하게 하는 것이고요,

sdi 에서 아예 view 가 없게 설정을 하면,

(예를 들어 context 정보에서 view 포인터를 null 로 잡는다던가 하면,)

뷰 영역이 invalidate 가 되지 않는 현상이 나옵니다. 물론 프레임만 있고요.

한번 해보세요. 재미(?)있습니다--;

 


<MSFlexGrid 사용법>


요즈음에 이런 질문들이 많이 올라와서요..간단한 알고리즘을 적어 봅니다...

 

void SetGridData()

{

m_flexGridCtrl.Clear();

 

m_flexGridCtrl.SetTextMatrix(0,1,"이름");//1행 2열에 이름이라는 컬럼 제목을 달았습니다...

m_flexGridCtrl.SetTextMatrix(0,2,"주소");//1행 3열에 이름이라는 컬럼 제목을 달았습니다...

//보통 1행을 Fixed 로 하죠...

 

.........

 

 

int i=1;

while(1){

m_flexGridCtrl.SetTextMatrix(i,1,m_strName);//2행 2열에 CString 형의 자료를 집어 넣어요...

m_flexGridCtrl.SetTextMatrix(i,2,m_strAddr);

.....

 

i++;

if(그리드에 입력할 것이 더 이상 없다는 조건)

break;

}

 

}

 

Access 데이터 베이스 라면

if(!m_ptSet.IsBOF())

m_ptSet.MoveFirst(); // 오픈한 레코드의 처음이 아니면 처음으로 이동합니다...이것을 Clear 밑에 적어 주세요..

 

m_ptSet.IsEOF()를 입력할 것이 더이상 없다는 조건문으로 주시고요...

m_ptSet.MoveNext(); 를 i++; 위에 적어 주세요

 

 

음...저도 허겁지겁 짠 거라서...잘 못된 점이나 이상한 점이 있다면 답글 달아 주세요...

 

<ActivX에서 다이얼로그 베이스 사용>


출처는 코드구루 입니다.
폼뷰로 할경우 이미지버턴을 만들경우 잘 안되더라구요.
그래서 며칠동안 고생했는데 다이얼로그 베이스로 만들면 아무 문제없이 되길래 이렇게 올립니다.
그럼 수고하세요

This article was contributed by Petr Stejskal.

I wanted to create a control which would behave as a dialog or formview (you can place controls here). There is a simple way to do it - to take advantage of ActiveX.

Create a new MFC ActiveX ControlWizard workspace (no need to special options).
Insert a new dialog resource named IDC_MYDIALOG (check following: style - child, border - dialog frame, visible, control, static edge)
Insert a new MFC class named CMyDialog (base class CDialog)
Add CMyDialog m_MyDialog member to your CDialogCtrl header source (don't forget to add #include "MyDialog.h")
Using classwizard add a member function OnCreate (WM_CREATE)
int CDialogCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (COleControl::OnCreate(lpCreateStruct) == -1)
        return -1;

    m_MyDialog.Create(IDD_MYDIALOG, this);
    return 0;
}

Modify the member function OnDraw (the dialog's size depends on the WIDTH and HEIGHT specified in the HTML file):

void CDialogCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
   // TODO: Replace the following code with your own drawing code.
   // pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
   // pdc->Ellipse(rcBounds);

   m_MyDialog.MoveWindow(rcBounds, TRUE);
}

To show the control in your browser use this simple HTML:

  <html>
  <head>
  <title>DialogControl</title>
  </head>
  <body>
 
  <center>
  <OBJECT ID="DialogControl"  CLASSID="CLSID:insert here the GUID from ODL file"
   HEIGHT=300 WIDTH=300>
  </OBJECT>
  </center>
 
  </body>
  </html>

 


<메모리 누수 체크  예>


void CGraphView::OnDraw(CDC* pDC)
{
 CGraphDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);

 pDC->TextOut(20,200,"this program has memory problems!!");

/////////////////////////////////////////////////////////////////////////////
// CGraphView diagnostics

#ifdef _DEBUG

newMemState.Checkpoint();

if(diffMemState.Difference(oldMemState, newMemState))
{

 TRACE("Memory Leaked here!\n\n");
 diffMemState.DumpStatistics();
}

#endif
}
#ifdef _DEBUG
void CGraphView::AssertValid() const
{
 CView::AssertValid();
}

void CGraphView::Dump(CDumpContext& dc) const
{
 CView::Dump(dc);
}

CGraphDoc* CGraphView::GetDocument() // non-debug version is inline
{
 ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGraphDoc)));
 return (CGraphDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CGraphView message handlers


int CGraphView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CView::OnCreate(lpCreateStruct) == -1)
  return -1;
 
 // TODO: Add your specialized creation code here
 LOGFONT lf;
 CFont NFont;
 CFont *pOFont;
 CClientDC dc(this);
    memset(&lf, 0 , sizeof(LOGFONT));
 lf.lfHeight=50;
 lf.lfWeight=FW_NORMAL;
 lf.lfEscapement=0;
 lf.lfOrientation=0;
 lf.lfItalic=false;
 lf.lfUnderline=false;
 lf.lfStrikeOut=false;
 lf.lfCharSet=ANSI_CHARSET;
 lf.lfPitchAndFamily=34;
 NFont.CreateFontIndirect(&lf);
    pOFont=dc.SelectObject(&NFont);
    DeleteObject(pOFont);

#ifdef _DEBUG
 oldMemState.Checkpoint();
#endif

 return 0;
}

 


1. 할당해제가 지연된 블럭수
2. 힙에 할당된채 남아 있는 객체수
3. 힙에 배정된고 해제되지 않은 비객체 블럭( new 로 할당된 아이템)
4. 주어진 시간에서 사용되는 최대의 메모리
5. 프로젝트에 의해 사용되는 메모리 총량 (이 영역이 잘못되면 메모리 누수를 의미한다)

 


<투명다이얼로그박스........>

 

typedef BOOL (WINAPI *SetLayer)(HWND hWnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);

#define LWA_COLORKEY            0x01

#define LWA_ALPHA               0x02

void FourierDlg::OnOK()
{
 // TODO: Add extra validation here
 
 HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));

  SetLayer pSetLayer = (SetLayer)GetProcAddress(hUser32, "SetLayeredWindowAttributes");

    if(pSetLayer == NULL)

    {

        MessageBox("win2000 이상");

        return;

    }

    char chAlpha = 100; //투명도 설정 0 ~ 255

    SetWindowLong(this->m_hWnd, GWL_EXSTYLE, GetWindowLong(this->m_hWnd, GWL_EXSTYLE) | 0x80000);
    pSetLayer(this->m_hWnd, 0,chAlpha, LWA_ALPHA);

 //CDialog::OnOK();
}

 

 


<뷰의 자유자재 이동 >


저 수준의 MFC 라이브러리를 사용하여 뷰전환 기능을 수행합니다.
어떤 View를 처음 볼 때는 Memory에 없기 때문에 그것을 Mem.으로 가지고 오고   
그렇지 않은 것은(한번 메모리에 올려 놓았던 것)단순히 View만 바꾸어 준다.
모든 동작은 MainFrame에서 수행합니다.

뷰전환하는 함수를 만들어야 겠죠....
이것은 MFC에 있는 함수가 아니고 제가 만든 것임.
void CMainFrame::SwitchToForm(int nForm)
{

     // 현재 활성화되어 있는 뷰 객체
     CView* pOldActiveView = GetActiveView(); 
     // 선택한 뷰 객체를 얻는다.
     CView* pNewActiveView = (CView*)GetDlgItem(nForm);
     if(pNewActiveView ==NULL)
     {          //nForm이 Form에 대한 ID라는 것은 아시죠..
          if(nForm==IDD_PROJ_FORM) // Form 추가시 View Change
                 pNewActiveView=(CView*)new CProjView;
      else if(nForm==IDD_VIEWER_FORM)      
          pNewActiveView=(CView*)new CViewerView;  
          else if(...)                 
          ....;
          else if(...)
          ....;
      else if(...)
          ...;

      CCreateContext context;
      context.m_pCurrentDoc=pOldActiveView->GetDocument();
           //새로운 뷰 윈도우 생성
      pNewActiveView->Create(NULL,NULL,0L,
          CFrameWnd::rectDefault,this,nForm,&context);
      pNewActiveView->OnInitialUpdate();
    }

   SetActiveView(pNewActiveView);
   pNewActiveView->ShowWindow(SW_SHOW);
   pOldActiveView->ShowWindow(SW_HIDE);
  
   UINT nID;
   /////////////// Form 추가시 View Change/////////////////////////////////////
   if(pOldActiveView->GetRuntimeClass() ==          
       RUNTIME_CLASS(CProjView))             
       nID = IDD_PROJ_FORM;
   else if(pOldActiveView->GetRuntimeClass() ==
       RUNTIME_CLASS(CViewerView))
       nID = IDD_VIEWER_FORM;
   else if(pOldActiveView->GetRuntimeClass() ==
       RUNTIME_CLASS(....))
       nID= ...;
   else if(pOldActiveView->GetRuntimeClass() ==
       RUNTIME_CLASS(...))
       nID= ...;
   else if(pOldActiveView->GetRuntimeClass() ==
       RUNTIME_CLASS(...))
       nID= ...;
   ////////////////////////////////////////////////////////////////////////////
   pOldActiveView->SetDlgCtrlID(nID);
   pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
   RecalcLayout();

} 이상 무
그람 즐프 히히 ^_^

 

 

이렇게 해보세요,,^^

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{

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

    m_pView1 = new  CFormView1(IDD_FORM1);

    m_pView1->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
        rectDefault, this, AFX_IDW_PANE_FIRST + 1, NULL);


    m_pView2 = new  CFormView2(IDD_FORM2);
    m_pView2->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
            rectDefault, this, AFX_IDW_PANE_FIRST + 1, NULL);

      //////  미리 폼뷰를 생성합니다.
  

}
void CMainFrame::ChangView(CView *View1, CView *View2)
{
   CDocument* pDoc = GetActiveDocument();
   int nSwitchChildID = View2->GetDlgCtrlID();

   View2->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
   View1->SetDlgCtrlID(nSwitchChildID);

   View2->ShowWindow(SW_SHOW);
   View1->ShowWindow(SW_HIDE);

   pDoc->AddView(View2);
   pDoc->RemoveView(View1);
   SetActiveView(View2);

   View2->OnInitialUpdate();
   View2->SetFocus();

   RecalcLayout();

}
void OnJop() //어떤 버튼이나 이벤트가 일어 날때
{
    CView * View  = GetActiveView();
    if(View == m_pView1) return;
    ChangView(View,m_pView1);
}

이런식으로 뷰를 바꾸어 주면 됩니다..

 도움이 되었는지 모르겠네요,,,

 

 


<다중모니터>


윈도우즈는 동시에 2개 이상의 모니터를 지원합니다.

그래서 이런 모니터(디스플레이)를 제어하기 위한 API가 따로 존재합니다.

    EnumDisplayMonitors
    GetMonitorInfo
    MonitorEnumProc
    MonitorFromPoint
    MonitorFromRect
    MonitorFromWindow

이런 함수가 있습니다... 그리고 이런 함수를 사용하기 위해서는 좌표계를

이해해야 하는데... 좌표는 주 디스플레이의 좌 상단이 (0, 0)이 되고

부 디스플레이의 위치에 따라 부 디스플레이의 좌표가 결정됩니다.

(부 디스플레이가 주 디스플레이의 왼쪽에 위치한다면 부 디스플레이의

x 좌표는 마이너스가 됩니다..)


그리고 가상 스크린(Virtual Screen)이라는게 있는데 이것은 모든 디스플레이를

포함하는 가장 큰 스크린을 말합니다.
 

    -> 만약 MoveWindow(-200, 100, 100, 100);  이렇게 윈도우를 옮긴다면

        위 상황에서 부 디스플레이에 윈도우가 위치하게 됩니다.
 

이외에 GetSystemMetrics의 SM_CMONITORS, SM_CXVIRTUALSCREEN

SM_CXVIRTUALSCREEN, 등의 함수로 Multiple Display에 대한 정보를

얻을 수 있습니다..

 

더 자세한 사항은 MSDN에 설명을 참고하시고요... Multiple Display는

Win98 이상에서만 동작한다는 것을 숙지하십시오.

반응형

'C & C++ > C & C++' 카테고리의 다른 글

[Tip] ExitWindowsEx 컴퓨터 종료  (0) 2011.05.24
[Tip] 네트워크 프린터 검색  (0) 2011.05.24
[TIP] 프로젝트 병합법  (0) 2011.05.24
(Tip) 포인터 값으로 추적하는 디버그 팁  (0) 2011.05.21
BOOL 과 bool 의 차이점  (0) 2011.05.06

댓글