65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (14投票s)

2019 年 6 月 12 日

CPOL

4分钟阅读

viewsIcon

39684

downloadIcon

731

一个简单易用的 InputBox() 函数,适用于任何类型的 Windows C++ 程序

引言

在大多数编程语言中,都有一些构建模块,它们使编程变得更容易。例如,弹出消息的能力。在 Win32 中,这将是 MessageBox()。另一个构建模块是 InputboxInputBox() 是一个非常方便的命令,用于提示用户输入。您可以在 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);
}
//

延伸阅读

历史

  • 2019 年 6 月 12 日:初始版本
© . All rights reserved.