[MFC] 도형 그리기

[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 로 초기화함
    1. 화면에서 볼 수 있듯이 완벽하게 0xff 로 초기화되지 않음(bitmap을 메모리에서 어떻게 다루는지 상세히 공부해볼 필요 있음)
%d 블로거가 이것을 좋아합니다: