심심해서 만들어본 시리얼 테스트 프로그램


툴 : bds2006
사용 컴포넌트 : CPort 3.1
제작기간 : 1day


cport test.zip


반도체 Probo Neelde Insert 장비...

작업환경 : BDS 2006 (화면 및 Vision & MCS 통신)
               PE-WIN(MCS)

조금 어려운 장비다.. 비전쪽에서도 제대로 넘겨줄지 모르겠음..

우선 07.3.12 부터 작업 시작(기존 예비 작업을 수정 시작)

07.10. 납품..
현재 작업중인 프로그램...

제어부도 모두 PC BASE이다...  리니어 모터를 사용하는 장비...


아직 화면만 잡아 놔서 얼마 되지 않지만... 그래도... 장비 일하면서 처음으로 빌더로 만드는 프로그램이다..

앞으로는 아마 계속 빌더로 작업할 생각이다.. 시간 문제도 그렇고...

구관이 명관이라고.. 난 빌더가 좋다.. 뭐 어쩔수 없는 경우에는 MFC도 쓰겠지만..

























화면을 전면 수정...

HMI를 처음 써 보면서 만들고 있는 프로그램이다.

제어부는 PLC로 되어 있고.. 화면에서 지령 및 데이터 관리는 화면에서 처리하도록 되어 있다..

처음 만들어서 그런지 조금은 어설픈 듯한데.. 사람들 반응은 의외로 좋다..

HMI도 어차피 베이스는 윈도우 기반이라서 프로그램 짜듯이 짜면 된다..

그런데, 지원이 안 되는 부분들이 있어서 조금은 짜증이 나기도 하는 개발툴이다..




 
저항 값을 계산하면서 심심해서 만들어본 프로그램이다..

BDS 에서 처음으로 완성(?)한 프로그램이다..

그동안 MFC만 3년 가까이 쓰다가 다시 빌더로 돌아와서 만들어서 그런지 좀 해메기도 하고.. ㅠㅠ

인터넷에 자바 스크립트로 작성되어 있는것을 BDS로 옮겼을뿐이다.. (안의 내용은 귀찮아서 안 보고.. 그냥.. 그림파일만 갔다가 내 스타일에 맞게 잘라서 사용했음)

저항값 계산을 나처럼 못 외우는 사람은 쓸만할지도..

뭐 너무 간단한 프로그램이어서.. 완성이라고 하기도 좀 그렇네..


좌우지간 소스도 간단하고..

뭐 사용법은 각 ComboBox 값을 바꾸면 자동으로 저항값하고 오차값이 바뀌는 형식이다..
(색띠를 클릭해도 변경된다. 최고값이 되면 최소값으로 변경)

TImage와 TImageList 사용법... 그리고 ComboBox 참고법 정도를 익히는데 괜찮을듯 싶다..

이런 간단간단한 예제가 쌓이면 큰거 될 수 있다...

좌우지간 소스를 아래에 첨부한다.

 RegistCal.zip

C++ Builder 화이팅!!
SDI 형태
1.     MainFrame 얻기
-          CMainFrame *pFrame = (CmainFrame *) AfxGetMainWnd();

2.     App 포인터 얻기
-          CTestApp *pApp = (CtestApp *) AfxGetApp();

3.     Document 포인터 얻기
-          CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
            CTestDoc *pDoc = (CTestDoc *)pFrame->GetActiveDocument();
-          CTestDoc *pDoc = ((CMainFrame *)AfxGetMainWnd())->GetActiveDocument();

4.     View 포인터 얻기

-          CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
           CTestView *pView = (CTestView *)pFrame->GetActiveView();
-          CTestView *pView = ((CMainFrame *)AfxGetMainWnd())->GetActiveView();

MDI 형태
1.     ChildFrame 포인터 얻기
-          CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
           CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
-          CChildFrame *pChild = ((CMainFrame *)AfxGetMainWnd())->GetActiveFrame();

2.     Document 포인터 얻기
-           CMainFrame *pFrame = (CMainFrame)AfxGetMainWnd();
            CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
            CMdiTestDoc *pDoc = (CMdiTestDoc *)pChild->GetActiveDocument();
-          CMdiTestDoc *pDoc = (((CMainFrame *)AfxGetMainWnd())->GetActiveFrame())->GetActiveDocument();

3.     View 포인터 얻기
-          CCainFrame *pFrame = (CMainFrame)AfxGetMainWnd();
            CChildFrame *pChild = (CChildFrame *)pFrame->GetActiveFrame();
            CMdiTestView *pView = (CMdiTestDoc *)pChild->GetActiveView();
-          CMdiTestView *pView = (((CMainFrame *)AfxGetMainWnd())->GetActiveFrame())->GetActiveView();

--------SDI----------------

1.애플리케이션 클래스의 포인터를 얻을 때

CWinApp* AfxGetApp()

함수를 사용합니다.

2.메인 프레임 클래스의 포인터를 얻을 때

CWnd* AfxGetMainWnd()

함수를 사용합니다.

 이들 두 함수는 MFC의 전역함수로써 프로그램을 작성하는 도중 어디에서나 사용할 수 있습니다. MFC에서는 Afx~로 시작하는 함수들은 모두 전역함수를 의미합니다.

 물론 타입 캐스팅을 해야 하구요. 사용법은 다음과 같습니다.

    CTestApp *pApp = (CTestApp *)AfxGetApp();
    CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pApp와 pFr은 각각 애플리케이션 클래스와 메인 프레임 클래스의 인스턴스 포인터를 가리키게 됩니다.

 이 외에 뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조할 때는

    CFrameWnd* GetParentFrame() const

함수를 사용할 수 있습니다. 물론 뷰 클래스뿐만이 아니라 일반적인 윈도우를 둘러싸는 틀로써 프레임 윈도우가 사용될 수 있기 때문에 GetParentFrame() 함수는 CWnd() 클래스의 멤버함수로 되어있습니다.

 이 함수와 AfxGetMainWnd() 함수는 SDI에서는 같은 기능을 하지만, MDI에서는 메인 프레임 윈도우와 뷰를 둘러싸고 있는 프레임 윈도우가 다르기 때문에 그 각각을 구하는 역할을 합니다.

3.도큐먼트 클래스의 포인터를 얻을 때는 몇 가지 경우가 있습니다.

    (a) 뷰 클래스에서 도큐먼트 클래스에 접근할 때.

      이때는 말할 필요도 없이 GetDocument() 함수를 쓰면 됩니다. 뷰에 이미 정의되어 있는 함수죠. 하지만 사용자가 임의로 뷰를 추가한 경우에는 이 GetDocument() 함수가 포함되어 있지 않습니다. 이럴 경우 기존에 있는 뷰에서 GetDocument() 함수 부분을 복사해다가 넣으면 됩니다. 이 부분은 Debug 모드와 Release 모드 두 가지의 함수가 있으므로 모두 복사해 넣아야 합니다.

    (b) 임의의 클래스에서 도큐먼트 클래스에 접근할 때.

       CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();
       CTestDoc *pDoc = (CTestDoc *)pFr->GetActiveDocument();

    위와 같이 두 줄에 걸쳐 써도 되고 다음처럼 한 줄로 줄여써도 됩니다.

    CTestDoc *pDoc = (CTestDoc *) ((CMainFrame *)AfxGetMainWnd())->GetActiveDocument();

4. 뷰 클래스의 포인터를 얻을 경우.

    (a) 임의의 클래스에서 뷰 클래스에 접근할 때

     뷰 클래스의 포인터를 얻어야 하는 경우는 대부분 다이얼로그에서 뷰에 접근하거나, 스플릿을 사용한 경우 다른 뷰 클래스에서 접근하는 경우가 대부분일 겁니다. 뭐 어떻든 상관없이 다음과 같이 하면 어디서든 뷰에 접근할 수 있습니다.

    CTestView *pView = (CTestView *) ((CMainWnd *)AfxGetMainWnd())->GetActiveView();

     물론 위의 3번의 경우처럼 두 줄로 나누어 써도 상관이 없습니다.

    (b) 도큐먼트 클래스에서 뷰 클래스에 접근을 할 때

    도 큐먼트 클래스에서 뷰 클래스의 인스턴스 포인터를 얻으려면 GetFirstViewPosition() 함수와 GetNextView() 함수를 조합하여 사용해야 합니다. 이렇게 복잡해지는 이유는 도큐먼트 하나에 여러개의 뷰가 연결될 수 있기 때문입니다.

    도큐먼트에는 이에 연결된 뷰가 연결 리스트 형태로 관리되고 있기 때문에 몇 번째 뷰를 얻을 것인지 선택하고 나서 위의 함수를 조합하여 사용하면 됩니다.

    다음은 도큐먼트와 연결된 모든 뷰 클래스를 차례로 얻어 뷰 클래스의 멤버함수인 UpdateWindow() 함수를 호출하는 예제입니다.

      POSITION pos = GetFirstViewPosition();

      while(pos != NULL) {
           CView *pView = GetNextView(pos);
           pView->UpdateWindow();
      }

    물 론 이와 같은 효과를 내기 위해서 도큐먼트 클래스의 멤버함수인 UpdateAllViews(NULL) 함수를 호출해도 됩니다. 여기서 쓰이는 인자인 NULL 은 모든 뷰를 업데이트하는 것이고, NULL 대신, 신호를 보내는 뷰의 포인터를 넣어주면 신호를 보내는 뷰는 빼고 나머지 뷰만 업데이트를 합니다.

      도큐먼트에 뷰가 오직 하나만 연결되어 있는 경우에는 다음과 같이 간단하게 뷰 클래스의 인슽턴스 포인터를 얻어낼 수도 있습니다. m_viewList 는 CDocument 클래스의 멤버변수로서, 뷰를 관리하는 연결 리스트입니다. 이것을 이용하여 GetHead() 함수를 호출하면 리스트에 들어있는 첫 번째 뷰가 얻어집니다.

      void CTestDoc::OnRepaintViews()
      {
           CView *pView = m_viewList.GetHead();
           pView->UpdateWindows();
      }

 

    (c) 스플리트 윈도우에서의 각 뷰 클래스에 접근할 때

      동적 스플리트 윈도우라면 모든 페인에서 같은 뷰를 사용하므로 별 문제가 되지 않는데, 정적 스플리트 윈도우라면 각 페인마다 다른 뷰를 사용할 수 있으므로 각 페인별로 뷰의 인스턴스 포인터를 얻는 것이 문제가 되는 경우가 생길 수 있습니다.

     이렇때는 메인 프레임 클래스에서 정의한 CSplitterWnd 클래스의 변수인 m_wndSplitter 의 멤버함수 GetPane()을 사용하면 각 페인의 뷰에 접근할 수 있습니다.

      우선 메인 프레임에서 정의된 m_wndSplitter 변수를 public: 속성으로 바꾸고(외부에서 접근해야 하므로) 메인 클래스의 인스턴스 포인터를 얻은 다음, 다시 여기서 m_wndSplitter 변수에 접근하여 이 멤버변수의 멤버함수 GetPane()을 이용하면 됩니다. 다음은 GetPane()의 함수 원형입니다. 리턴값은 대부분의 경우 CView에서 파생된 클래스의 인스턴스 포인터가 됩니다.

    CWnd* GetPane( int row, int col );

    임의의 클래스에서 다음과 같이 사용하면 페인에 연결된 뷰의 포인터를 얻을 수 있습니다.

        CTestView *pView = (CTestView *)((CMainFrame *)AfxGetMainWnd())->m_wndSplitter.GetPane(0,1);

-------- MDI ---------------

1.애플리케이션 클래스의 포인터를 얻을 때

    CWinApp* AfxGetApp()

함수를 사용합니다. 이것은 SDI에서와 동일합니다. App 클래스는 MDI든 SDI든 프로그램 내에서는 하나뿐이니까요. 다음처럼 사용하면 pApp는 애플리케이션 클래스의 인스턴스 포인터를 가리키게 됩니다.

    CTestApp *pApp = (CTestApp *)AfxGetApp();

2. CMDIFrameWnd의 파생클래스인 메인 프레임 클래스의 포인터를 얻을 때

    CWnd* AfxGetMainWnd()

함수를 사용합니다. 사용법은 SDI에서와 동일합니다.

    CMainFrame *pFr = (CMainFrame *)AfxGetMainWnd();

이렇게 써준 다음에는 pFr은 메인 프레임 클래스의 인스턴스 포인터를 가리키게 됩니다.

3. CMDIChildWnd의 파생클래스인 자식 프레임 윈도우의 포인터를 얻을 때

    (a) 활성화된 자식 프레임 윈도우의 포인터를 얻을 때

      virtual CFrameWnd* GetActiveFrame( );

    함수를 사용합니다. MSDN에 실려있는 이 함수의 리턴값에 대한 설명을 보면, 애플리케이션이 SDI이거나 MDI 프레임 윈도우에 활성화된 도큐먼트가 없을 때, 리턴값은 묵시적인 this 포인터가 된다고 하네요.

    사용법은 다음과 같습니다.

    CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();

4. 뷰 / 도큐먼트 클래스의 포인터를 얻을 때

 SDI 에서 구한 것과 마찬가지 방법을 사용한다. SDI에서는 메인 프레임의 포인터를 얻어 GetActiveView() 또는 GetActiveDocument() 함수를 사용했지만, MDI에서는 차일드 프레임의 포인터를 얻어 거기서 GetActiveView() / GetActiveDocument() 함수를 사용하면 된다. 사용법은 거의 동일하다.

 MDI에서도 SDI와 마찬가지로 도큐먼트나 뷰가 여러 개가 연결될 수 있으므로 그점만 주의해 주면 된다.

 사용법은 다음과 같다.

    CMDIChildWnd* pChild = (CMDIChildWnd *)AfxGetMainWnd()->GetActiveFrame();

    // 뷰 클래스의 포인터 얻기
    CTestView *pView = (CTestView *)pChild->GetActiveView();  

    // 도큐먼트 클래스의 포인터 얻기
    CTestDoc *pDoc = (CTestDoc *)pChild->GetActiveDocument();


'1.소프트웨어 이야기 > 01.MFC(Visual Studio)' 카테고리의 다른 글

[펌] DialogBar 구현  (0) 2008.08.07
클래스간 포인터 얻기  (0) 2007.12.06
MFC Socket 사용시 유의점  (0) 2007.12.06
MFC Socket 사용시 유의점

socket.IOCtl( FIONREAD, &avail ); // avail에 읽을 수 있는 양이 들어간다.
socket.Receive( pBuf, avail ) // 하지만 avail 만큼 다 못 읽을 경우가 있다.

따라서

MFC CAsyncSocket 사용시 유의사항

1. 소켓 API를 이용하여 특정 크기의 데이터를 보내면 나눠지거나 합쳐지는 경우가 있는가?

2. 송신자가 100바이트를 전송하여 수신자의 OnReceive함수가 호출 되었다.
그러나 그 함수 에서 50 바이트만 Receive했을 경우 다시 OnReceive함수가 호출되는가?

3. 위와 같은 경우에서 50 바이트가 아니라 아예 Receive를 하지 않은 경우는 어떻게 되는가?

4. 특정 데이터 크기 단위로 받아서 처리하는 로직을 구성하려 한다.
송신자는 데이터 단위당 그 크기를 4바이트 정수로 데이터 앞에 붙여서 보낸다.
다음과 같이 구성하여 완전한 길이의 데이터가 들어왔을때만 메세지를 보내도록 하였다.
이것이 잘 동작하는가? 문제가 있다면 무엇인가?
5. 소켓버퍼에 데이터가 있더라도 인위적으로 OnReceive가 호출 되지 않도록 할 수 있는가?

6. 데이터 크기를 명시하여 잘 동작하는 패킷 전송 프레임웍을 구현해보라.

+ Recent posts