Từ 1 tới 8 trên tổng số 8 kết quả

Đề tài: Cách vẽ đa giác giống như Paint trên VC++?

  1. #1
    Ngày gia nhập
    11 2006
    Bài viết
    13

    Unhappy Cách vẽ đa giác giống như Paint trên VC++?

    Em đang code 1 chương trình vẽ đa giác trong MFC. Chương trình đơn giản là nhái cách vẽ đa giác của Microsoft Paint nhưng em gặp 1 trục trặc ở chỗ này . Trong Paint, em thấy nét đầu tiên phải LeftButtonDown và Move Mouse thì mới hiện ra ,chỗ này bỏ qua , rắc rối xuất hiện ở những nét vẽ bước thứ 2 cho đến khi kết thúc 1 đa giác .

    Nếu ta nhấn tiếp LeftButtonDown thì nét thứ 2 của đa giác hiện ra ,tuy nhiên nếu ta LeftButtonDown và lại Move Mouse thì sẽ chỉnh được hướng xoay cho nét thứ 2 ,tương tự như vậy cho nét thứ n. Em cũng bắt chước thao tác như thế nhưng khi em LeftButtonDown và Move thì nét vẽ khi Down Mouse xuống bị dính lại ,nó ko mất đi như trong Paint. (em dùng cách hàm MoveTo, LineTo để vẽ đa giác). Còn nét xoay khi Move thì ngon lành do em xài SetROP2().

    Vậy cho em hỏi làm sao có thể thực hiện 2 thao tác như trong Paint ?

    + Nếu chỉ LeftButtonDown thì hiện ra nét vẽ thứ n. (n > 1)
    + Nếu LeftButtonDown và Move thì nét vẽ khi Down phải biến mất.

    PS: EM đã thử dùng Invalidate() để clear nguyên vùng client ngay khi vừa Move Mouse nhưng cách này ko hay.

  2. #2
    Ngày gia nhập
    07 2006
    Bài viết
    166

    Bạn diễn tả như vậy quá khó hiểu, nên không biết trả lời sao cho đúng. Nhưng thôi cứ đoán bừa rồi trả lời vậy .
    Tôi nghĩ chắc là bạn muốn khi MOUSEMOVE thì sẽ vẽ một đoạn thẳng từ đỉnh (đặt là Ai)vừa được vẽ đến tọa độ chuột, nếu ấn tiếp MOUSEDOWN tại điểm A(i+1)thì sẽ nối từ đỉnh Ai đó đến đỉnh A(i+1). Theo như tôi đoán thì vấn đề của bạn có lẽ là khi MOUSEMOVE chương trình sẽ vẽ ra cả một chùm đường thẳng đi qua điểm Ai và bạn có một cách là dùng InValidate(...); nhưng với cách dùng hàm InValidate(...) thì màn hình sẽ bị giật. Vì vậy bạn phải tạo ra một hàm chỉ dùng để vẽ đa giác (hàm này sẽ nối các tọa độ đỉnh lại), mỗi khi MOUSEMOVE thì sẽ gọi hàm này. Kiểu như sau:
    Code:
    void CSomeClass::OnMouseMove(UINT nFlags, CPoint point)
    {
             ...
             if ((nFlags & MK_LBUTTON) == MK_LBUTTON) // kiểm tra xem có ấn chuột trái không
             {
                   CClientDC dc(this);
                   DrawPolygon(&dc);
             }
    }
    ...
    void CSomeClass::DrawPolygon(CDC *pDc)
    {
            // Xóa màn hình bằng cách vẽ màu nền lên
    	CRect rect;
    	GetClientRect(&rect);
    	CBrush brush(RGB(0,0,0));
    	pDC->FillRect(&rect,&brush);
            ...
            // Nối các đỉnh của đa giác lại với MoveTo và LineTo
            ...
    }
    Đã được chỉnh sửa lần cuối bởi vinhie47 : 28-11-2006 lúc 02:57 PM.

  3. #3
    Ngày gia nhập
    11 2006
    Bài viết
    13

    Trích dẫn Nguyên bản được gửi bởi vinhie47
    Bạn diễn tả như vậy quá khó hiểu, nên không biết trả lời sao cho đúng. Nhưng thôi cứ đoán bừa rồi trả lời vậy .
    Tôi nghĩ chắc là bạn muốn khi MOUSEMOVE thì sẽ vẽ một đoạn thẳng từ đỉnh (đặt là Ai)vừa được vẽ đến tọa độ chuột, nếu ấn tiếp MOUSEDOWN tại điểm A(i+1)thì sẽ nối từ đỉnh Ai đó đến đỉnh A(i+1). Theo như tôi đoán thì vấn đề của bạn có lẽ là khi MOUSEMOVE chương trình sẽ vẽ ra cả một chùm đường thẳng đi qua điểm Ai và bạn có một cách là dùng InValidate(...); nhưng với cách dùng hàm InValidate(...) thì màn hình sẽ bị giật. Vì vậy bạn phải tạo ra một hàm chỉ dùng để vẽ đa giác (hàm này sẽ nối các tọa độ đỉnh lại), mỗi khi MOUSEMOVE thì sẽ gọi hàm này. Kiểu như sau:

    [/code]
    Em đọc lại bài mình thì thấy dễ bị hiểu nhầm thật. Em xin trình bày lại.

    Vấn đề Move Mouse thì em giải quyết được rồi ,ko bị chùm đường thẳng ,nhưng vấn đề là nhái cách vẽ của Paint thì có tới 2 kiểu để vẽ 1 đa giác. Bác cứ mở Paint lên vẽ thử 1 đa giác sẽ thấy .

    + Khi ta Click tại 1 điểm nào đó (trong Mode vẽ đa giác), Paint tự nối dài tới đó (nếu ta nhả mouse ra ngay) ,tức là nó xử lý sự kiện LeftButtonDown để vẽ ngay khi nhận sự kiện này .

    +Đồng thời nếu ta Move Mouse ngay lúc đang đè mouse, thì ta lại có thể chọn điểm dừng tùy ý ,đường thẳng sẽ chạy theo trỏ chuột cho tới khi ta nhả chuột ra. Vậy tức là Paint đã xử lý ngay khi vừa Move Mouse, nét vẽ khi vừa nhận LeftButtonDown ở trên đã bị xóa đi (chỉ 1 nét duy nhất ,ko phải chùm).

    Nên vấn đề của em là khi vừa nhận message move mouse trong lúc đang đè mouse thì nó phải xóa 1 nét đã vẽ trước đó (khi vừa nhận LeftButtonDown mà chưa move).

    Bác chạy file em đã build sẽ thấy rõ vấn đề. (có 1 nét thừa mỗi lần đè + move )
    Đây là cách sử dụng ct này :
    + Click hoặc Click + Move Mouse để vẽ các nét của Đa giác
    + Double Click để kết thúc vẽ 1 đa giác.
    Code:
    http://www.freewebtown.com/trickyboy/Test/VeDaGiac.rar

  4. #4
    Ngày gia nhập
    07 2006
    Bài viết
    166

    Nói chung là có nhiều cách, thử nói một cách xem có được không )
    Giả sử đa giác đã có n đỉnh (đã vẽ được n-1 cạnh), bây giờ bạn LBUTTONDOWN ở điểm A, bạn gọi hàm DrawPolygon (hàm này chỉ vẽ n-1 cạnh trước) rồi nối thêm đoạn từ đỉnh thứ n đến điểm A (chú ý lúc này chưa thêm điểm A để nó trở thành đỉnh thứ n+1 của đa giác). Nếu có LBUTTONUP thì mới thêm đỉnh A này để trở thành đỉnh n+1.
    Khi đó ở sự kiện MOUSEMOVE (chính xác thì là WM_MOUSEMOVE ) và có LBUTTONDOWN bạn cũng lại gọi hàm DrawPolygon() rồi vẽ thêm một đoạn thẳng từ đỉnh thứ n đến tọa độ chuột, do chưa có LBUTTONUP nên các điểm tính từ khi LBUTTONDOWN cho đến giờ vẫn chưa được thêm vào thành đỉnh của đa giác nên sẽ không bị hiện tượng như ở trên.
    Cái quan trọng ở đây là bạn chỉ thêm đỉnh thứ n+1 (khi vẽ cạnh thứ n) khi có sự kiện WM_LBUTTONUP.

    Nói vậy hơi khó hiểu không biết có giúp cho bạn được không, nếu vẫn không hiểu thì bạn upload cái project kia lên để sửa luôn cho tiện
    Đã được chỉnh sửa lần cuối bởi vinhie47 : 28-11-2006 lúc 03:22 PM.

  5. #5
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,760

    Theo Dreaminess nó đơn giản như sau:

    Trước hết cần lưu lại tọa độ điểm cuối của đường thẳng đã vẽ (ox,oy), tọa độ này là điểm đầu của đường thẳng cần vẽ tiếp. Nếu là click đầu tiên thì (ox,oy) chính là điểm kích đó

    Nếu là LeftButtonDown = True, ta lưu lại tọa độ Mouse ngay tại vị trí chuột (x,y) và vị trí Mouse ngay trước (lx,ly) .

    lx=ox;ly=oy;

    Trong khi LeftButtonDown vẫn còn là True, ta vẽ 2 line sau:
    {
    Line (lx,ly,ox,oy), line này có màu trùng với màu của nền.
    Line (x,y,ox,oy), Line này là line cần hiển thị lên màn hình.
    lx=x; ly=y;
    } đến khi nhả chuột thì thôi.

    Như vậy, nếu như chỉ click một lần mà không giữ chuột trái thì line nhận được sẽ là: Line(x, y, ox, oy)

    Dreaminess nghĩ rằng làm vậy là đạt được yêu cầu rồi đó, nhưng tối ưu thì .... Chắc là không????
    Email: kevin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó.
    Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp hoặc bị sự thiếu kỷ luật làm tiêu tan sự nghiệp.

  6. #6
    Ngày gia nhập
    11 2006
    Bài viết
    13

    Mặc định Cách vẽ đa giác giống như Paint trên VC++?

    Trích dẫn Nguyên bản được gửi bởi Dreaminess
    Nếu là LeftButtonDown = True, ta lưu lại tọa độ Mouse ngay tại vị trí chuột (x,y) và vị trí Mouse ngay trước (lx,ly) .

    lx=ox;ly=oy;

    Trong khi LeftButtonDown vẫn còn là True, ta vẽ 2 line sau:
    {
    Line (lx,ly,ox,oy), line này có màu trùng với màu của nền.
    Line (x,y,ox,oy), Line này là line cần hiển thị lên màn hình.
    lx=x; ly=y;
    } đến khi nhả chuột thì thôi.

    Như vậy, nếu như chỉ click một lần mà không giữ chuột trái thì line nhận được sẽ là: Line(x, y, ox, oy)
    @Dreaminess: Theo ý bác thì đoạn code trên sẽ để trong hàm xử lý mesage MouseMove đúng ko? < OnMouseMove() >

    Như vậy khi click chuột mà ko move thì hàm này đâu được gọi, tức là sẽ ko vẽ được các line nối tiếp ngay khi vừa click. Nếu chỉ move rồi nhả chuột mới tạo các line nối tiếp thì chỉ đạt 1 yêu cầu của bài trên.

    Ở paint, ta thấy là ngay khi nhấn chuột(chưa nhả) thì Line hiện ra ngay ,tức là trong hàm OnLButtonDown() nó đã vẽ trước 1 nét rồi. Sau khi vẽ nét này ,nếu cho đoạn code trên của bác vào OnMouseMove() thì khi move, nó sẽ thêm một nét trùng màu nền đè lên nét đã vẽ trên nên cũng đâu có làm nét đó mất được. (màu nền sẽ cắt ngang nếu đi qua các line khác )

    Tất nhiên là vẽ đa giác có nhiều cách, Click + Move hoặc chỉ Click từng điểm đều được .Nhưng làm sao để làm cả 2 cái đó cùng lúc em mới đau đầu

    Cám ơn các bác cho chỉ dẫn ,ai còn cao kiến xin nói thêm.
    Đã được chỉnh sửa lần cuối bởi trickyboy : 28-11-2006 lúc 08:40 PM.

  7. #7
    Ngày gia nhập
    11 2006
    Bài viết
    13

    Đây phần source của em ,em đã sửa lại để cái nét thừa là màu nền và dùng Invalidate() xóa nó đi . Mấy bác coi chỗ nào ko ổn thì nói em biết.
    Code:
    struct Line
    {
    	CPoint ptTo;
    	CPoint ptFrom;
    	COLORREF color;
    	int penStyle;
    	int penWidth;
    };
    typedef struct Line LINE;
    Code:
    {
    ..............
    //Khai bao
    protected:
    	//{{AFX_MSG(CTrickM_06bView)
    	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    	afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    private:
    	LINE m_line;
    	CPoint m_ptStart;
    	BOOL m_bIsFirst;
    	COLORREF m_color;
    	int m_width;
    	void DrawLine(CDC *pDC, CPoint P1, CPoint P2);
    	CPoint m_ptTo;
    	CPoint m_ptFrom;
    	CPoint m_ptPre;
    	BOOL m_bDown;
    	BOOL m_bMove;
    ..............
    }
    Code:
    CTrickM_06bView::CTrickM_06bView()//Khoi tao ban da`u
    {
    	// TODO: add construction code here
    	
    	m_bDown = FALSE;
    	m_bMove = FALSE;
    	m_bIsFirst = TRUE;
    }
    Code:
    void CTrickM_06bView::DrawLine(CDC *pDC, CPoint P1, CPoint P2)
    {
    	int nOldMode;
    	nOldMode = pDC->SetROP2(R2_NOTXORPEN);
    		
    	pDC->MoveTo(P1);
    	pDC->LineTo(P2);
    	
    	pDC->SetROP2(nOldMode);
    }
    Code:
    void CTrickM_06bView::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	CDC *pDC = GetDC();
    	m_bDown = TRUE;
    	CPen Pen;
    	srand((unsigned)time(NULL));
    	if(m_bIsFirst)//Neu la` diem da`u tien cua da giac n
    	{
    		m_bIsFirst = FALSE;
    		m_ptStart = point;
    		m_ptFrom = point;
    		m_color = RGB(rand() % 256, rand() % 256, rand() % 256);
    		m_width = rand() % 10;
    	}
    	else
    	{
    		m_ptFrom = m_ptPre;
    	}
    	m_ptTo = point;
    	Pen.CreatePen(PS_SOLID, m_width, m_color);
    	pDC->SelectObject(&Pen);
    	pDC->MoveTo(m_ptFrom);
    	pDC->LineTo(point);
    	
    	m_ptPre = m_ptTo;
    	Pen.DeleteObject();
    
    	SetCapture();
    	CView::OnLButtonDown(nFlags, point);
    }
    Code:
    void CTrickM_06bView::OnMouseMove(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	CDC *pDC = GetDC();
    	if(m_bDown)
    	{
    		m_bMove = TRUE;
    		
    		CPen Pen;	
    		Pen.CreatePen(PS_SOLID, m_width, m_color);
    		pDC->SelectObject(&Pen);
    		DrawLine(pDC, m_ptFrom, m_ptTo);//La`m mat' net truoc' do
    		DrawLine(pDC, m_ptFrom, point);//Ve net tai toa do Move toi'
    					
    		m_ptTo = point;
    		m_ptPre = m_ptTo;
    	}
    	
    	CView::OnMouseMove(nFlags, point);
    }
    Code:
    void CTrickM_06bView::OnLButtonUp(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	CDC *pDC = GetDC();
    	
    	if(m_bMove)
    	{
    		m_bMove = FALSE;
    	}
    	
    	if(m_bDown)
    	{
    		m_bDown = FALSE;
    	
    		//Sau moi la`n nha chuot thi` luu toa do cac Line
    		m_line.ptFrom=m_ptFrom;
    		m_line.ptTo=m_ptTo;
    		m_line.penWidth=m_width;
    		m_line.penStyle=PS_SOLID;
    		m_line.color= m_color;
    		m_arrayLine.Add(m_line);
    	}
    
    	Invalidate();
    	
    	::ReleaseCapture();
    	CView::OnLButtonUp(nFlags, point);
    }
    Code:
    void CTrickM_06bView::OnLButtonDblClk(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    
    	CDC *pDC = GetDC();
    	CPen Pen;
    	Pen.CreatePen(PS_SOLID, m_width, m_color);
    	pDC->SelectObject(&Pen);
    
    	//Noi' diem da`u va` diem cuoi
    	pDC->MoveTo(m_ptStart);
    	pDC->LineTo(point);
    
    	//Luu toa do diem cuoi cu`ng cua da giac n
    	m_line.ptFrom=m_ptFrom;
    	m_line.ptTo=m_ptTo;
    	m_arrayLine.Add(m_line);
    
    	//Luu lai toa. do. diem da`u tien cua da giac n va`o Mang
    	m_line.ptFrom=m_ptTo;
    	m_line.ptTo=m_ptStart;
    	m_arrayLine.Add(m_line);
    
    	m_bDown = FALSE;
    	m_bMove = FALSE;
    	m_bIsFirst = TRUE;
    	Pen.DeleteObject();
    	CView::OnLButtonDblClk(nFlags, point);
    
    }
    Code:
    void CTrickM_06bView::OnDraw(CDC* pDC)
    {
    	CTrickM_06bDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	// TODO: add draw code for native data here
    	
    	//Ve lai cac Line cua cac Da giac'
    	int size=m_arrayLine.GetSize();
    	for(int i=0;i<size;i++)
    	{
    	
    		CPen Pen;
    		Pen.CreatePen(m_arrayLine[i].penStyle, m_arrayLine[i].penWidth ,
    						m_arrayLine[i].color);
    		pDC->SelectObject(&Pen);
    		pDC->MoveTo(m_arrayLine[i].ptFrom);
    		pDC->LineTo(m_arrayLine[i].ptTo);
    		
    		Pen.DeleteObject();
    	}
    
    }
    Edit:
    Okie, coi như em đã sửa xong,trong hàm OnLButtonDown nên là thế này:
    Code:
    void CTrickM_06bView::OnLButtonDown(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    	CDC *pDC = GetDC();
    	m_bDown = TRUE;
    	CPen Pen;
    	srand((unsigned)time(NULL));
    	if(m_bIsFirst)//Neu la` diem da`u tien cua da giac n
    	{
    		m_bIsFirst = FALSE;
    		m_ptStart = point;
    		m_ptFrom = point;
    		m_color = RGB(rand() % 256, rand() % 256, rand() % 256);
    		m_width = rand() % 10;
    	}
    	else
    	{
    		m_ptFrom = m_ptPre;
    	}
    	m_ptTo = point;
    	Pen.CreatePen(PS_SOLID, m_width, m_color);
    	pDC->SelectObject(&Pen);
    	
    	//pDC->MoveTo(m_ptFrom);
    	//pDC->LineTo(point);
    
    	DrawLine(pDC,m_ptFrom,point);
    	
    	
    	m_ptPre = m_ptTo;
    	Pen.DeleteObject();
    
    	SetCapture();
    	CView::OnLButtonDown(nFlags, point);
    }
    Cám ơn các bác đã quan tâm.
    Đã được chỉnh sửa lần cuối bởi trickyboy : 01-12-2006 lúc 05:39 PM.

  8. #8
    Ngày gia nhập
    07 2006
    Nơi ở
    Hanoi, Vietnam
    Bài viết
    2,760

    Dreaminess chỉ biết vậy thôi, còn xem chỗ nào không ổn thì chắc phải nhờ đến mấy anh ....

    Best Regards
    Email: kevin[@]congdongcviet.com | CC to: info[@]congdongcviet.com
    Phone: 0972 89 7667

    Một người nào đó coi thường ý thức kỷ luật cũng có nghĩa là người đó đã coi thường tương lai số phận của chính bản thân người đó.
    Những người coi thường ý thức kỷ luật sẽ không bao giờ có được sự thành công trong sự nghiệp hoặc bị sự thiếu kỷ luật làm tiêu tan sự nghiệp.

Các đề tài tương tự

  1. Graphic Có phải thêm enventHandler cho Paint event mới vẽ hình được không ?
    Gửi bởi B_bnguyen trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 5
    Bài viết cuối: 16-02-2012, 08:17 PM
  2. Vẽ tàu vũ trụ bay trên trời đầy sao?
    Gửi bởi mrlamtb trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 12
    Bài viết cuối: 10-09-2011, 11:46 AM
  3. vẽ tam giác cân trên C# bằng các ngôi *?
    Gửi bởi tuan88hy trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 12
    Bài viết cuối: 14-11-2010, 03:00 PM
  4. Vẽ đồ thị hàm số từ bậc 1 đến bậc 4 trên C++?
    Gửi bởi royalfamily trong diễn đàn Thắc mắc lập trình C/C++/C++0x
    Trả lời: 4
    Bài viết cuối: 20-07-2010, 01:31 AM
  5. interval timer trên C# | Lấy mẫu vẽ đồ thị trên C#. Giúp mình với?
    Gửi bởi mrvui trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 1
    Bài viết cuối: 09-05-2009, 10:16 PM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn