GSI

다음 소스 프로그램은 현재 디렉토리의 모든 서브 디렉토리에 있는 파일을 찾아서 파일 이름을 모두 소문자로 바꾸는 루틴입니다. 자세한 내용은 각 함수별로 도움말을 참조하기 바랍니다.

void lookup()
{
    char new_filename[100];
    int leng;
    struct _finddata_t c_file;
    long hFile;
    int temp = 0;

    if ((hFile = _findfirst("*.*",&c_file)) == -1L) {
     cout << "error" << endl;
    }

    for (; temp == 0; temp = _findnext(hFile,&c_file)){
        leng = strlen(c_file.name);
        if ((c_file.attrib & _A_SUBDIR) == _A_SUBDIR){
            if (c_file.name[0] != '.'){
                _chdir(c_file.name);
                lookup();
                _chdir("..");
            }
        continue;
        }
        else if ((c_file.attrib & _A_ARCH) != _A_ARCH) continue;
        for(int i = 0;i < leng;i++){
            new_filename[i] = tolower(c_file.name[i]);
        }
        new_filename[i] = '\0';
        rename(c_file.name, new_filename);
    }
    _findclose(hFile);
}

Posted by gsi
:

2개의 툴바를 한줄에

C++ 2007. 10. 27. 02:19 |

class CMainFrame : public CFrame
{
protected:
    CToolBar wnd_myToolBar;
    CToolBar wnd_othToolBar;
    ...
};

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ...
    wnd_myToolBar.Create(...);
    wnd_othToolBar.Create(...);
    ...
}

DockControlBarLeftOf 함수를 이용하면 가능합니다. DockControlBarLeftOf(CToolBar* Bar, CToolBar* LeftOf)처럼 두 개의 툴바를 인수로 받기 때문입니다. 따라서 Bar와 LeftOf 툴바는 한줄에 출력될 것입니다. 다음 코드를 참고하기 바랍니다.

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    ...
    EnableDocking(CBRS_ALIGN_ANY);

    m_wndToolBar.SetWindowText(_T("myToolBar"));
    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
    DockControlBar(&m_wndToolBar, AFX_IDW_DOCKBAR_TOP);

    wnd_othToolBar.SetWindowText(_T("otherToolBar"));
    wnd_othToolBar.EnableDocking(CBRS_ALIGN_ANY);
    DockControlBarLeftOf(&m_wndToolBar, &wnd_othToolBar);
   ...
}

void CMainFrame::DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf)
{
    CRect rect;
    DWORD dw;
    UINT n;
    // get MFC to adjust the dimensions of all docked ToolBars
    // so that GetWindowRect will be accurate
    RecalcLayout();
    LeftOf->GetWindowRect(&rect);
    rect.OffsetRect(1,0);

    dw=LeftOf->GetBarStyle();
    n = 0;
    n = (dw&CBRS_ALIGN_TOP) ? AFX_IDW_DOCKBAR_TOP : n;
    n = (dw&CBRS_ALIGN_BOTTOM && n==0) ? AFX_IDW_DOCKBAR_BOTTOM : n;
    n = (dw&CBRS_ALIGN_LEFT && n==0) ? AFX_IDW_DOCKBAR_LEFT : n;
    n = (dw&CBRS_ALIGN_RIGHT && n==0) ? AFX_IDW_DOCKBAR_RIGHT : n;
    // When we take the default parameters on rect, DockControlBar will dock
    // each Toolbar on a seperate line.  
    // By calculating a rectangle, we in effect
    // are simulating a Toolbar being dragged to that location and docked.
    DockControlBar(Bar,n,&rect);
}

Posted by gsi
:

(펌) - http://blog.naver.com/stkov?Redirect=Log&logNo=90014489284

기본적으로, MFC는 CFrameWnd 클래스를 상속한 객체만 툴바와 상태바를 추가할 수 있도록 허용한다. 이 기능이 좋긴 하나 만약 툴바와 상태바를 다이알로그에 넣으려고 한다면, 그것을 쉽게 할 수 없기 때문에 바보 같다는 기분을 느낄 것이다.

첫 번째 문제는 모든 핸들러 함수가 자신의 기반 클래스가 CFrameWnd를 상속한 객체라고 예상하고 있으며, 나머지 하나는 다이알로그가 IDLE 상태일 때만 툴팁이나 상태바 메시지를 보일 수 있다는 것이다. 사실, 컨트롤 바(control bar)들이 제대로 작동하려면, 프레임 창이 사용하는 몇몇 메시지를 처리해야 한다.

나는 이 일을 하는 데 도움이 될 만한 몇몇 문서를 찾아서 분석해 봐야 했다. Mihai Filimon ( 1998년 3월 16일 월요일 기사)이 내게 보여준 기사는 좋았으나, 바를 어떤 정적 객체와 함께 삽입해야하기 때문에 깔끔하지는 않았다. (나는 내가 터널의 끝을 본 데에 대해서 그를 매우 고맙게 생각한다.)

네가 만약 프로그램 상의 툴바(도킹된 상태로. 다른 방법이 없다)와 상태바와 통신이 가능한 메뉴를 넣는 방법을 설명할 것이다.

나는 툴바를 다이알로그에 넣는 방법만을 설명할 것이다. (메뉴를 넣는 것은 리소스 편집기로 메뉴를 정의하기만 하면 되는 뻔한 작업이기 때문이다)

첫째로, 툴바의 위치를 방해하지 않도록 다이알로그를 만들고 CDialog 클래스를 Dialog template으로 상속받는다. (지금까지는 별다른 것이 없다)

그리고 CDialog::OnInitDialog 함수에 다음의 코드를 넣는다. (단, m_wndToolBar는 CToolBarEx 타입):

BOOL CMyDlg::OnInitDialog()
{
// TODO: Add extra initialization here
CDialog::OnInitDialog();

// 툴바를 삽입한다.
if (!m_wndToolBar.Create( this ) ||
!m_wndToolBar.LoadToolBar(IDR_CORPS_EMIS) )
{
TRACE0("Failed to create toolbar\n");
return -1;      // 생성 실패
}

// TODO: 사이즈를 조절 할 수 있고 툴팁이 표시되는 툴바를 원하지 않으면 이 코드를 삭제할 것.
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY  );

// 컨트롤 바를 넣기 위해서 다이알로그의 크기를 조절할 필요가 있다.
// 첫째로, 컨트롤 바가 얼마나 큰지 알아보자.
CRect rcClientStart;
CRect rcClientNow;
GetClientRect(rcClientStart);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,
   0, reposQuery, rcClientNow);

// 나머지 클라이언트 영역 안에서 같은 상대적인 위치를 가지도록 모든 컨트롤을 옮긴다.
 CPoint ptOffset(rcClientNow.left - rcClientStart.left,
rcClientNow.top - rcClientStart.top);

CRect  rcChild;
CWnd* pwndChild = GetWindow(GW_CHILD);
while (pwndChild)
{
pwndChild->GetWindowRect(rcChild);
ScreenToClient(rcChild);
rcChild.OffsetRect(ptOffset);
pwndChild->MoveWindow(rcChild, FALSE);
pwndChild = pwndChild->GetNextWindow();
}

// 대화창의 크기와 위치를 조절한다
 CRect rcWindow;
GetWindowRect(rcWindow);
rcWindow.right += rcClientStart.Width() - rcClientNow.Width();
rcWindow.bottom += rcClientStart.Height() - rcClientNow.Height();
MoveWindow(rcWindow, FALSE);

// 컨트롤 바를 옮긴다
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);

return TRUE;  // return TRUE unless you set the focus to a control
              // EXCEPTION: OCX Property Pages should return FALSE
}

여기서 뻔하지 않은 것들을 볼 수 있다. (나는 이것을 DLGCBR32라는 좀 더 복잡한 예제에서 찾았고, 반드시 삽입되어야 하는 함수들을 찾아내느라 고생했다.)

여기서, 툴바는 다이알로그의 맨 위쪽에만 삽입되게 된다. (위의 코드가 충분히 일반적이기 때문에, 위 대화창에 보여진 요구 사항들이 어떤 툴바에서도 충족하는 것을 알 수 있다). 다이알로그에 여러 개의 툴바를 넣을 수도 있지만, 그 위치는 알아서 조절해야 한다.

이제 툴바에 툴팁을 표시하고 싶다면, TTN_NEEDTEXTA과 TTN_NEEDTEXTW (ANSI와 유니코드 모두를 위함) 메시지를 다음의 방법으로 처리해야 한다.

1. 메시지 핸들러를 다음과 같이 선언한다.

BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
...
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
END_MESSAGE_MAP() 

2. 헤더 파일에 함수를 다음과 같이 정의한다.

// Generated message map functions
//{{AFX_MSG(CMyDlg)
afx_msg BOOL OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG 

3. 마지막으로 OnToolTipText 함수를 다음과 같이 코딩한다

(MFC 예제에서 퍼옴) :

BOOL CMyDlg::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
 ASSERT(pNMHDR->code == TTN_NEEDTEXTA || pNMHDR->code == TTN_NEEDTEXTW); 
 // 메시지를 처리하기 위해 최상위 계층의 routing frame을 허용 (?)
 if (GetRoutingFrame() != NULL) return FALSE; 
 
 // ANSI와 유니코드 메시지를 모두 처리한다.
 TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
 TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
 TCHAR szFullText[256];
 CString cstTipText;
 CString cstStatusText;
 UINT nID = pNMHDR->idFrom;
 
 if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) 
 || pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND)) { 
 // idFrom은 사실 툴바의 핸들이다. 
 nID = ((UINT)(WORD)::GetDlgCtrlID((HWND)nID));
 }
 
 if (nID != 0) // 구분자에서는 0. 
 { AfxLoadString(nID, szFullText); 
 // 이건 button index가 아니라 command ID. 
 AfxExtractSubString(cstTipText, szFullText, 1, '\n');
 AfxExtractSubString(cstStatusText, szFullText, 0, '\n'); }
 // 툴팁 윈도우에는 ANSI만 표시 가능
 
 if (pNMHDR->code == TTN_NEEDTEXTA)
 lstrcpyn(pTTTA->szText, cstTipText, 
 (sizeof(pTTTA->szText)/sizeof(pTTTA->szText[0]))); 
 else _mbstowcsz(pTTTW->szText, cstTipText,
 (sizeof(pTTTW->szText)/sizeof(pTTTW->szText[0]))); 
 
 *pResult = 0; 
 // 툴팁 창을 모든 팝업 윈도우의 위에 둔다. 
 ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0, 
 SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE);
return TRUE; // 메시지가 처리됨 
} 

이제 툴바에 툴팁이 삽입된 것을 볼 수 있을 것이다. (툴팁에 보여지는 텍스트는 리소스 에디터를 쓰는 고전적인 방법으로 정의할 수 있다. 휴~ ;-) )

만약 메인프레임의 상태바에 텍스트를 보여주고 싶다면 단 한 줄의 코드를 위의 함수에 리턴하기 바로 전에 넣으면 된다: (단, m_wndStatusBar가 public인 경우에만)

// 메인프레임의 상태바에 텍스트를 표시한다 (단, 도움말 표시부가 인덱스 0에 있을 경우)

((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText(0, cstStatusText);

이것이 오늘 할 말의 끝이다.

아, 한 가지만 더 말하도록 하겠다. 만약 다이알로그 메뉴가 메인프레임의 상태바에 텍스트를 표시하게 하고 싶다면 (다른 상태바라도 됨) WM_MENUSELECT (window-type 핸들러)의 핸들러 함수에 다음의 코드를 넣으면 된다:

void CMyDlg::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu) { 
 CDialog::OnMenuSelect(nItemID, nFlags, hSysMenu); 
 TCHAR szFullText[256]; 
 CString cstStatusText; 
 
 // TODO: Add your message handler code here
 // 메인프레임의 상태바 창에 출력. 
 if (nItemID != 0) 
 // 구분자에서는 반드시 0.
 { 
 AfxLoadString(nItemID, szFullText); 
 // 이것은 button index가 아닌 command id. 
 AfxExtractSubString(cstStatusText, szFullText, 0, '\n');
 ((CMainFrame*)GetParent())->m_wndStatusBar.SetPaneText(0,cstStatusText);
 } 
} 
 
다이알로그가 IDLE 상태일 때에만 새로 고쳐지기 때문에 이 툴바에는 ON_UPDATE_COMMAND
_UI 메시지를 쓸 수 없다는 것에 유의하자. 만약 그것을 하고 싶다면, CToolBar (또는 CStatus
Bar) 클래스를 상속받아서 - CMyToolBar는 예를 든 것이다 - WM_IDLEUPDATECMDUI 핸들러를
추가하고, 다음의 코드를 그 함수에 넣자:
 
////////////////////////////////////////////////////////////////////////
// CMyToolBar::OnIdleUpdateCmdUI 
// OnIdleUpdateCmdUI는 WM_IDLEUPDATECMDUI 메시지를 처리하는데, 그것은 MFC 프레임
// 워크 안에서 UI 요소의 상태를 업데이트하는 데 쓰인다. (?) 
 
// 여기서 나는 약간의 트릭을 썼다: CToolBar::OnUpdateCmdUI는 첫 번째 인수로 CFrame
// Wnd 포인터를 요구한다. 하지만, 그 함수는 아무것도 하지 않고 그 인수를 CCmdTarget 
// 포인터를 요구하는 다른 함수에 넘긴다. 우리는 CFrameWnd가 아닌 CCmdTarget인 CWnd 
// 포인터를 부모 윈도우에서 받을 수 있다.
// 그렇다면, CToolBar::OnUpdateCmdUI를 기쁘게 만들기 위해서 여기서 CWnd 포인터를
// 잠깐 CFrameWnd로 바꾸기로 하자.
 
LRESULT CMyToolBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM) 
{
 if (IsWindowVisible())
 {
 CFrameWnd *pParent = (CFrameWnd *)GetParent();
 if (pParent)
 OnUpdateCmdUI(pParent, (BOOL)wParam);
 }
 return 0L;
} 
 
AfxLoadString 때문에, "Afxpriv.h"를 CPP 파일 맨 위에 포함(Include)시켜야 컴파일 할 
수 있다.
Posted by gsi
:

(펌) - http://fefene.tistory.com/88

34. ToolBar에 ComboBox붙이기
  CComboBox m_combo; //객체생성
  ID 등록 => view 메뉴 => resource symbol => new => ID_COMBO
  oncreate 에 내용 추가 (콤보를 만들고 표시하는 내용)
  m_wndToolBar.SetButtonInfo(10,IDC_COMBO,TBBS_SEPARATOR,150); 
  //툴바의 10번째버튼을 편집한다
  CRect itemRect; //콤보를넣을 사각형을 만든다
  m_wndToolBar.GetItemRect(10,&itemRect); //툴바의 10번째 버튼을 사각형에 넣는다
  itemRect.left+=5; //앞여백
  itemRect.right+=5; //뒤여백
  itemRect.bottom+=100; //콤보가열릴 공간확보
   m_combo.Create(WS_CHILD|WS_VISIBLE|CBS_DROPDOWN,itemRect,&m_wndToolBar,IDC_COMBO);
  //콤보박스를 툴바에 붙여준다
   m_combo.AddString("이름"); //내용추가
   m_combo.SetCurSel(0); //셀 선택

35.  Toolbar에 수동으로넣은 ComboBox 사용하기
  afx_msg void [안내]태그제한으로등록되지않습니다-xxOnSelectCombo(); //원형
  ON_CBN_SELCHANGE(IDC_COMBO,[안내]태그제한으로등록되지않습니다-xxOnSelectCombo) //메세지맵에 추가
  CMainFrame *pMain=(CMainFrame *)GetParent(); //메인프레임 주소참조
  CComboBox *pCom=(CComboBox *)(pMain->m_wndToolBar.GetDlgItem(IDC_COMBO));
  //콤보박스의 주소를 가져온다, 접근할 때 메인프레임 -> 툴바 -> 콤보박스 의 순서로 가야한다
  int n=pCom->GetCurSel(); //현재선택된 셀의 인덱스를 가져온다
  if(n==CB_ERR) return; //선택된셀이 없으면 중지한다
  CString str;
  pMain->m_combo.GetLBText(n,str); //선택된셀의 Text를 가져온다

36. UPDATE_COMMAND 사용하기
  pCmdUI->Enable(TRUE); //버튼 활성화
  pCmdUI->SetText((bAdd)?"취소":"신규"); //버튼의 text 설정
  pCmdUI->SetCheck(TRUE); //버튼 체크

37. 프로그램정보저장
  CWinApp::GetProfileString(섹션명,항목명,기본값); // 함수를 사용한다. (문자열)
  CWinApp::GetProfileInt(섹션명,항목명,기본값); //불러올때사용 (숫자) 
  CWinApp::WriteProfileString(섹션명,항목명,값); //저장할때 사용 (문자열)
  CWinApp::WriteProfileInt(섹션명,항목명,값); //저장할때 사용 (숫자)
  //불러올때 사용할함수
  void CMainFrame::ActivateFrame(int nCmdShow) //프로그램 실행후 프레임생성될때 실행
  //저장할 때 WM_DESTROY 메시지 사용

38. 컨트롤바 표시하기
  CMainFrame *pMain=(CMainFrame *)GetParent(); //MainFrame 주소가져오기
  //툴바를 bTool2 에따라 보이고 감춘다
  pMain->ShowControlBar(&pMain->m_wndToolBar,bTool1,FALSE);

39. Window 창크기,위치정보 저장하기
  MainFrame 의 WM_DESTROY 에
    WINDOWPLACEMENT w;
    this->GetWindowPlacement(&w); //윈도우의 정보를 저장한다.
    CString strRect;
    strRect.Format("%04d,%04d,%04d,%04d", //04d 는 4자리 확보하고 남은건 0으로 채워라
         w.rcNormalPosition.left,w.rcNormalPosition.top,
         w.rcNormalPosition.right,w.rcNormalPosition.bottom); //윈도우의 위치,크기 확보..
        
        BOOL bMax,bMin; //윈도우의 상태를 저장하기위한 변수
        //w.falg 는 이전상태의 정보를 가지고 잇다!!
        if(w.showCmd==SW_SHOWMINIMIZED)           //최소화 상태
        {
                bMin=TRUE;
                if(w.flags==0) //falg 값이 0 이면 이전 상태가 보통상태이다!!
                        bMax=FALSE;
                else   //이전상태가 최대화 상태
                        bMax=TRUE;
        }
        else                            
        {
                if(w.showCmd==SW_SHOWMAXIMIZED) //최대화상태
                {
                        bMax=TRUE;
                        bMin=FALSE;
                }
                else //보통 상태
                {
                        bMax=FALSE;
                        bMin=FALSE;
                }
        }
        AfxGetApp()->WriteProfileString("WinStatus","Rect",strRect);
        AfxGetApp()->WriteProfileInt("WinStatus","Max",bMax);
        AfxGetApp()->WriteProfileInt("WinStatus","Min",bMin);


//읽어올차례..
ActivateFrame 함수로 가서
        WINDOWPLACEMENT w;  //윈도우의 상태를 저장하는 구조체..
        BOOL bMax,bMin;               //최대,최소상태를 저장할 변수
        CString strRect; //창크기를 받아올 변수
        strRect=AfxGetApp()->GetProfileString("WinStatus","Rect","0000,0000,0500,0700");
        bMin=AfxGetApp()->GetProfileInt("WinStatus","Min",FALSE);
        bMax=AfxGetApp()->GetProfileInt("WinStatus","Max",FALSE);
        int a=atoi(strRect.Left(4)); //문자열을 int 로 바꿔준다.
        int b=atoi(strRect.Mid(5,4));     //atoi 아스키 값을 int형으로 바꿔준다..
        int c=atoi(strRect.Mid(10,4));
        int d=atoi(strRect.Mid(15,4));
        w.rcNormalPosition=CRect(a,b,c,d);
        if(bMin)
        {
                w.showCmd=SW_SHOWMINIMIZED;
                if(bMax)
                {
                        w.flags=WPF_RESTORETOMAXIMIZED  ;
                }
                else
                {
                        w.flags=0;
                }
        }
        else
        {
                if(bMax)
                {
                        w.showCmd=SW_SHOWMAXIMIZED;
                }
                else
                {
                        w.showCmd=SW_SHOWNORMAL;
                }
        }
        this->SetWindowPlacement(&w); //설정된 값으로 윈도우를 그리게 한다..
        
        //CFrameWnd::ActivateFrame(nCmdShow); //이건 반드시 주석처리한다..

Posted by gsi
:

CTabCtrl 컨트롤을 사용하게 되면 탭의 내용을 추가해주어야 합니다.

아래와 같이 하나하나 추가 하게 되는데요.
m_tbMain.InsertItem(0, "Pixel Map");
m_tbMain.InsertItem(1, "Programming");
m_tbMain.InsertItem(2, "Color...");


사실 이렇게 하게 되면 탭이 늘어나거나 코드의 분량이 많아 지거나 하는 조금 지저분하게 되는 경향이 생기기도 합니다. 중간에 고치기 위해서 해당 코드를 찾아야 하구요.
그래서 아래와 같이 바꿔 보았습니다.

탭 컨트롤이 많은 어플에서는 유용할지도 모르겠어요.

탭에 들어갈 이름을 배열로 선언해 놓습니다.
TCHAR * tab_MainHeadersName[] = {
        _T("Pixel Map"),
        _T("Programming"),
        _T("Color..."),
        NULL };


이것을 사용하기 위해서 아래와 같이 for문을 사용해서 자동으로 입력 받습니다.
for (int i = 0; ; i++) {
 if (tab_MainHeadersName[i] == NULL) break;
 m_tbMain.InsertItem(i, tab_MainHeadersName[i]);
}


이렇게 하게 되면 코드 분량도 작아 지고 수정도 용이 하게 됩니다.
하지만 이런 코드를 컨트롤마다 다 넣어 주자니 귀찮아 집니다. ^^
그래서 아래와 같이 디파인으로 묶어 보았습니다. ^^

// 탭 컨트롤 해당 헤더 정보를 사용해서 자동으로 이름 부여 하는 디파인
#define TABCTRL_AUTOINPUT_INSERTITEM(ctl, headerlist) \
 for (int i = 0; ; i++) {       \
  if (headerlist[i] == NULL) break;    \
  ctl.InsertItem(i, headerlist[i]);    \
 }


이제 코드에서는 한줄로 해당 탭 이름을 추가할 수 있습니다.
// 탭 추가
TABCTRL_AUTOINPUT_INSERTITEM(m_tbMain, tab_MainHeadersName);
// 첫번째 항목이 선택되게.
m_tbMain.SetCurSel(0);


어때요?.
코드의 정리 면에서 더 효율이 있을가요? ^^
이런 항목들이 많아 진다면 config.h, cpp 등을 두어서 그쪽에 다 모아 놓으면 될거 같구요.
mfc를 할때는 그냥 stdafx.h, cpp 에 몰아 놓고 작업할때도 있어요.

나름대로 정리해본 내용입니다.
더 좋은 방법이 있다면 연락 주시거나 코멘트 남겨 주세요.
Posted by gsi
:

사용자 삽입 이미지

컬럼 정보를 크기에 맞도록 채우는 코드 입니다.
넓이 값을 가져 와서 비율 적으로 처리 하는 부분도 있지만.
그 부분을 빼고 직접 넓이를 지정하게 하는 구조를 취하게 했습니다.

코드는 아래와 같습니다.

//컬럼 채우기
int m_nColWidths[] = { 90, 60}; // sixty-fourths
TCHAR * lpszHeaders[] = {
       _T("Port/Sequence"),
       _T("Address"),
       NULL };

int i;
LV_COLUMN lvcolumn;
memset(&lvcolumn, 0, sizeof(lvcolumn));

// add columns
for (i = 0; ; i++)
{
 if (lpszHeaders[i] == NULL)
  break;

 lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
 lvcolumn.fmt = LVCFMT_LEFT;
 lvcolumn.pszText = lpszHeaders[i];
 lvcolumn.iSubItem = i;
 lvcolumn.cx = m_nColWidths[i];
 m_listPortSequencePerAddress.InsertColumn(i, &lvcolumn);
}

lpszHeaders, m_nColWidths 의 정보를 사용해서 for문을 통해서
컬럼 정보를 입력 하는 구조입니다.

하드 코딩 하는거 보다는 이 방법을 취하는게 중간 중간 컬럼명이 바뀔 경우
lpszHeaders의 내용만 수정해 주면 되니까 편한듯 합니다.

Posted by gsi
:

Dialog Form (MFC) 를 개발하다 보면 CView, CScroll, CHtmlView 등과 같은
뷰의 클래스를 추가 하고 싶을때가 있다.

하지만 동적으로 생성하는 방법을 사용해서
CMyView* pMyView = new CMyView();
pMyView.Create(...);
pMyView.ShowWindow(SW_SHOW);

이런 방법을 사용하게 되면 생성후에 화면에 제대로 나오는걸 확인할 수 있다.
하지만 종료할때 보면 디버그 에러가 발생하게 된다.

자세한 이유는 모르겠다. 하지만 분명한건 아래와 같은 RUNTIME_CLASS() 를 사용해서 생성해야 하는걸 확인하였다.
아래와 같이 코드를 작성해서 추가를 해보면 이상없이 동작하는 것을 확인할 수 있다.

///
BOOL CDlgTestViewDlg::OnInitDialog()
{
...
 CCreateContext pContext;
 /**
 * Note:CDialig derived pointer is converted to
 * CWnd pointer (a common base class for CDialog and CFrameWnd).
 * Thus casting it back to CFrameWnd is also easy.
 */
 CWnd* pFrameWnd = this;
 
 pContext.m_pCurrentDoc = new CDocument;
 pContext.m_pNewViewClass = RUNTIME_CLASS(CTestView);
 CTestView *pView =
  (CTestView *) ((CFrameWnd*)pFrameWnd)->CreateView(&pContext);
 ASSERT(pView);
 pView->ShowWindow(SW_NORMAL);

 /**
 * After a view is created, resize that to
 * have the same size as the dialog.
 */
 CRect rectWindow;
 rectWindow = CRect(10, 10, 100, 100);
 /**
 * Leave a little space for border and title...
 */
 pView->MoveWindow(rectWindow);

...

 return TRUE;
}
Posted by gsi
:

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Developer Studio">
<META HTTP-EQUIV="Content-Type" content="text/html; charset=iso-8859-1">
<TITLE>Netshow 3.0 Beta 1 - Close Captioning Sample</TITLE>
</HEAD>
<BODY>
    <CENTER>
        This is a sample of Close Captioning using Netshow 3.0<BR>
        and SAMI (Synchronized Accessible Media Interchange) files.<BR><BR><BR>

        <!-- BEGIN GENERIC ALL BROWSER FRIENDLY HTML FOR NETSHOW V3 -->
        <OBJECT ID="MediaPlayer1" width=320 height=240 classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
                codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"
                standby="Loading Microsoft Media Player components..." type="application/x-oleobject">
                <PARAM name="FileName" value="kstr100.asf">
                <PARAM name="SAMIFileName" value="ccsample.smi">
                <PARAM name="ShowCaptioning" value="1">
                <PARAM name="ShowControls" value="1">
                <EMBED type="application/x-mplayer2"
                       pluginspage="http://www.microsoft.com/Windows/Downloads/Contents/Products/MediaPlayer/"
                       filename="kstr100.asf"
                       name="MediaPlayer1"
                       width=320
                       height=240
                       SAMIFileName="ccsample.smi"
                       ShowCaptioning=1
                       ShowControls=1
                ></EMBED>
        </OBJECT>
        <BR>
        <A href="kstr100.asf">Start the NetShow presentation in the stand-alone player.</A>
        <!-- END GENERIC ALL BROWSER FRIENDLY HTML FOR NETSHOW V3 RTM -->
    </CENTER>
</BODY>
</HTML>

Posted by gsi
:

10.22 ~ 10.26 일까지 동영상 소프트 웨어 교육을 받는다.
Direct Show를 사용해서 하는것..

이것을 배우면 동영상 제작을 통한 웹 관련 프로젝트를
진행할 수 있을런지..
제대로 함 받아봐야 겠다.
Posted by gsi
:

csFile 클래스 래퍼 클래스

C# 2007. 10. 19. 15:45 |

csFile 클래스
때로는 사용하기 쉬운 메서드를 제공하는 간단한 클래스를 만들고, 그 안에서 이들 파일과 관련된 메서드들을 감싸두면( Wrap ) 편리하다. 그러므로 여기서는 그러한 csFile 클래스를 작성하고, 나머지 장들의 예제에서 이 클래스를 사용해 볼 것이다.

public class csFile {
   private string fileName;
   StreamReader ts;
   StreamWrite ws;

   private bool opened, writeOpened;

   //--------------
   public csFile() { Init(); }

   //--------------
   private void Init() {
      opened = false;
      writeOpened = false;
   }

   //---------------
   public csFile(string file_name) {
      fileName = file_name;
      Init();
   }
}

우리는 두 가지 방법으로 파일을 읽기 위해 열 수 있다. 하나는 파일 이름을 포함하는 것이고, 다른 하나는 파일 이름을 인수로 받는 것이다.

그리고 readLine 메서드를 이용하여 텍스트 파일로 부터 데이터를 읽어 올 수 있다.

public bool OpenForRead(string file_name)
{
   fileName = file_name;
   try {
      ts = new StreamReader(fileName);
      opened = true;
   }
   catch(FileNotFoundException e) {
      return false;
   }
   return true;
}

//-----------------
public bool OpenForRead() {
   return OpenForRead(fileName);
}
public string readLine() {
   return ts.ReadLine();
}

마찬가지로, 다음 메서드는 파일에 쓸 수 있게 해준다.

public void writeLine(string s) {
   ws.WriteLine(s);
}
//------------
public bool OpenForWrite() {
   return OpenForWrite(fileName);
}
//------------
public bool OpenForWrite(string file_name) {
   trye {
      ws = new StreamWriter(file_name);
      fileName = file_name;
      writeOpended - true;
      return true;
   }
   catch(FileNotFoundException e) {
      return false;
   }
}

앞으로 파일 읽어야 할 때 이렇게 단순화된 파일 메서드 래퍼 클래스를 사용하면 좋다.

Posted by gsi
:

파일 끝을 검사하기

C# 2007. 10. 19. 15:44 |

파일 끝을 검사하기
파일의 끝을 지났는지 확인하는 방법에는 두 가지가 있다. 즉, null 예외를 찾는 것과 데이터 스트림의 끝을 찾는 것이다. 실제로, 텍스트 파일의 끝을 지나서 파일을 읽더라도 아무런 에러도 발생하지 않고, 파일 끝 예외도 발생하지 않는다. 그러나 파일의 끝을 지나서 읽으려고 한다면, null 값을 반환받게 될 것이다. 그러므로 이것을 이용하여 파일을 읽는 클래스에서 파일 끝을 검사하는 기능을 만들 수 있다.

private StreamReader rf;
private bool eof;
//--------------
public String readLine() {
   String s = rf.ReadLine();
   if( s == null )
      eof = true;
}
//---------------
public bool fEof {
  return eof;
}

파일의 끝을 지나서 읽는 것을 막기 위한 또 다른 방법은 Stream 객체의 Peek 메서드를 사용하여 미리 값을 꺼내 오는 것이다. 이것은 남은 문자가 있으면 다음 문자의 아스키 코드 값을 반환하고, 남아 있는 문자가 없으면 -1을 반환한다.

public String read_Line() {
   String s = "";
   if(rf.Peek() > 0) {
      s = rf.ReadLine();
   } else {
      eof = true;
   }
   return s;
}
Posted by gsi
:

파일 내에서의 예외 처리

C# 2007. 10. 19. 15:44 |

파일 내에서의 예외 처리
자주 발생하는 많은 예외는 파일의 입출력이 일어날 때 생긴다. 주로 유효하지 않은 파일 이름, 존재하지 않는 파일, 존재하지 않는 디렉토리, 유효하지 않은 파일 이름 인수, 파일 접근 권한 에러 등의 예외를 접할 수 있다. 따라서 파일의 입출력을 처리하는 가장 좋은 방법은, 파일을 처리 하는 코드를 try  불록에 넣고 가능한 모든 에러 조건을 잡아서 당황스럽고 치명적인 에러를 방지하는 것이다. 다양한 파일 클래스의 메서드에서 발생할 수 있는 모든 예외는 문서에 나타나 있다. 그리고 확실하게 모든 예외를 잡아내고 싶으면 일반적인 Exception 객체에 대한 처리를 하면 된다. 그러나 각각의 예외에 대해 다른 처리를 하고 싶다면, 예외에 따라 분리해서 검사할 수 있다.

try {
   // 텍스트 파일을 읽기 위해 연다.
   StreamReader ts = File.OpenText("fool.txt");
   String s = ts.ReadLine();
}
catch (Exception e) {
   Console.WriteList(e.Message);
}
Posted by gsi
:

파일 처리 (File Handling)

C# 2007. 10. 19. 15:42 |

C# 에서 파일을 처리하는 객체는 파일을 유연하게 사용하는 방법을 제공한다.

File 객체
File 객체는 파일을 나타내며, 파일의 존재를 검사하고, 이름을 바꾸고, 지우는 등의 기능을 하는 유용한 메서드 들을 제공한다. 모든 메서드는 static이므로 이들 메서드를 사용하기 위해 File 클래스의 인스턴스를 생성할 필요는 없다. 그 대신, 메서드를 직접 사용하면 된다.

fi(File.Exists("Foo.txt"))
   File.Delete("Foo.txt");

File을 사용하여 파일을 읽고 쓰는데 필요한 FileStream을 구할 수도 있다.

//텍스트 파일을 읽기 위해 파일을 연다.
StreamReader ts = File.OpenText("fool.txt");
//임의의 타입의 파일을 읽기 위해  파일을 연다.
FileStream fs = File.OpenRead("foo2.any");

File  클래스의 메서드들...

  • File.FileExists(filename) : 파일이 존재한다면 true를 반환함
  • File.Delete(filename) : 파일 삭제
  • File.AppendText(fliename) : 텍스트를 덧붙임
  • File.Copy(filename) : 파일 복사
  • File.Move(filename) : 파일 이동 후 이전 파일은 삭제
  • File.GetExtension(filename) : 파일 확장자를 반환함
  • File.HasExtension(filename) : 파일이 확장자를 갖고 있다면 true를 반환함

텍스트 파일 읽기
텍스트 파일 읽기 위해서는, File 객체를 이용하여 StreamReader 객체를 얻어내야 한다. 그 다음에는 텍스트 스트림을 읽는 메서드를 사용하면 된다.

StreamReader ts = File.OpenText("fool.txt");
String s = ts.ReadLine();

텍스트 파일 쓰기
텍스트 파일을 만들고 쓰기 위해서는, CreateText 메서드를 사용하여 StreamWriter를 얻어낸다.

//쓰기 위해 열기
StreamWriter sw = File.CreateText("Foo3.txt");
sw.WriteLine("Hello file");

만약 이미 존재하는 파일에 덧붙이기를 원한다면, 파일 이름 다음에 오는 Boolean 인수를 true로 지정하여 직접 StreamWriter 객체를 생성할 수도 있다.

//텍스프 파일에 덧붙이기
StreamWriter asw = new StreamSwiter("fool.txt", true);
Posted by gsi
:

Exception (예외) 처리

C# 2007. 10. 19. 15:17 |

Exception

C# 에서의 에러 처리는 예외를 사용하여 손쉽게 수행된다. 예외 처리는 에러가 발생할 만한 구문들을 try 블록 안에 넣고, catch 블록에서 에러를 잡는 것이다.

try {
   // 에러가 발생할 만한 구문
}
catch (Exception e) {
   // 에러가 발생했을 때 처리하는 구문
}
finally {
   // 언제나 실행되는 구문
}


이러한 접근 방식은 파일을 다루는 문장에서 에러를 검사하거나, 배열의 범위를 벗어나는 인덱스 문장의 에러를 잡아내는 등의 여러가지 에러 상황을 검사하는 곳에서 사용된다. 이 방법이 동작하는 방식은 일단 try 블록이 실행되고, 여기서 에러가 발생하지 않으면, finally 블록이 실행된다. 만약 try 구문내에서 에러가 발생하면 제어가 catch 구문으로 넘어간 후, finally 블록을 실행하고 밖으로 빠져나가게 된다.

다음 예제는 예외를 검사하는 것을 보여준다. ArrayList 에서 범위를 벗어난 값에 접귾려고 했기 때문에, 에러가 발생할 것이다.

try {
   // 너무 많이 접근한다는 점에 주의 하자
   for(int i = 0; i <= arl.Count; i++)
      console.WriteList(arl[i]);
}
catch (Exception e) {
   Console.WriteList(e.Message);
}


이 코드는 에러 메시지를 출력하고, 프로그램에서 에러가 발생한 부분을 보여주고 계속 실행된다.

0123456789 인덱스가 범위를 벗어났습니다.
인덱스는 음수가 아니어야 하며 컬렉션의 크기보다 작아야 합니다.
매개 변수 이름 : index
   at System.Collections.Arraylist.get_Item(int32 index)
   at arr.Form1..ctor() in form1.cs:line 58

만약 예외를 잡아내지 못하면, 실행중에 시스템으로부터 에러 메시지를 받고, 프로그램은 계속 진행되지 않고 종료될 것이다.

C# 예외 클래스들..

  • AccessException : 클래스의 메서드 또는 필드에 접근할 때의 에러
  • ArgumentException : 메서드의 인수가 유효하지 않음
  • ArgumentNullException : 인수가 null임
  • ArthmeticException : 오버플로우 또는 언더플로우
  • DivideByZeroException : 0으로 나누기
  • IndexOutOfRangeException :배열의 범위를 넘어선 인덱스
  • FileNotFoundException : 파일을 찾을수 없음
  • EndOfStreamException : 입력 스트림의 범위를 넘어선 접근
  • DirectoryNotFoundException : 디렉터리를 찾을 수 없음
  • NullReferenceException : 객체 변수가 실제값으로 초기화 되지 않음

다중 예외
여러 개의 catch 블록에서 여러 개의 예외를 받아 서로 다르게 처리할 수 있다.

try {
   for(int i = 0; i <= arl.Count; i++) {
      int k = (int)(float)arl[i];
      Console.Write(i + "" + k/i);
   }
   catch (DivideByZeroException e) {
      printZErr(e);
   }
   catch (IndexOutOfRangeException e) {
      printOErr(e);
   }
   catch(Exception e) {
      printErr(e);
   }
}


예외 던지기
예외가 발생했다고 해서 바로 그곳에서 처리해야할 필요는 없다. throw 구문을 사용하여 호출한 프로그램에게 예외를 전달할 수 있다. 이것은 호출한 프로그램에서 예외가 발행하게 하는 것이다.

try {
   // 구문
}
catch (Exception e) {
   throw(e);      // 호출한 프로그램에게 전달한다.
}

C#은 자바의 throw 구문을 지원하지 않는다는 것에 주의 하자. 자바에서는 메서드가 예뢰를 던질 것이라는 것을 선언할 수 있으므로, 프로그램에서는 반드시 예외 처리 핸들러를 제공해야 한다.

Posted by gsi
:

Collection 객체

C# 2007. 10. 19. 14:38 |

System.Collections 네임 스페이스에는 여러가지 방법으로 항목을 추가하거나 구할 수 있는 가변 길이의 배열 객체들이 많이 있다.

ArrayList
ArrayList 객체는 필요할 때마다 항목을 추가할 수 있는 가변 길이의 배열로, ArrayList의 기본적인 메서드를 사용하면 쉽게 배열에 요소를 추가하고, 개별 요소를 변경시킬 수 있다.

float[] z = {1.0f, 2.9f, 5.6f};
ArrayList arl = new ArrayList();
for(int j = 0; j < zLength; j++)
{
   arl.Add(z[j]);
}

ArrayList는 배열의 개수를 찾느 데 사용할 수 있는 Count 속성을 갖고 있다. ArrayList를 배열과 같이 취급하여, 0에서 시작하여 Count 속성 값보다 하나 작은 값까지 이동하면서 이들 요소에 접근 할 수 있다.

for(j = 0; j < arl.Count; j++)
{
   Console.WriteList(arl[j]);
}

또한 foreach 루프 구문을 사용하여 인덱스 변수를 생성하거나, ArrayList의 길이를 알지 못하고도  ArrayList 객체의 멤버에 순차적으로 접근 할 수 있다.

foreach(float a in arl)
{
   Console.WriteList(a);
}

ArrayList에서 가져온 객체는 항상 object 타입이다. 따라서 우리는 그것을 사용하기 전에 반드시 정확한 타입으로 변환해야 한다.

float x = (float)arl[j];

ArrayList 메서드

  • Clear :  ArrayList 안에 있는 모든 내용을 삭제한다.
  • Contains(object) : ArrayList가 해당하는 값을 가지고 있으면 true를 반환한다.
  • CopyTo(array) : ArrayList의 모든 내용을 일차원 배열에 복사한다.
  • IndexOf(object) : 해당하는 값의 첫번째 인덱스를 반환한다.
  • Insert(index, object) : 정해진 인덱스에 요소를 삽입힌다.
  • Remove(object) : 목록에서 지정된 객체를 삭제한다.
  • RemoveAt(index) : 지정된 위치에서 요소를 삭제한다.
  • Sort : ArrayList를 정렬한다.


HashTable

HashTable은 각각의 요소들을 키 값으로 접근할 수 있는 가변 길이의 배열이다. 일반적으로 키 값은 문자열로 지정하지만, 어떤 객체로 지정해도 상관이 없다. 각각의 요소는 중복되는 값이 있어도 상관없지만, 그 키 값은 반드시 유일해야 한다. HashTable은 크고 정렬되지 않은 항목들의 집합에 빠르게 접근하는 데 사용되고, 키와 요소의 값을 역순으로 함으로써 요소가 중복되지 않는 것을 보장하기 위해 사용되기도 한다.

HashTable hash = new HashTable();
float freddy = 12.3f;
hash.Add("fread", freddy);
float tmp = (float)hash["fread"];

ArrayList 에서와 같이 HashTable에서 구한 갑도 만드시 적절한 타입으로 변환해서 사용해야 한다. 또한, HashTable도 Count 속성을 가지고 있으므로 클래스의 키 또는 값들의 개수를 알아낼 수 있다.

SortedList
SortedList 클래스는 두 개의 내부 배열을 관리하며, 0부터 시작하는 인덱스와 알파벳 키 중 하나를 사용하여 요소를 구할 수 있다.

float sammy = 44.5f;
ShortedList slist = new SortedList();
slist.Add("fred", freddy);
slist.Add("sam", sammy);
float newFred = (float)slist.GetByIndex(0);
float newSam = (float)slist["sam"];
Posted by gsi
: