GSI

사용자 삽입 이미지

CStatic를 사용한 Outlook 스타일의 컨트롤
해당 아이템을 누르면 뒤에 있는 아이템은 아래로 내려간다.
아이템헤더의 구조체를 Link 구조의 형태로 구성해서 처리 하였다.

더 추가되어야할 것은 에니메이션 처리 되는 형태와
아이템이 펼쳐 지면 해당 아이템의 내용이 표시되어야 한다.
이 부분은 ListCtrl로 처리 하면 될듯 하다.

소스코드 :

Posted by gsi
:

사용자 삽입 이미지

해당 이미지의 특정 칼라의 외곽픽셀을 선별해서 최대, 최소 사각형을 구하는 프로그램을
구성중에 있습니다.
아무래도 이것을 사용할 수 있는 용도가 어떤게 있을지는 모르지만.

개선해야될 부분도 많으며, 가운데가 비어 있는 이미지의 경우 오류가 조금 나기도 한다.

앞으로 테스트로 몇가지 더 해볼만한 프로그램이 될듯..

소스코드 :



혹 필요하신분은 받아 가세요 ^^..
Posted by gsi
:

ListCtrl의 LPARAM의 포인터 변수 지우는 방법!!

가끔 생각해 보면 참 바보 같다는 생각이 든다.
기존의 작업 스탈을 보면 ListCtrl의 하나하나의 열에 해당 포인터 변수를 추가해서
사용하게 되는 경우가 많은데,
이때 포인터 변수이기 때문에 메모리를 소거해야 하는 부담감에 휩싸이게 된다.
하지만 난 이제까지 몰랐던것이다.. -.-;

ListCtrl의 흐름 자체를 말이다.

삭제를 할때 나는 해당 아이템을 DeleteItem(i); 이런식으로 하기 전에 사용자 데이터를
지워주어야 하는줄 알았다.
하지만 이 작업은 중간 중간 수정을 하거나 모두 지우거나 추가 하면서
몇가지 부수적인 작업패턴을 부적절하게 발생 시키게 된다.

하지만 이것은 아래의 함수에서 DeleteItem(), DeleteAllItem()을 할때 매번 호출 되는
오버라이드 함수가 있었다는 사실을 알게 되었다.

즉,
ON_NOTIFY(LVN_DELETEITEM, IDC_LIST_IMAGELIST, OnLvnDeleteitemListImagelist)
이 함수를 오버라이딩 해서 사용하게 되면 해당 아이템이 지워질때
이 함수가 호출 되게 된다. 다시 말해서 이 함수 안에서 해당 하는 아이템만
지워 주면 다른건 신경 쓰지 않아도 되는 것이다.


그렇다면 모두 지우는 과정에서는 어떻게 되는가 하고 모르는 분들이라면 질문을 할텐데요.
위의 함수가 그 개수만큼 호출 됩니다.

그래서 위의 함수에서 해당 데이터를 지워 주기만 하면 된다는 것이죠.
아래 처름요.

void CDlgProgrammingPage::OnLvnDeleteitemListImagelist(NMHDR *pNMHDR, LRESULT *pResult)
{
 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
 
 // 메모리 삭제하기
 CString* pStr = (CString*)m_ImageList.GetItemData(pNMLV->iItem);  //<-- 이 부분은 작업자가 포함시킨 포인터 변수(가정)
 SAFE_DELETE(pStr);

 *pResult = 0;
}

Posted by gsi
:

가끔 테스트로 이름을 짰다가 다른 이름으로 변경하고 싶을때가 있는데요.
다 찾아서 하는것도 좋지만.
자동으로 바꿔 주는 프로그램이 있습니다.

VS 프로젝트 까지.. ^^

VSProjectRenamer :
Posted by gsi
:

원격지에 있는 파일의 사이즈 체크 하는 방법

DWORD GetUrlFileLength (CString url)
{
 DWORD filesize;

 TCHAR   szCause[255];
 CString CauseOfError;
 TRY
 {
  CInternetSession session;
  CHttpFile *remotefile= (CHttpFile*)session.OpenURL(url,1,INTERNET_FLAG_TRANSFER_BINARY);
  TCHAR szContentLength[32];
  DWORD dwInfoSize = 32;
  DWORD dwFileSize = 0;
  BOOL bGotFileSize = FALSE;
  if (remotefile->QueryInfo ( HTTP_QUERY_CONTENT_LENGTH, szContentLength, &dwInfoSize , NULL))
  {
   bGotFileSize = TRUE;
   dwFileSize = (DWORD) _ttol(szContentLength);
   filesize = dwFileSize;// Return 값에 할당.
  }
  else
  { // 에러나 나서 파일이 없을경우에
   filesize = -1 ;
  }
  remotefile->Close ();
  session.Close ();
  delete remotefile;
  delete session;
 }

 CATCH_ALL(error)
 {
  AfxMessageBox ("서버로부터 파일 크기를 얻어오는 과정에서 에러발생");
  error->GetErrorMessage(szCause,254,NULL);
  CauseOfError.Format("%s",szCause);
  AfxMessageBox (CauseOfError);
 }
 END_CATCH_ALL;

 return filesize;
}

원격지에 있는 파일 다운로드 받기

void DownloadUrlFileBuffer (CString url)
{
 DWORD dwServiceType = AFX_INET_SERVICE_HTTP;
 CString szServer, szObject, szInfo;

 INTERNET_PORT nPort;
 INTERNET_PROXY_INFO m_proxyinfo;

 CInternetSession m_SessionDownload;
 CHttpConnection* m_pConnection = NULL;
 CHttpFile* m_pHttpFile = NULL;
 CFile FileWrite;

 DWORD d_BytesRead=0;
 DWORD d_FileSize=0;

 char szHTTPBuffer[199926];

 ZeroMemory(szHTTPBuffer, sizeof(szHTTPBuffer));

 //start Download Routine
 ::AfxParseURL(url.GetBuffer(url.GetLength()), dwServiceType, szServer, szObject, nPort);

 try
 {
  m_pConnection = m_SessionDownload.GetHttpConnection(szServer,INTERNET_FLAG_KEEP_CONNECTION, nPort,NULL, NULL);
  m_pHttpFile= m_pConnection->OpenRequest("GET",szObject,NULL,0, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION);
 }
 catch(CInternetException* m_pException)
 {
  //exception found
  //lots of clean up code
  return;
 }

 if(m_pHttpFile)
 {
  if(!FileWrite.Open("d:\\aaa.gif", CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone ))
  {
   //exception found
   //lots of clean up code
   return;
  }

  try
  {
   m_pHttpFile->SendRequest(NULL);
  }
  catch(CInternetException* m_pException)
  {
   //exception found
   //lots of clean up code
   return;
  }

  m_pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, d_FileSize);
  m_pHttpFile->QueryInfo(HTTP_QUERY_MAX, szInfo);

  while(d_BytesRead = m_pHttpFile->Read((void*)szHTTPBuffer,199926))
  {
   FileWrite.Write((void *)szHTTPBuffer,d_BytesRead);
   memset(szHTTPBuffer, 0, sizeof(szHTTPBuffer));
  }

  szServer.Empty();
  szObject.Empty();

  m_SessionDownload.Close();
  m_pConnection->Close();
  m_pHttpFile->Close();

  delete m_SessionDownload;
  delete m_pConnection;
  delete m_pHttpFile;

  FileWrite.Close();
 }
}

위에 있는 FileWrite 부분이 그 부분이며, 이 부분을 해당 프로젝트에 맞도록 고쳐야 할 것이다.
Posted by gsi
:

사용자 삽입 이미지

FormView로 구성된 세부 컨트롤 처리

Color1 + Pick... + CheckButton 은 한줄씩 생성 됩니다.
Add, Delete 로 추가하고 삭제할 수 있습니다.

스크롤로 아래 위로 움직일 수 있습니다.

Add를 하게 되면 하단의 버튼이 아래로 내려 간다.

 int pos = GetScrollPos(SB_VERT);
 GetDlgItem(IDC_EFFECTATTRIB8_CHILD_ADD)->MoveWindow(20, m_NewHeightPos + 10 - pos, 100, 30);
 GetDlgItem(IDC_EFFECTATTRIB8_CHILD_DELETE)->MoveWindow(20, m_NewHeightPos + 42 - pos, 100, 30);
 CSize scrollSize;
 scrollSize.cx = 200;
 scrollSize.cy = m_NewHeightPos + 80;
 SetScrollSizes(MM_TEXT, scrollSize);

위의 코드에서 보듯이 컨트롤을 동적으로 생성할 때
스크롤 성분에 의해서 원하는 위치에 생성되지 않습니다.
이 문제를 해결하기 위해서 GetScrollPos()를 사용해서 스크롤 값을 얻어 오고
그 값을 보정해서 생성하면 되네요..

관련코드 :
Posted by gsi
:

웹의 경로에 위치한 이미지를 가져오는 모듈입니다.
원래 이미지 사이즈를 구하기 위해서 사용했던건데요.
파일 다운로드 쪽으로 활용해도 가능성이 있을듯 하네요.

try
{
    byte[] data = new System.Net.WebClient().DownloadData(url);
    System.IO.MemoryStream ms = new System.IO.MemoryStream(data);
    Image img = Image.FromStream(ms);

    Size size = new Size(img.Width, img.Height);
    return size;
}
catch(Exception ex)
{
    return new Size(-1, -1);
}

msdn 주소 : http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=637975&SiteId=1
키워드 : Image Url

Posted by gsi
:

스마트 포인터를 사용하고,
템플릿을 연동해서 여러가지 단위전략을 세울수 있다.

// CTest //
class CTest
{
public:
 CTest() {}
 ~CTest() }

public:
 int value;
};
typedef SmartPtr<CTest> CDeleteTestPtr;
typedef vector< CDeleteTestPtr > vObject;

// OpNewCreator //
template <class T>
struct OpNewCreator
{
 static T* Crate()
 {
  return new T;
 }
};

// CTestArray //
template < template <class> class CreatePolicy>
class CTestArray
 : public CreatePolicy< CTest >
 , public vObject
{
public:
 CTestArray()
 {
  vObject::clear();
 }
 ~CTestArray() { }

 // Add라는 함수를 하나 제작해 봤다.
 // OpNewCreator를 사용해서 간접적으로 메모리를 생성한다.
 void Add(int idx)
 {
  CDeleteTestPtr ptr = OpNewCreator<CTest>().Crate();
  ptr->value = idx;
  vObject::push_back( ptr );
 }
};
typedef SmartPtr< CTestArray<OpNewCreator> > CTestArrayPtr;

///// 사용법
CTestArrayPtr ar;
for(int i = 0; i < 10; i++)
{
   ar->Add(i);
}

Posted by gsi
:

Smart Ptr

#ifndef SMARTPTR_H
#define SMARTPTR_H

template <class T> class SmartPtr;

// IRefCount 참조 횟수 관리를 위한 인터페이스
// 클래스들은 이것을 직접 구현해도 되고, 아니면
// 내부적으로 IRefCount를 구현하고 있는 SmartPtr을 사용해도 된다.

template <class T> class IRefCount {
    friend class SmartPtr<T>;
protected:
    virtual void AddRef() = 0;
    virtual void Release() = 0;
    virtual T* GetPtr() const = 0;
};

// IRefCountImpl
// IRefCount의 표준적인 구현
// 이것을 상속하기만 하면 참조 횟수 관리 기능이 생긴다.
// class CMyObject : public IrefCountImpl<CMyObjct> { ... };
// 주의: 개별 클래스가 IRefCount를 꼭 구현할 필요는 없지만,
// 직접 구현함으로써 메모리 단편화를 줄일 수도 있다.

template <class T> class IRefCountImpl
: public IRefCount<T>
{
private:
    int m_Count;

protected:
    virtual void AddRef() { m_Count++; }
    virtual void Release();
    {
        assert( m_Count>=0);
        m_Count--;
        if( m_Count<=0 )
        {
            Destroy();
        }
    }
    virtual T* GetPtr() const { return ( (T*)this ); }
    virtual void Destroy() { if(GetPtr()!=NULL) delete GetPtr(); }

    IRefCountImpl() { m_Count = 0; }
};

// SmartPtr

template <class T> class SmartPtr
{
private:
    IRefCount<T> *m_RefCount;
// RefCounter
// IRefCount를 직접 구현하지 않는 클래스를 위한 내부구현.
// SmartPtr은 이 내부 구현과 클래스 T의 IRefCount 구현중
// 적절한 것ㅇ르 자동적으로 선택한다.

    class RefCounter : public IRefCountImpl<T> {
    private:
         T *m_Ptr;
    protected:
         virtual T* GetPtr() const { return m_Ptr; }
         virtual void Destroy() { delete this; }

    public:
       RefCounter( T* ptr ) { m_Ptr = ptr; }
       virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
    };
//  T가 IRefCount를 구현하지 않았다면 이 메서드가 호출된다.
    void Assign( void *ptr )
    {
        if( ptr==NULL )
            Assign( (IRefCount<T> *)NULL );
        else
        {
            Assign( new RefCounter( static_cast<T*>(ptr) ) );
        }
    }

     // T가 IRefCount를 구현하고 있다면 Assign(void *ptr) 대신
// 이 메서드가 호출된다.
// 이를 통해서 메모리 사용이 좀더 최적화된다.
    void Assign( IRefCount<T> *refcount )
    {
        if( refcount != NULL )
             refcount->AddRef();
        IRefCount<T> *oldref = m_RefCount;
        m_RefCount = refcount;
        if( oldref!=NULL )
             oldref->Release();
    }
public:

    SmartPtr() { m_RefCount = NULL; }
    SmartPtr( T *ptr ) { m_RefCount = NULL; Assign(ptr); }
    SmartPtr(const SmartPtr &sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
    virtual ~SmartPtr() { Assign( (IRefCount<T> *)NULL); }

    T* GetPtr() const { return (m_RefCount = NULL ) ? NULL : m_RefCount->GetPtr(); }

    // 배정 연산자들
    SmartPtr& operator = (const SmartPtr &sp) { Assign(sp.m_RefCount); return *this; }
    SmartPtr& operator = (T* ptr) { Assign(ptr); return *this; }

    // T접근 및 const 변환
    T* operator -> () { assert(GetPtr() != NULL); return GetPtr(); }
    operator T* () const { return GetPtr(); }

    // 기타 편의성 연산자들
    bool operator ! () { return GetPtr() == NULL; }
    bool operator == (const SmartPtr &sp) { return GetPtr() == sp.GetPtr(); }
    bool operator != (const SmartPtr &sp) { return GetPtr() != sp.GetPtr(); }
};

#endif

다음은 템플릿 사용 예
SmartPtr.cpp

#include "stdafx.h"
#include "assert.h"
#include "smartptr.h"

class CMyObject
{
   char *name;
public:
   CMyObject(char *aname) { name = aname; printf( "create %s\n", name ); }
   virtual ~CMyObject() { printf("delete %s\n", name ); }
   void print() { printf("print %s\n",name ); }
};

SmartPtr<CMyObject> f1( char *name )
{
    return SmartPtr<CMyObject>(new CMyObject(name));
}

void f2( CMyObject *o )
{
    printf( " (print from a function) ");
    o->print();
}

int main( void )
{
    SmartPtr<CMyObject> ptr1(new CMyObject("1")); // 객체 1을 생성
    SmartPtr<CMyObject> ptr2 = new CMyObject("2"); // 객체 2을 생성

    ptr1 = ptr2; //객체 1을 파괴
    ptr2 = f1("3"); // 반환값으로 쓰이는 경우
    ptr2 = NULL; // 객체 3을 파괴
    f2(ptr1);

    // 잘못된 용례
    //  CMyObject o1;
    // ptr1 = &o1; // o1은 스택에 있으므로 이렇게 하면 안된다.
   
    // CMyObject *o2 = new CMyObject;
    // ptr1 = o2;
    // ptr2 = o2; // CMyObject가 IRefCount를 구현하지 않는 한 이렇게 하면 안된다.
    //     대신 ptr1 = ptr2를 사용할 것, 그것이 항상 안전하다.

    // int에 대해서도 SmartPtr을 사용할수 있다.
    SmartPtr<int> a(new int);
    SmartPtr<int> b(new int);

    *a = 5;
    *b = 6;

    // 명시적으로 파괴하지 않아도 메모리가 새지 않는다.
    return 0;
}

(펌) : http://blog.naver.com/twofree?Redirect=Log&logNo=21484155

Posted by gsi
:

단위 전략 부분의 디자인 패턴 내용을 보고 있다.

template 을 사용해서 다중 상속과 비슷한 구조를 취하기도 하고 메모리 생성 부분을 struct, class 형태로 따로 빼서 관리도 되는거 같다.

예제 1 :

class Ca
{
public:
 Ca() { value = 100; }
 virtual ~Ca() {}

 int value;
protected:
private:
};

template< class T>
class Cb
{
public:
 Cb() {}
 virtual ~Cb() {}

 T b;
protected:
private:
};

template< class T>
class Cc
{
public:
 Cc() {}
 virtual ~Cc() {}

 T c;
protected:
private:
};

template
<
 class T,
 template <class> class CheckingPolicy,
 template <class> class ThreadingModel
>
class SmartPtr
{
public:
 SmartPtr() {}
 ~SmartPtr() {}

public:
 T a;
 CheckingPolicy<T> b;
 ThreadingModel<T> c;
};

typedef SmartPtr<Ca, Cb, Cc> WidgetPtr;

위의 내용에서 보면 typedef를 사용해서 WidgetPtr을 하나 만들고 있다.
여기에 들어가는 내용은 Ca, Cb, Cc 가 있으며,
Cb, CC는 Ca를 포함할 수 있기 때문에 template로 선언되어 있는게 조건인듯 하다.

위와 같이 선언한 후에 아래와 같이 선언해서 사용하게 된다.

TestPtr< OpNewCreator > b;

이렇게 되면 b의 내용을 보면 SmartPtr의 클래스 내부에 b, c가 존재 하는데
이것은 T라는 템플릿 즉, Ca를 가지게 되며, 다른 동작들을 관리할 수 있을거 같다.

예제 2 :

class CTest
{
public:
 CTest() { value = 20; }
 ~CTest() {}

public:
 int value;
};

template <class T>
struct OpNewCreator
{
 static T* Create()
 {
  return new T;
 }
};

template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
{
public:
 TestPtr()
 {
  ptr = CreationPolicy<CTest>().Create();
 }
 ~TestPtr()
 {
 }

public:
 CTest* ptr;
};

OpNewCreator 라는 struct를 사용하면서 new를 처리해 준다.
이 곳에서 몇개의 다른 처리를 해서 넘겨 주는 형태를 취해도 될것 같다.

상속 형태로 해서 아래와 같은 코드로 작성 하면,
template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
...
이렇게 하고 나서

ptr = CreationPolicy<CTest>().Create();
이런 식으로 생성할 수 있다. 이 코드 참 멋진듯 하다. ^^

생성해서 처리 하는 방법은 아래와 같습니다.

 TestPtr< OpNewCreator > b;
 b.ptr->value = 30;
 printf("%d\n", b.ptr->value);
 TestPtr< OpNewCreator > c;
 b.ptr->value = 50;
 printf("%d\n", b.ptr->value);

아뭍턴.. 템플릿을 구현하는 방법이 복잡하긴 하지만,
제대로 사용하면 정말로 많은 기능을 구사할 수 있다.
Posted by gsi
:

객체 지향 설계에서 기존의 것과는 독립된 새로운 것을 추가, 확장시키기 위한 가장 좋은 방법 중 하나가 클래스 상속(InHeritance)을 이용하는 것이다.

객체지향 설게에서 클래스 상속은 크게 두가지 목적을 가지는데,

하나는 상위 클래스가 여러 하위 클래스들의 공통된 데이터를 추출해서 관리하도록 만드는 것이고,
다른 하나는 상위 클래스는 전반적인 자료형을 대표 하면서 외부에 공통된 인터페이스를 제공하고, 하위 클래스들은 각기 다른 구현 내용을 가지도록 만들어 주기 위한 것이다.
Posted by gsi
:

State Pattern

C++ 2008. 1. 22. 09:21 |

State Pattern

사용자 삽입 이미지
< State 패턴예>


GamePlayer 클래스와 GameLevel 및 그 하위 클래스들은 모두 동일한 인터페이스를 가지고 있는데, 이는 GamePlayer 객체에 각기 다른 유형의 공격 요청이 주어졌을 때 이에 대한 처리를 GameLevel 및 그 하위 클래스에게 위임시키기 위한 것이다.
이때 GamePlayer 객체가 공격 요청을 위임시키기 위한 방법으로는 내부적으로 관리하고 있는 GameLevel 포인터 객체를 통해 다형성(Polymorphism)을 적용시키는 것이다.

추가된 상태를 포함해서 객체의 상태 변화 시 기존 소스코드 변경없이 행위 수행 변경이 가능하도록 객체 상태 정보를 클래스 상속 구조로 정의해서 사용하는 방식을 State 패턴이라고 한다.

Posted by gsi
:

Observer Pattern - Simple

C++ 2008. 1. 21. 12:25 |


Observer Pattern을 공부중..

사용자 삽입 이미지

<Observer 패턴예>


데이터와 뷰가 분리 되어 있을때 하나의 데이터를 두개 이상의 뷰에 의존적일 경우에
이 패턴을 사용하면 되는거 같아요.
즉, 데이터를 두개의 뷰에 업데이트가 가능하며, 하나의 뷰에서 데이터가 수정된 후에
다른 뷰에도 업데이트가 가능하게 됩니다.

Posted by gsi
:

#include <iostream>

 

using namespace std;

 

typedef void(*F)(int);

 

class QSpinBox

{

       int data;

      F handler;   // call back 함수 이게 포인트. 값이 변경되면 이 함수를 통해서 콜백을 한다.

public:

       QSPinBox(F f = 0 ) : handler(f) { }

       void SetValue(int n)

       {

             data = n;     // data가 변경되었다

             valueChanged(data);

       }

       void up() { ++data; valueChanged(data);   }

       void Down() { --data; valueChanged(data); }

 

private:

       // Spin은 내부 상태가 바뀔때마다 valueChanged가 호출되는데 여기서 외부로 알려지게 된다 - Signal 이라고 부른다.

       void valueChanged(int n)

       { // 여기서 callback handler를 관리하자

             if(handler != 0)

                    handler(n);

       }

 

 

};

 

int main()

{

       QSpinBox s;

       s.SetValue(100);

       s.Up();

}

 

// SpinBox 의 상태가 변경되면 외부에 알려준다 -> callback


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

Posted by gsi
:



세미나를 다녀 왔습니다.
아주 유익한 시간이였던거 같습니다.
목표도 더 생긴듯 하구요.

솔직히 기존에 코딩 작업을 하면서 구현한 내용들이 알게 모르게 패턴의 한 종류였다는 것도 알게 되었는데요.

코딩을 할때 부분 부분의 디자인 패턴과 프레임웍의 패턴이 잘 융합 되면 정말 좋은 프로그램이 되는거 같습니다.

각각의 패턴의 장단 점을 이해 하고 여러가지의 패턴을 조합해서 사용하는 방법을 터득하고 나면 조금더 업그레이드 된 나를 만날수 있을듯 합니다.

이 참에 세미나 관련 분들이 하는 스터디도 활동을 해봐야 할듯 합니다.

posa 참.. 이거 할려면 gof 부터.. ^^
Posted by gsi
: