I am doing a small drawing tool with MFC.
I define five shapes: rectangle, line, circle, ellipse and dot. int m_drawType is used to switch between five shapes.
The code as below:
void CDrawToolView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_startRect=TRUE;
m_startPoint=point;
m_OldPoint=point;
::SetCursor(m_HCross);
CView::OnLButtonDown(nFlags, point);
}
void CDrawToolView::OnMouseMove(UINT nFlags, CPoint point)
{
CClientDC dc(this);
dc.SetROP2(R2_NOT);
dc.SetROP2(R2_NOT);
dc.SelectStockObject(NULL_BRUSH);
if(TRUE==m_startRect)
{
switch(m_drawType)
{
case 1://Rectangle
::SetCursor(m_HCross);
dc.Rectangle(CRect(m_startPoint,m_OldPoint));
dc.Rectangle(CRect(m_startPoint,point));
m_OldPoint=point;
break;
case 2: //Line
::SetCursor(m_HCross);
dc.MoveTo(m_startPoint);
dc.LineTo(m_OldPoint);
dc.MoveTo(m_startPoint);
dc.LineTo(point);
m_OldPoint=point;
break;
.
.
.
}
}
CView::OnMouseMove(nFlags, point);
}
void CDrawToolView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_startRect=FALSE;
::ClipCursor(NULL);
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
switch(m_drawType)
{
case 1: //Retangle
dc.Rectangle(CRect(m_startPoint,m_OldPoint));
dc.Rectangle(CRect(m_startPoint,point));
break;
case 2: //Line
dc.MoveTo(m_startPoint);
dc.LineTo(m_OldPoint);
dc.MoveTo(m_startPoint);
dc.LineTo(point);
break;
.
.
.
}
CView::OnLButtonUp(nFlags, point);
}
void CDrawToolView::OnEditShape() // when click menu-edit-shape a dialog is pop up
{
CShapeDlg dlg;
dlg.DoModal();
}
The pop up dialog as below:
I have created a dialog of five buttons. My problem is I don't know how to link between the buttons and these five shapes. Could some one help me?
So your question is how to make the buttons of CShapeDlg set m_drawType?
Your dialog could have a local public drawType variable. Introduce button click event handlers for the buttons.
BEGIN_MESSAGE_MAP(CShapeDlg, CDialog)
ON_BN_CLICKED(IDC_BUTTON1, &CShapeDlg::OnBnClickedButton1)
... etc.
ON_BN_CLICKED(IDC_BUTTON5, &CShapeDlg::OnBnClickedButton5)
END_MESSAGE_MAP()
Make the handlers set the local drawType variable to integer value 0 - 4 as the case may be.
void CShapeDlg::OnBnClickedButton1() { drawType = 0; }
... etc.
void CShapeDlg::OnBnClickedButton5() { drawType = 4; }
Then
if (dlg.DoModal() == IDOK)
m_drawType = dlg.drawType;
The dialog should have an m_drawtype variable that it sets when a button is clicked. When DoModal returns this variable can be read to get the result:
dlg.DoModal();
m_drawtype = dlg.m_drawtype;
Related
I have an MFC dialog application where the user can upload a photo and it will be displayed within the dialog. After they have uploaded an image they will be able select a region of this image and for this I am using the CRectTracker class. My problem however is that the tracker is currently being displayed behind the image.
What I have tried so far is:
Googling how to set the z-order of the CRectTracker object, but cannot seem to find any documentation on it.
Set the z-order of the image to the bottom using SetWindowPos(&wndBottom,...) but the tracker still appears behind the image.
I am using a Picture Control (type Bitmap) to display the image.
EDIT:
I draw the tracker in the OnPaint() method of my dialog class like this:
CPaintDC dc(this);
m_tracker.Draw(&dc);
which is being called by this->Invalidate(); in OnLButtonDown and OnMouseMove whenever I need to refresh the tracker:
void CTAB3::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_tackerFlag)
{
int nHitTest;
nHitTest = m_tracker.HitTest(point);
if (nHitTest < 0) // if the mouse down point is outside of the rect tracker
{
m_start = point; // Record the start drawing point
m_bDraw = TRUE; // set m_bDraw (in handle funtion WM_MOUSEMOVE will test this to decide whether to draw)
}
else // if the mouse down point is inside of the rect tracker
{
m_tracker.Track(this, point, FALSE); // start drag the rect tracker
this->Invalidate(); // make the window paint to refresh the track
}
}
CDialogEx::OnLButtonDown(nFlags, point);
}
void CTAB3::OnMouseMove(UINT nFlags, CPoint point)
{
// m_bDraw is set to true in funtion OnLButtonDown and set to false in funtion OnLButtonDown
// m_bDraw is use for testing if the mouse is moved along with the left button is pressed.
if (m_bDraw)
{
m_tracker.m_rect.SetRect(m_start, point); // set the rect of rect tracker
this->Invalidate(); // make the window paint to refresh the rect
}
CDialogEx::OnMouseMove(nFlags, point);
}
EDIT2:
Based on #ConstantineGeorgiou comment I decided to keep trying to implement the tracker with the resize handles using Track() as this would be the preferred solution for my project. I finally managed to draw the tracker on top of the image, but I am not particularly happy with the solution I ended up with. Basically I moved the Draw() function to the mouse move handler, so that the tracker is drawn after the OnPaint() has drawn everything else on the dialog. If anyone has any suggestion on better ways to do this, I would be very grateful for any feedback.
This is how I implemented it with the Draw() in the OnMouseMove() handler:
//In the header file:
BOOL m_bDraw = FALSE
void CTAB3::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_tackerFlag)
{
m_tracker.Track(this, point, FALSE); // start drag the rect tracker
this->Invalidate();
m_bDraw = TRUE;
}
CDialogEx::OnLButtonDown(nFlags, point);
}
void CTAB3::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bDraw)
{
//Draw tracker
CDC* dc = GetDC();
m_tracker.Draw(dc);
}
CDialogEx::OnMouseMove(nFlags, point);
}
BOOL CTAB3::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (m_tackerFlag)
{
if (pWnd == this && m_tracker.SetCursor(this, nHitTest))
{
return TRUE;
}
}
return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}
void CTAB3::OnPaint()
{
CPaintDC dc(this); // device context for painting
//m_tracker.Draw(&dc);
}
I have a Dialog with 8 Dynamic Read-Only Edit Boxes, 7/8 of them will hold different text strings, and the last one is empty. What i'm trying to do is: when a user clicks at 1 of those Edit Boxes (which hold the text string), the text will be shown in the empty Edit Box. If you guys have any ideas on how this should be done, I would be grateful.
Here are some codes that i've tried:
void CTab1::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
...
DDX_Text(pDX, IDC_TAB1CMTBOX, m_StrShow);
}
BEGIN_MESSAGE_MAP(CTab1, CDialog)
...
ON_CONTROL_RANGE(EN_SETFOCUS, 4000, 4100, &CTab1::OnEditBoxClicked)
END_MESSAGE_MAP()
void CTab1::OnEditBoxClicked(UINT nID)
{
switch (nID)
{
case 4001:
GetDlgItemText(4001, m_CmtText);
m_CmtText = m_StrShow;
UpdateData(FALSE);
break;
case 4003:
GetDlgItemText(4003, m_CmtText);
m_CmtText = m_StrShow;
SetDlgItemText(IDC_TAB1CMTBOX, m_StrShow);//This line doesn't work
UpdateData(FALSE);
break;
...
}
What I see You obviously only have swapped the variables.
void CTab1::OnEditBoxClicked(UINT nID)
{
switch (nID)
{
case 4003:
GetDlgItemText(4003, m_CmtText); // Read ctrl Text to m_CmtString
// m_CmtText = m_StrShow; // then Write immediately m_strShow to m_CmtText. Which make no sense
m_StrShow = m_CmtText; // <-- swapped
// SetDlgItemText(IDC_TAB1CMTBOX, m_StrShow); // sure? You want show the Text in IDC_TAB1CMTBOX ?
SetDlgItemText(IDC_SHOWBOX, m_StrShow); // replace IDC
UpdateData(FALSE);
break;
..
}
This is what I would do, simplify the code.
void CTab1::OnEditBoxClicked(UINT nID)
{
if (UpdateData(TRUE))
{
GetDlgItemText(nID, m_CmtText); // Read ctrl Text nID
SetDlgItemText(IDC_SHOWBOX, m_CmtText); // Show the ctrl nID Text to ShowBox
UpdateData(FALSE);
}
}
I am trying to set an mouse click event on editbox and when I am double clicking on edit box it should bring up a message box.
ON_WM_LBUTTONDBLCLK(IDC_EDITItem, &MessageManage::OnItemDoubleClick)
void MessageManage::OnItemDoubleClick()
{
MessageBox( m_strItemMsg, "Sample code", MB_OK | MB_ICONINFORMATION );
}
At alternative is to just use PreTranslateMessage on your dialog:
BOOL CMFCApplication1Dlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_LBUTTONDBLCLK &&
pMsg->hwnd == ::GetDlgItem(m_hWnd, IDC_EDIT1))
{
AfxMessageBox(_T("Run Code"));
return TRUE; //Important!!! Message is handled
}
return CDialogEx::PreTranslateMessage(pMsg);
}
It's not taking double click event from edit box
One way to accomplish this is to derive your own class from CEdit and handle ON_WM_LBUTTONDBLCLK(). The following code responded to the double click on an edit control in a sample program.
BEGIN_MESSAGE_MAP(MyEdit, CEdit)
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()
// MyEdit message handlers
void MyEdit::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CEdit::OnLButtonDblClk(nFlags, point);
}
I need to move window by right mouse button. The window has no caption, titlebar. By left button it works
void CMyHud::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
SendMessage(WM_SYSCOMMAND, SC_MOVE|0x0002);
CDialogEx::OnLButtonDown(nFlags, point);
}
But if I place this code on OnRButtonDown it dosen't work. What is the problem?
Well, the solution is found, thanks to Mark Ransom:
CRect pos;
void CMyHud::OnRButtonDown(UINT nFlags, CPoint point)
{
pos.left = point.x;
pos.top = point.y;
::SetCapture(m_hWnd);
CDialogEx::OnRButtonDown(nFlags, point);
}
void CMyHud::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd* pWnd = CWnd::FromHandle(m_hWnd);
CRect r;
if(GetCapture() == pWnd)
{
POINT pt;
GetCursorPos(&pt);
GetWindowRect(r);
pt.x -= pos.left;
pt.y -= pos.top;
MoveWindow(pt.x, pt.y, r.Width(), r.Height(),TRUE);
}
CDialogEx::OnMouseMove(nFlags, point);
}
void CMyHud::OnRButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
CDialogEx::OnRButtonUp(nFlags, point);
}
In your OnRButtonDown function, do a SetCapture to ensure all mouse messages are routed to your window while the mouse button is down. Also store the mouse position in a member variable. Now, in your OnMouseMove function, check to see if GetCapture returns an object with the same HWND as yours - if it does, calculate the difference between the current mouse position and the saved one, then call MoveWindow to move the window.
In regards to left-mouse click:
SC_MOVE|0x0002 comes out as 0xF012 or SC_DRAGMOVE. This is apparently an undocumented constant. There is probably a good reason Microsoft doesn't want anybody to use this, that's why they have hidden it.
Also WM_SYSCOMMAND is a notification message. You should respond to it, not send it. To drag the window with left-mouse click:
message map ...
ON_WM_NCHITTEST()
LRESULT CMyDialog::OnNcHitTest(CPoint p)
{
//responding to a notification message
return HTCAPTION;
}
To drag the window with right-mouse you have to override OnRButtonDown, OnMouseMove, OnRButtonUp and make your own routine. But Window's behaviour gets very confusing. Is that really worth it?
you can use mouse message to realize.
WM_RBUTTONDOWN, WM_MOUSEMOVE
The code
#include "stdafx.h"
#include "TestClass.h"
IMPLEMENT_DYNAMIC(TestClass, CStatic)
TestClass::TestClass()
{
}
void TestClass::Ini(CWnd* parent)
{
Create(L"hello world",WS_CHILD|WS_VISIBLE|SS_CENTER | SS_NOTIFY ,
CRect(0,0,50,50), parent, 200);
}
void TestClass::OnMouseMove(UINT nFlags, CPoint point)
{
CStatic::OnMouseMove(nFlags, point);
}
void TestClass::OnMouseLeave()
{
CStatic::OnMouseLeave();
}
TestClass::~TestClass()
{
}
BEGIN_MESSAGE_MAP(TestClass, CStatic)
ON_WM_MOUSEMOVE()
ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()
As you can see I'm using SS_NOTIFY and I can not get the OnMouseLeave event, but OnMouseMove working without any problems.
Note:
I creating a custom window so I removed the title bar.
If you want to handle the mouse leave and mouse hover event you have to call TrackMouseEvent in the OnMouseMove function.
void TestClass::OnMouseMove(UINT nFlags, CPoint point)
{
TRACKMOUSEEVENT MouseBehaviour;
CStatic::OnMouseMove(nFlags, point);
MouseBehaviour.cbSize = sizeof(TRACKMOUSEEVENT);
MouseBehaviour.dwFlags = TME_HOVER | TME_LEAVE;
MouseBehaviour.hwndTrack = GetSafeHwnd();
MouseBehaviour.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&MouseBehaviour);
}