๋ฐ˜์‘ํ˜•

์ง€๋‚œ ํฌ์ŠคํŒ…์— ์ด์–ด ๊ทธ๋ฆผํŒ ํ”„๋กœ์ ํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„ํ•˜๋Š”์ง€ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

[MFC] ๊ทธ๋ฆผํŒ(mspaint) ๋งŒ๋“ค๊ธฐ ํ”„๋กœ์ ํŠธ #1

Figure Interface ์„ค๊ณ„

๋จผ์ €, ๋„ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. ๋„ํ˜•์—๋Š” ์„ , ์‚ฌ๊ฐํ˜•, ์›ํ˜•, ๋‹ค๊ฐํ˜•, ์‚ผ๊ฐํ˜•, ํ™”์‚ดํ‘œ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ฒƒ๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋กœ IFigure๋ฅผ ์„ ์–ธํ•˜๊ณ , ๋ชจ๋“  ๋„ํ˜•์€ IFigure๋ฅผ ์ƒ์†๋ฐ›๋„๋ก ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ชจ๋“  ๊ตฌํ˜„์€ ์ƒ์†๋ฐ›๋Š” ๊ฐ ๋„ํ˜• ํด๋ž˜์Šค์—์„œ ํ•ฉ๋‹ˆ๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค IFigure์˜ ์„ ์–ธ๋ถ€.

class IFigure
{
public:
	virtual void Draw(Gdiplus::Graphics* g) = 0;
	virtual void Drag(const unsigned int x, const unsigned int y) = 0;
	virtual void SetPoint(const unsigned int index, const int x, const int y) = 0;
	virtual bool IsInBound(const unsigned int x, const unsigned int y) = 0;
	virtual Gdiplus::Rect GetSize() const = 0;

protected:
	Gdiplus::Point m_pointOfBegin;
	Gdiplus::Point m_pointOfEnd;
};

์ธํ„ฐํŽ˜์ด์Šค IFigure๋ฅผ ์ƒ์†๋ฐ›๋Š” Line ํด๋ž˜์Šค์˜ ์„ ์–ธ๋ถ€.

class Line : public IFigure
{
public:
	Line();
	~Line();

public:
	virtual void SetPoint(const unsigned int index, const int x, const int y) override;
	virtual void Draw(Gdiplus::Graphics* g) override;
	virtual bool IsInBound(const unsigned int x, const unsigned int y) override;
	virtual void Drag(const unsigned int x, const unsigned int y) override;
	virtual Gdiplus::Rect GetSize() const override;
};

Line ํด๋ž˜์Šค์˜ Draw() ํ•จ์ˆ˜ ์ •์˜๋ถ€.

void Line::Draw(Gdiplus::Graphics* g)
{
	Pen pen(Color(255, 255, 0, 0), 1);

	g->DrawLine(&pen, m_pointOfBegin.X, m_pointOfBegin.Y, m_pointOfEnd.X, m_pointOfEnd.Y);
}

์ดํ•ด๋˜์‹œ๋‚˜์š”? Rectangle ํด๋ž˜์Šค๋„ ๋ชจ๋‘ ๋™์ผํ•œ๋ฐ Draw() ํ•จ์ˆ˜๋งŒ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

void Rectangle::Draw(Graphics* g)
{
	Pen pen(Color(255, 255, 0, 0), 1);

	Rect newRect = Rect(
		min(m_pointOfBegin.X, m_pointOfEnd.X),
		min(m_pointOfBegin.Y, m_pointOfEnd.Y),
		abs(m_pointOfEnd.X - m_pointOfBegin.X),
		abs(m_pointOfEnd.Y - m_pointOfBegin.Y));

	g->DrawRectangle(&pen, newRect);
}

๊ทธ๋Ÿฐ๋ฐ ๋‚˜์ค‘์— ๋ณด์—ฌ์ค„ ๊ทธ๋ฆผํŒ ํ”„๋กœ์ ํŠธ์˜ ์†Œ์Šค๋ฅผ ๋ณด๋ฉด, IsInBound()๋‚˜ Drag() ์™ธ์— ๋ช‡ ๊ฐ€์ง€ ํ•จ์ˆ˜์˜ ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ๋™์ผํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋™์ผํ•œ ์ฝ”๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ตฐ๋ฐ์— ๋ณด์ธ๋‹ค๋ฉด, ์ด๋Š” ๋‹ค์‹œ ์„ค๊ณ„ํ•˜์—ฌ ๋”์šฑ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. IFigure๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ ์ƒ์œ„ ํด๋ž˜์Šค๋กœ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜, IFigure๋ฅผ ์ƒ์†๋ฐ›๋Š” ํด๋ž˜์Šค์— ๊ตฌํ˜„ํ•˜๊ณ  ์ด๋ฅผ ์ƒ์†๋ฐ›๋Š” ๋„ํ˜• ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ง์ด์ฃ . ํ•˜์ง€๋งŒ ๋ณธ๋ฌธ์˜ ํ”„๋กœ์ ํŠธ๋Š” ์—ฌ์ง€๋ฅผ ๋‚จ๊ฒจ๋‘๊ณ  ์ง„ํ–‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Main Source์—์„œ ์ถ”์ƒ ํด๋ž˜์Šค์˜ ์‚ฌ์šฉ

์•„๋ฌดํŠผ, ์ด๋ ‡๊ฒŒ ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๊ตฌํ˜„ํ•œ ์ด์œ ๋Š” ๋”ฐ๋กœ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”์ธ ์†Œ์Šค์—์„œ ๊ฐ๊ฐ์˜ ๋„ํ˜• ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๊ณ , ์ผ€์ด์Šค ๋ณ„๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ์—„์ฒญ ๋ณต์žกํ•  ํ…๋ฐ์š”. ๊ทธ๋ž˜์„œ ๋ฉ”์ธ ์†Œ์Šค์—์„œ๋Š” ์ถ”์ƒ ํด๋ž˜์Šค๋งŒ ์ •์˜ํ•˜๊ณ  ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ExamPaintDlg.h์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค. ์ถ”์ƒ ํด๋ž˜์Šค์ธ IFigure๋ฅผ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

std::shared_ptr<Figure::IFigure> m_figure;

ExamPaintDlg.cpp์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์„ ํƒ๋œ ๋„ํ˜•์— ๋”ฐ๋ผ ๊ฐ ๋„ํ˜• ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ถ”์ƒ ํด๋ž˜์Šค์˜ Draw() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ์•Œ์•„์„œ ๋„ํ˜•์˜ ๋ชจ์–‘์„ ๊ทธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

void CExamPaintDlg::OnFiguresLine()
{
	m_figure = std::make_shared<Figure::Line>();
}

void CExamPaintDlg::OnFiguresRectangle()
{
	m_figure = std::make_shared<Figure::Rectangle>();
}

void CExamPaintDlg::OnFiguresCropbox()
{
	m_figure = std::make_shared<Figure::CropRectangle>();
}

void CExamPaintDlg::OnDrawImage()
{
	if (m_figure != nullptr)
		m_figure->Draw(&memG);
}

๊ทธ๋Ÿฐ๋ฐ CropRectangle ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ์กฐ๊ธˆ ํŠน๋ณ„ํ•œ ๋™์ž‘์„ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ชจ๋“  ํ–‰๋™์„ IFigure์— ์ •์˜ํ–ˆ๋Š”๋ฐ, CropRectangle์€ ์ž˜๋ฆฐ ์ด๋ฏธ์ง€์˜ ์˜์—ญ์„ ์ง€์ •ํ•œ๋‹ค๋“ ๊ฐ€ ์ž˜๋ฆฐ ์ด๋ฏธ์ง€๋ฅผ ์›€์ง์ด๋Š” ๋“ฑ์˜ ๋‹ค๋ฅธ ๋™์ž‘์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

class CropRectangle : public Rectangle
{
public:
	CropRectangle();
	~CropRectangle();

public:
	virtual bool IsInBound(const unsigned int x, const unsigned int y) override;
	virtual void Drag(const unsigned int x, const unsigned int y) override;
	virtual Gdiplus::Rect GetSize() const override;

	void Draw(Gdiplus::Graphics* g, const bool isDrawBorder);
	void Draw(Gdiplus::Graphics* g, Gdiplus::Image* image);
	void SetCropPoints();

private:
	Point m_pointOfBeginCrop;
	Point m_pointOfEndCrop;
};

์ด ๊ฒฝ์šฐ, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์šด ์บ์ŠคํŒ…(Down Casting) ํ›„ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

std::shared_ptr<Figure::CropRectangle> crop = std::dynamic_pointer_cast<Figure::CropRectangle>(m_figure);
crop->SetCropPoints();

์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์—์„œ๋Š” std::dynamic_pointer_cast๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์šด ์บ์ŠคํŒ…์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ค๋‹ˆ ์ ์  ๋ณต์žกํ•ด์ง‘๋‹ˆ๋‹ค. ์•„์ง๊นŒ์ง€๋Š” ์„ค๋ช…์ด๋‹ˆ '๊ทธ๋ ‡๊ตฌ๋‚˜~'ํ•˜๊ณ  ๋„˜์–ด๊ฐ€์…”๋„ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ GDI+์™€ ๋”๋ธ” ๋ฒ„ํผ๋ง์— ๊ด€ํ•œ ์†Œ๊ฐœ๋กœ ๋‚ด์šฉ์„ ์ด์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•