GSI

헤더 파일에 추가하세요.

#ifndef _MEMDC_H_
#define _MEMDC_H_

//////////////////////////////////////////////////
// CMemDC - memory DC
//
// Author: Keith Rule
// Email:  keithr@europa.com
// Copyright 1996-1999, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History - 10/3/97 Fixed scrolling bug.
//                   Added print support. - KR
//
//           11/3/99 Fixed most common complaint. Added
//                   background color fill. - KR
//
//           11/3/99 Added support for mapping modes other than
//                   MM_TEXT as suggested by Lee Sang Hun. - KR
//
// This class implements a memory Device Context which allows
// flicker free drawing.

class CMemDC : public CDC {
protected:
 CBitmap  m_bitmap;       // Offscreen bitmap
 CBitmap* m_oldBitmap;    // bitmap originally found in CMemDC
 CDC*     m_pDC;          // Saves CDC passed in constructor
 CRect    m_rect;         // Rectangle of drawing area.
 BOOL     m_bMemDC;       // TRUE if CDC really is a Memory DC.

 void Construct(CDC* pDC)
 {
  ASSERT(pDC != NULL);

  // Some initialization
  m_pDC = pDC;
  m_oldBitmap = NULL;
  m_bMemDC = !pDC->IsPrinting();

  if (m_bMemDC) {
   // Create a Memory DC
   CreateCompatibleDC(pDC);
   pDC->LPtoDP(&m_rect);

   m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
   m_oldBitmap = SelectObject(&m_bitmap);

   SetMapMode(pDC->GetMapMode());
   pDC->DPtoLP(&m_rect);
   SetWindowOrg(m_rect.left, m_rect.top);
  } else {
   // Make a copy of the relevent parts of the current DC for printing
   m_bPrinting = pDC->m_bPrinting;
   m_hDC       = pDC->m_hDC;
   m_hAttribDC = pDC->m_hAttribDC;
  }

  // Fill background
  FillSolidRect(m_rect, pDC->GetBkColor());
 }

 // TRK begin
public:
 CMemDC(CDC* pDC                  ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }
 CMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect           ; Construct(pDC); }
 // TRK end

 virtual ~CMemDC()
 {       
  if (m_bMemDC) {
   // Copy the offscreen bitmap onto the screen.
   m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
    this, m_rect.left, m_rect.top, SRCCOPY);           

   //Swap back the original bitmap.
   SelectObject(m_oldBitmap);       
  } else {
   // All we need to do is replace the DC with an illegal value,
   // this keeps us from accidently deleting the handles associated with
   // the CDC that was passed to the constructor.           
   m_hDC = m_hAttribDC = NULL;
  }   
 }

 // Allow usage as a pointer   
 CMemDC* operator->()
 {
  return this;
 }   

 // Allow usage as a pointer   
 operator CMemDC*()
 {
  return this;
 }
};


#endif

Posted by gsi
:

헤더 선언 및 라이브러리 추가

#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

GDI+ 초기화
 // Initialize GDI+.
 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

GDI+ 객체 삭제
 GdiplusShutdown(gdiplusToken);

Posted by gsi
:

void CGDITestView::OnLButtonDown(UINT nFlags, CPoint point)
{
 SetCapture();

 m_oldPoint = point;

 CView::OnLButtonDown(nFlags, point);
}

void CGDITestView::OnLButtonUp(UINT nFlags, CPoint point)
{
 ReleaseCapture();

 CView::OnLButtonUp(nFlags, point);
}

void CGDITestView::OnMouseMove(UINT nFlags, CPoint point)
{
 if( GetCapture() == this )
 {
  m_realPos += (point - m_oldPoint);
  m_oldPoint = point;

  Invalidate();
 }

 CView::OnMouseMove(nFlags, point);
}

Posted by gsi
:

Google
 
CView를 사용해서 해당 뷰를 만들고 그 위에 CStatic를 생성해서 처리를 하고 있습니다.
CStatic에는 해당 컬러 정보를 사용해서 드로잉이 되며, 마우스로 이동, 크기변경 등의 이벤트가
발생하게 되는데요.

이때 드로잉 되는 순서가 CView가 먼저 드로잉 되고, CStatic가 드로잉 되게 되면서
강한 Flicker 현상(번쩍임)이 발생을 하네요..

이것저것 처리를 해봐도 언뜻 보면 드로잉 순서로 인해서 어쩔 수 없을거 같다는 생각이 드네요.

그래서 조금 우회를 시켜서 CStatic의 드로잉 부분을 CView에 직접 그리기로 했습니다.
CStatic는 보이지는 않지만 자기 기능을 대신 하고 있는거구요.

이렇게 하니 Flicker는 해결이 되었네요 ^^..

원래 이렇게 하는걸까요?.. 아님 다른 방법이 있는 걸까요?
Posted by gsi
:

Google
 

몇달 전부터 Scroll View 페이지를 응용한 개발툴을 몇개 작성을 하게 되었네요.
CView 보다 더 복잡하고, 스크롤이 들어 가면서 포지션 정보를 무시할 수 없더군요.

가장 귀찮게 여겨 지는 것은 Client Area 부분의 마우스가 Down, Up Move 등의 행위를 할때
항상 ScrollToPosition()을 달고 다녀야 한다는게 너무나 맘에 안들었습니다.

마우스의 위치 좌표가 왜 스크롤된 위치가 나오지 않고 현재 보이는 화면 영역의 상대 값이 나오는지.
정말 귀찮습니다.

그래서 CScrollView 클래스에 CView를 삽입 하고,
TotalSize 만큼 CView를 확장해서 처리를 하게 되었습니다.

스크롤 정보는 CSCrollView로 보내야 되고,
화면의 마우스 처리는 CView가 담당하게 처리 하였죠.

근데 .. 이렇게 하니 마우스의 좌표가 스크롤된후의 CView의 위치 정보가 보이게 되더군요.
참으로 편합니다. ^^ 그 위치가 스크롤된 화면 위치니까요.

조금더 나아지는 MFC 방법들이 재미나게 느껴 집니다.

요즘은 애매한 컨트롤은 CWnd, CStatic, CView, CDialog 등과 같은 컨트롤을
여러개 겹치면서 다양한 효과를 구현하고 있네요 ^^..

이번에 테스트뷰로 만들고 있는 화면입니다.
사용자 삽입 이미지

이 프로그램의 기능은 휠을 통한 좌우 스크롤 기능과 화면의 픽킹 처리가 CView에서 담당하는게 특징입니다.

배움에 있어서 여러가지 새로운 ms의 기술들과 플렉스 등을 보면서.
MFC의 기술 또한 같이 성장하는거 같습니다.

아.. 이제 자야 겠네요.. @.@.. 몽롱합니다.
Posted by gsi
:

Flicker Free Drawing In MFC

이런 주제의 CodeProject 의 내용을 볼 수 있다.
테스트해본 코드 주소는 http://www.codeproject.com/KB/GDI/flickerfree.aspx 이며,
해본 결과 Flicker 를 줄일 수 있었다.

기존의 다른 코드를 사용해서 처리 할때
Release 시 드로잉이 되지 않는 문제점이 발생하였다.
솔직히 이거 때문에 디버깅에 시간이 좀 걸렸다.
나머지 모듈을 다 제거 하고나서야 이 클래스를 사용하지 않고 디버깅을 해봐야 겠다.
생각이 들었고, 빼고 보니 제대로 되었다.
즉, CMemDC 클래스가 이상하다는 것을 알았고,
위의 주소에 있는 내용을 복사해서 처리 하니 되었다.

물론 생성자에 CRect 의 내용도 포함될 수 있는 코드도 있는걸로 봐서
ActiveX 와 같은 곳에서도 사용될 수 있을거 같다.

관련 페이지 >

Sample Image

Posted by gsi
:

MFC 의 Doc, View 부분의 구조를 취하다 보면,
여러개의 다이얼로그를 구성하고 그곳에 데이터의 정보가 연동되는 경우가 있는데,
사실상 이때 new, open, save, saveas 를 고려 해서 작업을 해야 할듯 하다.

어느정도 된 후에 이것을 고려 할려다 보면 많은 부분 수정이 가해진다.

그래서 생각이 든건데, new, save, saveas 가 고려되지 않을 경우에
그 함수를 생성해서 데이터 로직 처리 해보는게 더 좋은 구조를 취할 수 있을거 같다.

더 좋은 방법이 있을까?.
혹.. 더 잘아시는분 있으시면.. 연락주세요 ^^
Posted by gsi
:

파일 저장 다이얼로그

 static char BASED_CODE szFilter[] = "Bitmap Files(*.*)|*.bmp|Jpeg Files(*.*)|*.jpg|Colorplay Files(*.*)|*.colorplay|All Files(*.*)|*.*|";
 CFileDialog dlg(TRUE, _T("*.*"), _T("*.*"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);
 dlg.m_ofn.lpstrInitialDir = "";     //기본 경로를 설정한다.

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

Posted by gsi
:

파일 저장 다이얼로그

 static char BASED_CODE szFilter[] = "DMXD Files (*.dmxd)|*.dmxd||";
 CFileDialog dlg(FALSE, _T("*.dmxd"), _T("*.dmxd"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter);

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

Posted by gsi
:

마우스가 해당 View의 영역 밖으로 나갈때 처리 방법.

해당 View의 영역에 커서가 위치할 때랑 커서가 밖으로 나갔을때 다르게 처리 하고 싶을때가 발생한다. 이때는 SetCursor를 이용하면 된다.

즉, 해당 어플리케이션의 MainFrame 에서 SetCursor 부분에서 해당 View의 클래스 포인터의 값을 비교해서 처리 하면 된다.

코드는 아래와 같다.
BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
 if( pWnd == g_PixelMapView )
 {
 }
 else // 해당 포인터가 다를 경우, 즉 다른 윈도우일 경우...
 {
  if( g_PixelMapView )
   g_PixelMapView->OutCursorDCxRop();
 }
 return CFrameWnd::OnSetCursor(pWnd, nHitTest, message);
}

이때 한가지 문제점은 있다. 마우스가 갑자가 해당 메인 프레임 밖으로 이동하게 되면
이 함수는 호출 되지 않는다. 그정도를 감안한다면 이 코드도 괜찮을듯 하다.
Posted by 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
:

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

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
: