Re: I want to get rid of a beep
Joseph M. Newcomer wrote:
See below...
On Sun, 15 Jul 2007 01:12:18 +0200, Eric Lilja <mindcoolerremoveme@gmail.com> wrote:
Hello, I have an edit box in a dialog and I've subclassed the edit box.
If I press enter when the edit box has focus, I hear an annoying beep.
My subclass is very simple, simply handling OnKeyDown and OnGetDlgCode:
#include "stdafx.h"
#include "MyEditBox.h"
#include "ActivityDialog.h"
BEGIN_MESSAGE_MAP(MyEditBox, CEdit)
ON_WM_KEYDOWN()
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
MyEditBox::MyEditBox(CWnd *parent, UINT nID)
{
VERIFY(Create(WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP,
CRect(30, 50, 200, 70), parent, nID));
*****
All of this is nonsense. You cannot possibly know the dimensions of an edit control so
that you can hardwire these numbers. They might represent a dialog on YOUR computer, with
your current display, at its current resolution, with your current display card, with its
current driver, given your current default font, and quite possibly also depend on the
position of Mars with respect to Jupiter, but it doesn't make any sense in the context of
creating real programs.
Well, how am I supposed to specify its size then? When I look at the
resource files, what do I see there? Hardwired numbers. The reason I'm
not placing a normal CEdit using the resource editor is because I wanted
it to perform an action when enter is pressed while it has input focus.
I wanted to do this because it makes testing my program easier while its
being developed (it's not in the assignment specifications). This class
wasn't meant to be re-usable, it's tailored specifically for this
purpose. I like the idea of sending messages instead, but of course that
means both classes involved must know about this message and what it's
supposed to trigger.
However, I restructured it a bit and here's the implementation:
/* MyEditBox.h */
#pragma once
class MyEditBox : public CEdit
{
public:
void Create(CWnd *parent, const CRect& rect, UINT nID, DWORD styles
= WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP);
CString get_text() const { CString s; GetWindowText(s); return s; }
protected:
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg UINT OnGetDlgCode();
DECLARE_MESSAGE_MAP()
};
/* MyEditBox.cpp */
#include "stdafx.h"
#include "MyEditBox.h"
#include "globals.h"
BEGIN_MESSAGE_MAP(MyEditBox, CEdit)
ON_WM_KEYDOWN()
ON_WM_GETDLGCODE()
END_MESSAGE_MAP()
void
MyEditBox::Create(CWnd *parent, const CRect& rect, UINT nID, DWORD styles)
{
VERIFY(CEdit::Create(styles, rect, parent, nID));
SetFont(parent->GetFont());
}
void
MyEditBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_RETURN && GetWindowTextLength())
{
GetParent()->SendMessage(UWM_ADD_ACTIVITY);
}
CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}
UINT
MyEditBox::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
Since CEdit::Create() isn't called in the constructor anymore, the owner
dialog no longer holds a pointer to an object of MyEditBox, but an
actual MyEditBox. This means I must include "MyEditBox.h" in the dialog
header and that means all users of the dialog, will get that include as
well. I wanted to avoid that, for some reason.
As you can see the CRect isn't hardwired here now, instead I use the
same CRect when calling MyEditBox::Create() from the dialog... I don't
know any other way of specifying its size. When I use the resource
editor I twiddle with my controls until I like their size and position
and the IDE hard codes sizes and positions in the resource file. I did
the same twiddling here only I manipulated the CRect passed to
CEdit::Create() until I was satisfied with the size and position.
And, btw, I don't think I will get a failure on this assignment, you
should see the other contributions... I know it's not perfect by far,
but this is not production code and I bet your code isn't always perfect
either. :P
I decided to ignore the cosmetic problem of the beep, it doesn't seem to
be worth it to get rid of it.
Next, why is a constructor for a child control creating the control? Why did you do this?
If you want an edit control, just create it in the dialog at design time and create a
control member variable to represent it. Even if you have a reason to create a control
dynamically, this is exactly the wrong way to do it. What are you trying to accomplish
here? There are probably six better ways of doing it, depending on what you are trying to
accomplish, but this is not a particularly useful way of accomplishing anything
worthwhile.
***
SetFont(parent->GetFont());
}
void
MyEditBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_RETURN && GetWindowTextLength())
{
dynamic_cast<ActivityDialog*>(GetParent())->OnAddActivity();
****
A control should never, ever, under any conditions imaginable, have any idea of the type
of its parent class, let alone have the foggiest notion of the names of methods. This is
the wrong approach. You should do
GetParent()->SendMessage(UWM_ADD_ACTIVITY);
where this is a user-defined message. See my essay on messaging on my MVP Tips site.
There is no sensible world in which a control would include the header file for its
parent.
****
}
CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}
UINT
MyEditBox::OnGetDlgCode()
{
return DLGC_WANTALLKEYS;
}
Why is this beep generated and how can I get rid of it?
*****
Probably because you have a single-line edit control. First, having <enter> do anything
is usually risky in a Windows environment, but it is very risky in a dialog environment.
You might get around this by making it a multiline edit control and then NOT calling the
superclass if you get a VK_RETURN notification.
But you really need to rethink the structure of your program. This is about as bad as you
can get. If this were a class assignment it would get somewhere between an F and a D-. It
violates most sane rules of modular design.
joe
****
- Eric
Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
- Eric