为任何 C++ 程序添加 InputBox()





5.00/5 (14投票s)
一个简单易用的 InputBox() 函数,适用于任何类型的 Windows C++ 程序
引言
在大多数编程语言中,都有一些构建模块,它们使编程变得更容易。例如,弹出消息的能力。在 Win32 中,这将是 MessageBox()。另一个构建模块是 Inputbox
。InputBox() 是一个非常方便的命令,用于提示用户输入。您可以在 VBA 和 Visual Basic 中找到它。但是,虽然消息框可以很容易地在任何 C++ 程序中显示,但没有直接调用像 InputBox
这样的命令的方法。因此,我创建了 SGInputBox()
。我将此代码作为静态库提供,并且没有资源,我认为这是最方便的使用方式,它可以被控制台应用程序、普通的 Win32 应用程序或任何其他类型的 C++ 应用程序使用。
函数
目标是创建一个非常简单易用的 InputBox
函数,可以像这样调用
LPWSTR result = SG_InputBox::GetString(
L"Code Project Demo - by Michael Haephrati",
L"What is your name");
结果,我们希望看到类似这样的内容
或者... 更好的是,为什么不添加一个“默认”值,这样用户将被显示这个值作为默认值,然后能够确认或编辑它。为了使它更加用户友好,我们将已经“全选”默认文本,因此如果用户键入不同的文本,它将替换旧的文本。
为了支持默认文本(但不强迫使用此库的程序员必须有一个),我们添加一个可选参数
LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");
并像这样调用该函数
LPWSTR result = SG_InputBox::GetString(
L"Code Project Demo - by Michael Haephrati",
L"What is your name",
L"My name is Michael");
我们还可以使对话框更漂亮,设置背景色和前景色,将文本对齐到中心并设置一个默认按钮。这些将在我的“如何做”部分中解释,因为这些是技巧和窍门,不一定与本文的范围相关。
测试程序
为了测试 SGInputBox()
函数,我创建了一个默认的 Windows 控制台应用程序,我所做的只是链接到 *InputBox.lib*。最好的方法是使用单个解决方案 (.sln),其中包含静态库项目和测试程序项目,两者都引用 *$(SolutionDir)\$(Configuration)\$(Platform)\*,因此您可以轻松地链接到该库,并且可以为所有配置(x64 / Win32 / Debug 等)定义一次。
$(SolutionDir)\$(Configuration)\$(Platform)\InputBox.lib;
然后,我创建了一个最小的头文件,以便可以调用我们的 SGInputBox()
函数
#include <Windows.h>
class SG_InputBox
{
public:
static LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");
};
然后,剩下的就是调用该函数并使用它返回的返回值。
我们 main()
函数的大部分将是
#include "SG_InputBoxLib.h"
int main()
{
wprintf(L"Testing the InputBox static lib\n");
LPWSTR result = SG_InputBox::GetString(
L"Code Project Demo - by Michael Haephrati",
L"What is your name",
L"My name is Michael");
wprintf(L"User entered '%s'\n", result);
}
如何做...
在我的各种文章中,我总是试图包含一些有用的代码,这些代码可以用于除本文范围以外的许多用途。
对齐文本
我编写了 setTextAlignment()
函数,目的是对齐文本。我将它放在我的 *utils.cpp* 文件中,因为建议将任何辅助函数放在一组 *utils.cpp* / *utils.h* 源文件中,这些源文件可以被其他项目使用。
void setTextAlignment(HWND hwnd,int intTextAlignment)
{
LONG_PTR s;
LONG_PTR textalignment = GetWindowLongPtr(hwnd, GWL_STYLE);
if (textalignment != intTextAlignment)
{
//delete the last text alignment
if (intTextAlignment == 0)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s & ~(SS_LEFT);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
else if (intTextAlignment == 1)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s & ~(SS_CENTER);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
else if (intTextAlignment == 2)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s & ~(SS_RIGHT);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
textalignment = intTextAlignment;
//put the new text alignment
if (textalignment == 0)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s | (SS_LEFT);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
else if (textalignment == 1)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s | (SS_CENTER);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
else if (textalignment == 2)
{
s = GetWindowLongPtr(hwnd, GWL_STYLE);
s = s | (SS_RIGHT);
SetWindowLongPtr(hwnd, GWL_STYLE, (LONG_PTR)s);
}
SetWindowPos(hwnd, 0, 0, 0, 0, 0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE |
SWP_NOCOPYBITS | SWP_DRAWFRAME);
}
}
设置默认按钮
我们希望 确认 按钮显示为默认按钮,表明如果用户按下 ENTER 键,就好像他/她按下了该按钮。为此,我们使用以下代码
// Set default button
SendMessage((HWND)m_hWndOK, BM_SETSTYLE,
(WPARAM)LOWORD(BS_DEFPUSHBUTTON), MAKELPARAM(TRUE, 0));
SendMessage((HWND)m_hWndCancel, BM_SETSTYLE,
(WPARAM)LOWORD(BS_PUSHBUTTON), MAKELPARAM(TRUE, 0));
设置背景色和前景色
首先,我选择了一个漂亮的背景颜色,并将其定义一次,以便以后可以在一个或多个地方使用它
#define SOFT_BLUE RGB(206,214,240)
然后我定义了一个画笔
HBRUSH SG_InputBox::hbrBkgnd = NULL;
然后,在我们的对话框的 Callback
函数中
LRESULT CALLBACK SG_InputBox::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
我们处理WM_CTLCOLORSTATIC 消息
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
if (hbrBkgnd == NULL)
{
hbrBkgnd = CreateSolidBrush(SOFT_BLUE);
}
SetTextColor(hdcStatic, RGB(0, 0, 0));
SetBkColor(hdcStatic, SOFT_BLUE);
return (INT_PTR)hbrBkgnd;
}
break;
设置默认文本并选择它
// Set default text
SendMessage(m_hWndEdit, EM_SETSEL, 0, -1);
SendMessage(m_hWndEdit, EM_REPLACESEL, 0, (LPARAM)szDefaultText);
SendMessage(m_hWndEdit, EM_SETSEL, 0, -1);
SetFocus(m_hWndEdit);
处理错误
当窗口的任何元素或窗口(对话框)本身的创建失败时,我们调用 REPORT_ERROR
。这实际上是我创建的一个 MACRO
#define REPORTERROR ReportError(__FUNCTION__)
然后,实际的 ReportError()
函数将其参数作为发生错误的函数的名称,这很有用。 ReportError()
函数可以扩展为记录任何 “wprintf
”,这样您就可以随时检查日志文件。
//
// void ReportError(const char *CallingFunction)
{
DWORD error = GetLastError();
LPVOID lpMsgBuf;
DWORD bufLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
wprintf(L"%S: Error '%s'\n", CallingFunction,(wchar_t *)lpMsgBuf);
}
//
延伸阅读
- 对话框:https://docs.microsoft.com/en-us/windows/desktop/dlgbox/using-dialog-boxes
- 使用画笔:https://docs.microsoft.com/en-us/windows/desktop/gdi/using-brushes
- 处理
WM_CTLCOLORSTATIC
消息:https://docs.microsoft.com/en-us/windows/desktop/controls/wm-ctlcolorstatic - Visual Studio 解决方案 (.sln):https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019
历史
- 2019 年 6 月 12 日:初始版本