[MFC] 도형 그리기

[MFC] 도형 그리기

[MFC] 도형 그리기

사용자로부터 X, Y, Radius 값을 입력받은 뒤 원을 그린 후 무게중심을 표시하라.

환경

  1. Windows 11
    • Visual studio community 2022(64bit)
      • MSVC v143 및 MFC
visual studio installer
visual studio installer

프로젝트 구성

  • MFC 앱
    • 애플리케이션 종류 : 대화 상자 기반
    • 이 외 default
MFC Project 생성
MFC Project 생성

구현

  • 기본으로 만들어지는 .cpp 파일과 .h 파일에 “MyImage” 클래스를 추가하여 구현

class MyImage 
{ 
private: 
    int nWidth; 
    int nHeight; 
    int nBpp; 

    CWnd* wnd; 
    CClientDC* dc;

    CImage img; 
    RGBQUAD rgb[256]; 

    int nPitch; 
    unsigned char* fm; 

    void init(CWnd* wnd); 
public: 
    MyImage(CWnd *wnd); 
    MyImage(CWnd *wnd, int nWidth, int nHeight, int nBpp); 
    ~MyImage(); 

    int getWidth(); 
    int getHeight(); 
    
    void drawCircle(CWnd *wnd, int x, int y, int nRadius); 
};

MyImage::MyImage(CWnd* wnd) 
{ 
    this->nWidth = 770; 
    this->nHeight = 400; 
    /* bit per pixel*/ 
    this->nBpp = 8; 
    
    init(wnd); 
    
    CClientDC dc(wnd); 
    
    return; 
} 

MyImage::MyImage(CWnd* wnd, int nWidth, int nHeight, int nBpp) 
{ 
    this->nWidth = nWidth; 
    this->nHeight = nHeight; 
    this->nBpp = nBpp; 
    
    init(wnd); 
    
    return; 
} 

MyImage::~MyImage() { return; } 

void MyImage::init(CWnd* wnd) 
{ 
    int i, j; 
    
    this->wnd = wnd; 
    this->img.Create(this->nWidth, this->nHeight, this->nBpp); 
    
    if (this->nBpp == 8) 
    { 
        for (i = 0; i < 256; i++) 
        { 
            this->rgb[i].rgbRed = this->rgb[i].rgbBlue = this->rgb[i].rgbGreen = i; 
            this->img.SetColorTable(0, 256, rgb); 
        } 
    } 
    
    this->nPitch = this->img.GetPitch(); 
    this->fm = (unsigned char*)this->img.GetBits(); 
    
    memset(this->fm - (sizeof(unsigned char) * this->nWidth * this->nHeight), 0xff, sizeof(unsigned char) * this->nWidth * this->nHeight); 
    
    dc = new CClientDC(wnd); 
    img.Draw(*dc, 0, 0);
    
    return; 
} 

void CDrawCircleDlg::OnBnClickedbtndrawimage() 
{ 
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. 
    myImg = new MyImage(this); 
} 

void MyImage::drawCircle(CWnd *wnd, int x, int y, int nRadius) 
{ 
    int i, j; 
    memset(this->fm - (sizeof(unsigned char) * this->nWidth * this->nHeight), 0xff, sizeof(unsigned char) * this->nWidth * this->nHeight);
    
    for (i = 0; i < this->nHeight; i++) 
    { 
        for (j = 0; j < this->nWidth; j++) 
        { 
            if (pow(i-y, 2) + pow(j-x, 2) < pow(nRadius, 2)) 
            { 
                this->fm[i*this->nPitch+j] = 0; 
            } 
        } 
    } 
    
    for (i = 0; i < this->nHeight; i++) 
    { 
        for (j = 0; j < this->nWidth; j++) 
        { 
            if (pow(i - y, 2) + pow(j - x, 2) < pow(10, 2)) 
            { 
                this->fm[i * this->nPitch + j] = 123; 
            } 
        } 
    } 
    
    for (i = x - 9; i < x + 10; i++) 
    { 
        fm[y * this->nPitch + i] = 255; 
    } 
    for (i = y-10; i < y+10; i++) 
    { 
        fm[i * this->nPitch + x] = 255; 
    } 
    
    this->img.Draw(*dc, 0, 0); 
    
    return; 
} 

void CDrawCircleDlg::OnBnClickedbtndrawicircle() 
{ // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    if (myImg != nullptr) 
    { 
        CString x, y, radius; 
        editXCoordinate.GetWindowTextW(x); 
        editYCoordinate.GetWindowTextW(y); 
        editRadius.GetWindowTextW(radius); 
        myImg->drawCircle(this, _ttoi(x), _ttoi(y), _ttoi(radius)); 
    } 
} 

int MyImage::getWidth() 
{ 
    return this->nWidth; 
} 

int MyImage::getHeight() 
{ 
    return this->nHeight; 
} 

void CDrawCircleDlg::OnEnChangeedtxcoordinate() 
{   
    // TODO: RICHEDIT 컨트롤인 경우, 이 컨트롤은 
    // CDialogEx::OnInitDialog() 함수를 재지정 
    //하고 마스크에 OR 연산하여 설정된 ENM_CHANGE 플래그를 지정하여 CRichEditCtrl().SetEventMask()를 호출하지 않으면 
    // 이 알림 메시지를 보내지 않습니다. 

    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. 
    CString x, y; 
    editXCoordinate.GetWindowTextW(x); 
    editYCoordinate.GetWindowTextW(y); 
    
    if (myImg != nullptr && myImg->getWidth() < _ttoi(x))
    { 
        MessageBox(L"이미지 폭을 벗어납니다.", L"Error"); 
    } 
} 

void CDrawCircleDlg::OnEnChangeedtycoordinate() 
{ 
    // TODO: RICHEDIT 컨트롤인 경우, 이 컨트롤은 
    // CDialogEx::OnInitDialog() 함수를 재지정 //하고 마스크에 OR 연산하여 설정된 ENM_CHANGE 플래그를 지정하여 CRichEditCtrl().SetEventMask()를 호출하지 않으면 
    // 이 알림 메시지를 보내지 않습니다. 
    
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다. 
    CString x, y; 
    editXCoordinate.GetWindowTextW(x); 
    editYCoordinate.GetWindowTextW(y); 
    if (myImg != nullptr && myImg->getHeight() < _ttoi(y)) 
    { 
        MessageBox(L"이미지 폭을 벗어납니다.", L"Error"); 
    } 
}

 

화면

결과
결과

파일

실행파일 : DrawCircle(64bit)

소스 : DrawCircle(source)

문제점

  1. memset() 으로 메모리를 직접 0xff 로 초기화함
    • 화면에서 볼 수 있듯이 완벽하게 0xff 로 초기화되지 않음(bitmap을 메모리에서 어떻게 다루는지 상세히 공부해볼 필요 있음)
, ,

%d 블로거가 이것을 좋아합니다: