Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Drawing a rectangle via mouse drag?

2,561 views
Skip to first unread message

Charles Tam

unread,
Mar 30, 2008, 8:07:00 PM3/30/08
to
In MFC 6, how do I draw a rectangle via a mouse drag?
Is there any example code I could look at?

Scott McPhillips [MVP]

unread,
Mar 30, 2008, 8:51:50 PM3/30/08
to
"Charles Tam" <Charl...@discussions.microsoft.com> wrote in message
news:8CA07CA7-F2AE-432F...@microsoft.com...

> In MFC 6, how do I draw a rectangle via a mouse drag?
> Is there any example code I could look at?
>

Here's a minimal example:

void CSDIView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_ptStart = point;
m_ptEnd = point;
SetCapture();
}

void CSDIView::OnMouseMove(UINT nFlags, CPoint point)
{
if (GetCapture() == this)
{ m_ptEnd = point;
Invalidate();
}
}

void CSDIView::OnLButtonUp(UINT nFlags, CPoint point)
{
if (GetCapture() == this)
{ ReleaseCapture();
m_ptEnd = point;
Invalidate();
}
}

void CSDIView::OnDraw(CDC* pDC)
{
CRect r(m_ptStart, m_ptEnd);
pDC->Rectangle(&r);
}


--
Scott McPhillips [VC++ MVP]

Charles Tam

unread,
Mar 31, 2008, 12:16:00 AM3/31/08
to
Hi Scott,

I've modified your code in OnMouseMove to support SDI applications. It
seems to be working fine. Please reply otherwise.

void CXxxDlg::OnMouseMove(UINT nFlags, CPoint point)

{
if (GetCapture() == this)
{
m_ptEnd = point;
Invalidate();
}

CRect r(m_ptStart, m_ptEnd);
CPaintDC dc(this);
dc.GetSafeHdc();
dc.Rectangle(&r);

AliR (VC++ MVP)

unread,
Mar 31, 2008, 10:19:47 AM3/31/08
to
What part of Scott's OnMouseMove did not support SDI? One has nothing to do
with other?

Why are you drawing your rectangle in the OnMouseMove method? All your
drawing code should be in OnPaint, just the way Scott posted it.

In your OnMouseMove, while there is capture you are recording the endpoint
and then invalidating the client area which will cause a WM_PAINT to get
posted after OnMouseMove returns, and then drawing a rect which will get
erased when the WM_PAINT from the Invalidate() call gets processed.

Anyway drawing anything in OnMouseMove is pointless.

AliR.

"Charles Tam" <Charl...@discussions.microsoft.com> wrote in message

news:B1E93C60-C653-45DA...@microsoft.com...

Scott McPhillips [MVP]

unread,
Mar 31, 2008, 10:33:30 AM3/31/08
to
"Charles Tam" <Charl...@discussions.microsoft.com> wrote in message
news:B1E93C60-C653-45DA...@microsoft.com...

> Hi Scott,
>
> I've modified your code in OnMouseMove to support SDI applications. It
> seems to be working fine. Please reply otherwise.
>
> void CXxxDlg::OnMouseMove(UINT nFlags, CPoint point)
> {
> if (GetCapture() == this)
> {
> m_ptEnd = point;
> Invalidate();
> }
>
> CRect r(m_ptStart, m_ptEnd);
> CPaintDC dc(this);
> dc.GetSafeHdc();
> dc.Rectangle(&r);
> }

CPaintDC is specialized for use only in a WM_PAINT handler. It is an error
to use it elsewhere. When painting outside of a WM_PAINT handler you should
use CClientDC.

It also does not make sense to call Invalidate() and then paint. The
Invalidate() is going to cause WM_PAINT as soon as you return, and that will
erase or overwrite your illegal painting.

Why are you trying to paint on a dialog?

Joseph M. Newcomer

unread,
Mar 31, 2008, 2:02:31 PM3/31/08
to
The classic rubber-banding approach is to do all the painting in OnMouseMove using one of
the complement-methods, such as XOR, XORNOT, etc.; each time you repaint the existing
rectangle and then draw the new one using CClientDC. When the mouse is released, you
typically Invalidate() and the OnPaint handler knows how to draw the selected items (e.g.,
reverse-video or some such). This is a classic from the Scribble tutorial

CPoint anchor;
CPoint endpoint;

void CMyClass::OnLButtonDown(...CPoint point)
{
anchor = endpoint = point;
CClientDC dc(this);
dc.DrawFocusRect(anchor.x, anchor.y, endpoint.x, endpoint.y);// very small rectangle
SetCapture();
}

void CMyClass::OnMouseMove(..., CPoint point)
{
if(GetCapture() != NULL)
{ /* rubber band */
CClientDC dc(this);
dc.DrawFocusRect(anchor.x, anchor.y, endpoint.x, endpoint.y);
endpoint = point;
dc.DrawFocusRect(anchor.x, anchor.y, endpoint.x, endpoint.y);
} /* rubber band */

void CMyClass::OnLButtonUp(..., CPoint point)
{
if(GetCapture() != NULL)
{ /* banding */
CClientDC dc(this);
dc.DrawFocusRect(anchor.x, anchor.y, endpoint.x, endpoint.y);
Selection = CRect(anchor.x, anchor.y, point.x, point.y);
ReleaseCapture();
InvalidateRect(&Selection);
} /* banding */

I think DrawFocusRect does an xor; if not, you will have to SetROP2 to select a
complementing mode.

The advantage of this technique is that it doesn't require redrawing everything, or for
that matter, anything, until the selection process has finished.
joe

On Sun, 30 Mar 2008 17:07:00 -0700, Charles Tam <Charl...@discussions.microsoft.com>
wrote:

>In MFC 6, how do I draw a rectangle via a mouse drag?
>Is there any example code I could look at?

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer

unread,
Mar 31, 2008, 2:06:11 PM3/31/08
to
See bleow...
On Sun, 30 Mar 2008 21:16:00 -0700, Charles Tam <Charl...@discussions.microsoft.com>
wrote:

>Hi Scott,


>
>I've modified your code in OnMouseMove to support SDI applications. It
>seems to be working fine. Please reply otherwise.
>
>void CXxxDlg::OnMouseMove(UINT nFlags, CPoint point)
>{
>if (GetCapture() == this)

****
GetCapture only has to be non-NULL. If you have capture, you get the message; if you
don't have capture, you're not in dragging mode. No need to compare to this
*****
>{
>m_ptEnd = point;
>Invalidate();
*****
See my later post; typically you do not Invalidate() the whole area, or any part of it,
during dragging
****


>}
>
>CRect r(m_ptStart, m_ptEnd);
>CPaintDC dc(this);

****
This makes no sense here. CPaintDC can only be used in OnPaint handlers
****
>dc.GetSafeHdc();
****
This makes no sense because it does nothing.
****
>dc.Rectangle(&r);
****
Probably wrong; you did not select the HOLLOW_BRUSH to fill, so you will get a solid white
rectangle that will overwrite everything. See my example.

Note that SDI is no different from any CWnd, so it is not clear what you had to "change"
to use it with SDI.
****


>}
>
>
>
>"Scott McPhillips [MVP]" wrote:
>
>> "Charles Tam" <Charl...@discussions.microsoft.com> wrote in message
>> news:8CA07CA7-F2AE-432F...@microsoft.com...
>> > In MFC 6, how do I draw a rectangle via a mouse drag?
>> > Is there any example code I could look at?
>> >
>>
>> Here's a minimal example:
>>
>> void CSDIView::OnLButtonDown(UINT nFlags, CPoint point)
>> {
>> m_ptStart = point;
>> m_ptEnd = point;
>> SetCapture();
>> }
>>
>> void CSDIView::OnMouseMove(UINT nFlags, CPoint point)
>> {
>> if (GetCapture() == this)
>> { m_ptEnd = point;
>> Invalidate();
>> }
>> }
>>
>> void CSDIView::OnLButtonUp(UINT nFlags, CPoint point)
>> {
>> if (GetCapture() == this)
>> { ReleaseCapture();
>> m_ptEnd = point;
>> Invalidate();
>> }
>> }
>>
>> void CSDIView::OnDraw(CDC* pDC)
>> {
>> CRect r(m_ptStart, m_ptEnd);
>> pDC->Rectangle(&r);
>> }
>>
>>
>> --
>> Scott McPhillips [VC++ MVP]
>>
>>

priyankak

unread,
Jul 25, 2008, 5:05:42 PM7/25/08
to
Hi all

I am new to C++,I tried the first, Drawing a rectangle via mouse drag? example by Scott McPhillips , it works fine ,, but
the 2ed example
Drawing a rectangle via mouse drag? by Joseph M. errors out saying
error C2660: 'DrawFocusRect' : function does not take 4 parameters.
Please let me know how to draw transparent rectangle , with a solid drak border.
Thanks
Priyanka

Scott McPhillips [MVP]

unread,
Jul 25, 2008, 5:39:07 PM7/25/08
to
"priyanka k" wrote in message news:200872517541...@gmail.com...

There are two DrawFocusRect functions, one is an API and one is a CDC member
function. Neither one of them takes 4 parameters! Neither one of them
draws with a solid dark border!

Why do you have 4 parameters? Perhaps you should show your code.

Ajay Kalra

unread,
Jul 25, 2008, 11:32:33 PM7/25/08
to
You should see MSDN for simple things like this(method definitions). Why do
you have these parameters?

--
Ajay

"priyanka k" wrote in message news:200872517541...@gmail.com...

Joseph M. Newcomer

unread,
Jul 26, 2008, 12:45:37 AM7/26/08
to
It may be a typo in which case I will have to fix it, let me know where it is. When in
doubt, RTFM.
joe

arfan...@gmail.com

unread,
Aug 11, 2008, 11:44:51 PM8/11/08
to

//This would make a hollow brush
CClientDC dc(this);
dc.SelectStockObject(HOLLOW_BRUSH);

dmanm...@gmail.com

unread,
Jul 16, 2019, 11:27:43 AM7/16/19
to
On Sunday, March 30, 2008 at 8:07:00 PM UTC-4, Charles Tam wrote:
> In MFC 6, how do I draw a rectangle via a mouse drag?
> Is there any example code I could look at?

You will probably want to increase the size of the pen so it it easier to see.
This is done with the SPI_SETFOCUSBORDERWIDTH. After the function is done you should set it back to the old value because this is a system setting.


void CMyClass::OnLButtonDown(...CPoint point)
{
anchor = endpoint = point;

CClientDC dc(this);

dc.SelectObject(create_focus_pen());

dc.DrawFocusRect(anchor.x, anchor.y, endpoint.x, endpoint.y);// very small rectangle
SetCapture();
}

...


HPEN create_focus_pen()
{
LONG width;
LONG height;

unsigned int newheight;

newheight = 6;

SystemParametersInfo(SPI_SETFOCUSBORDERHEIGHT, 0, (unsigned int*)newheight, SPIF_SENDCHANGE);
SystemParametersInfo(SPI_SETFOCUSBORDERWIDTH, 0, (unsigned int*)newheight, SPIF_SENDCHANGE);

SystemParametersInfo(SPI_GETFOCUSBORDERHEIGHT, 0, &height, 0);
SystemParametersInfo(SPI_GETFOCUSBORDERWIDTH, 0, &width, 0);

LOGBRUSH lb = { }; // initialize to zero
lb.lbColor = 0xffffff; // white
lb.lbStyle = BS_HATCHED;
lb.lbHatch = HS_FDIAGONAL;

return ExtCreatePen(PS_GEOMETRIC | PS_DOT, width, &lb, 0, 0);
}
0 new messages