用输入框提示用户? [C ++]

时间:2010-11-17 04:07:09

标签: c++ winapi inputbox

我的目标是只需使用弹出框询问用户输入。我搜索了很多,几乎所有的结果都说创建一个messageBox非常简单:

MessageBox (NULL, "Hello World" , "Hello", MB_OKCANCEL);

但是创建一个需要输入的弹出窗口更加复杂,并且没有直接的方法来实现它。我在谷歌上找到的所有结果都是在2001年到2005年的某个地方。我想我在这里问的是近年来是否有一些更直接的解决方案。

希望像Java一样好看和直接:

int number = JOptionPane.showInputDialog ("Enter an integer");

如果情况并非如此,我是否可以简要解释一下如何做到这一点?


编辑:我无法正常工作。 :(我最后编写代码来完成Java工作,然后编写一行C ++代码来调用.jar文件。: - /由于问题是时间敏感的,它总比没有好。

9 个答案:

答案 0 :(得分:7)

纯C ++没有类似的东西。基本上你要做的事情只能通过使用对操作系统的API调用或使用像Qt这样的GUI库来实现(我推荐它使得它更容易调用本机API而且它也是多平台的)

使用Qt,您可以显示输入对话框,就像在java上一样:

bool ok;
QString text = QInputDialog::getText(
        "MyApp 3000", "Enter your name:", QLineEdit::Normal,
        QString::null, &ok, this );
if ( ok && !text.isEmpty() ) {
    // user entered something and pressed OK
} else {
    // user entered nothing or pressed Cancel
}

您可以在此处下载Qt库:qt.nokia.com/products/developer-tools/

答案 1 :(得分:7)

如果您使用的是Visual C ++ Express,则可以使用许多可用于创建对话框的免费资源编辑器。 ResEdit是我找到的最好的之一。

您需要在添加到项目中的.RC文件中创建对话框资源。

然后,这是一个非常简单的调用DialogBox的情况 - 它将从资源文件中加载对话框并将其放在屏幕上。将通过许多通知调用传入的DialogProc。通常,您希望为所有内容返回FALSE,但将WM_INITDIALOG作为用文本初始化编辑控件的位置处理,并在单击按钮时发送WM_COMMAND。

答案 2 :(得分:3)

MessageBox一样,Microsoft不认为您的用例足够通用以进行优化。他们希望你能够在其上布置一个包含许多控件的对话框,可能与控件进行一些复杂的交互,并且只有在对话框完全填满后才会响应。你要求的只是简化版本。

资源编辑器是创建对话框的最简单方法,但它不包含在Visual Studio的免费Express版本中。您可以设计对话框,其中包含用于提示的文本控件和用于填写的用户的编辑控件。您将使用DialogBox Windows功能显示对话框,并在用户点击“确定”按钮或X时返回在对话框的角落里。 Microsoft为其提供了一些文档here

有一些平台可以尝试简化流程,例如MFC,WTL,Qt和wx,但这就是使用纯Windows API的方法。

答案 3 :(得分:1)

我必须承认,我在输入框的方式上并没有做太多的事情,但你基本上必须走出C ++以获得任何类型的图形输入框。出于可移植性的原因,对于那种类型的东西,根本就没有内置机制。我不记得它是否也适用于C ++,但C甚至不认为你有一个控制台。无论如何,你最好的选择是你已经尝试过的东西:Win32 API,Qt等。但是,如果你可以使用控制台,可以随意使用iostream库来完成工作。

答案 4 :(得分:1)

与Visual Basic和其他语言不同,在c ++中没有像命令那样的“内置”输入框。与可以直接调用的MessageBox不同,需要编写InputBox()。实际上,我已经这样做了。 The following article描述了如何将此类InputBox实现为小型静态库的一部分,该静态库可在没有资源的情况下从任何Win32 c ++程序使用。 Source code at Github。可以使用如下:

LPWSTR GetString(LPCTSTR szCaption, LPCTSTR szPrompt, LPCTSTR szDefaultText = L"");

例如:

LPWSTR result = SG_InputBox::GetString(
     L"Code Project Demo", 
     L"What is your name");

答案 5 :(得分:0)

使用控制台窗口更适合于通信模式,程序会提示用户,继续,再次提示用户,等等。

为此,您可以使用标准库的设施,例如cincout

答案 6 :(得分:0)

试试这个: InputBox in c++ vs2010

#include "stdafx.h"
#using <system.windows.forms.dll>
#using <Microsoft.VisualBasic.dll>

using namespace System;

int main(array<System::String ^> ^args)
{
    Microsoft::VisualBasic::Interaction::InputBox(L"Hello", L"Title", L"DefResp", 500, 500);
    return 0;
}

答案 7 :(得分:0)

我的回答基于Stephen Quan对How to load & call a VBScript function from within C++?的回答,增加了对UTF-8的全面支持,因为您可以从CPP文件中的代码注释中收集信息。与使用Microsoft脚本控件创建InputBox不同,可以在x86 x64可执行文件,库和控件中使用它。

“ inputbox.h”:

extern "C" char *InputBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");
extern "C" char *PasswordBox(char *Prompt, char *Title = (char *)"", char *Default = (char *)"");

“ inputbox.cpp”:

#include "inputbox.h"

// Windows API
#include <windows.h>

// VBScript InputBox
#include <atlbase.h>
#include <activscp.h>
#include <comdef.h>

// UTF-8 Support
#include <wchar.h>
#include <string>
#include <vector>

using std::string;
using std::vector;

typedef std::basic_string<wchar_t> tstring;

static tstring StringWiden(string Str)
{
    const size_t wchar_tCount = Str.size() + 1;

    vector<wchar_t> Buffer(wchar_tCount);

    return tstring{ Buffer.data(), (size_t)MultiByteToWideChar(CP_UTF8, 0, Str.c_str(), -1, Buffer.data(), wchar_tCount) };
}

static string StringShorten(tstring Str)
{
    int nBytes = (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), NULL, 0, NULL, NULL);

    vector<char> Buffer((size_t)nBytes);

    return string{ Buffer.data(), (size_t)WideCharToMultiByte(CP_UTF8, 0, Str.c_str(), (int)Str.length(), Buffer.data(), nBytes, NULL, NULL) };
}

static string StringReplaceAll(string Str, string SubStr, string NewStr)
{
    size_t Position = 0;
    const size_t SubLen = SubStr.length(), NewLen = NewStr.length();

    while ((Position = Str.find(SubStr, Position)) != string::npos)
    {
        Str.replace(Position, SubLen, NewStr);
        Position += NewLen;
    }

    return Str;
}

static string CPPNewLineToVBSNewLine(string NewLine)
{
    size_t Position = 0;

    while (Position < NewLine.length())
    {
        if (NewLine[Position] == '\n' || NewLine[Position] == '\r')
            NewLine.replace(Position, 2, "\" + vbNewLine + \"");

        Position += 1;
    }

    return NewLine;
}

class CSimpleScriptSite :
    public IActiveScriptSite,
    public IActiveScriptSiteWindow
{
public:
    CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { }

    // IUnknown

    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();
    STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);

    // IActiveScriptSite

    STDMETHOD(GetLCID)(LCID *plcid) { *plcid = 0; return S_OK; }
    STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) { return TYPE_E_ELEMENTNOTFOUND; }
    STDMETHOD(GetDocVersionString)(BSTR *pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; }
    STDMETHOD(OnScriptTerminate)(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) { return S_OK; }
    STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; }
    STDMETHOD(OnScriptError)(IActiveScriptError *pIActiveScriptError) { return S_OK; }
    STDMETHOD(OnEnterScript)(void) { return S_OK; }
    STDMETHOD(OnLeaveScript)(void) { return S_OK; }

    // IActiveScriptSiteWindow

    STDMETHOD(GetWindow)(HWND *phWnd) { *phWnd = m_hWnd; return S_OK; }
    STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; }

    // Miscellaneous

    STDMETHOD(SetWindow)(HWND hWnd) { m_hWnd = hWnd; return S_OK; }

public:
    LONG m_cRefCount;
    HWND m_hWnd;
};

STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef()
{
    return InterlockedIncrement(&m_cRefCount);
}

STDMETHODIMP_(ULONG) CSimpleScriptSite::Release()
{
    if (!InterlockedDecrement(&m_cRefCount))
    {
        delete this;
        return 0;
    }
    return m_cRefCount;
}

STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject)
{
    if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow)
    {
        *ppvObject = (IActiveScriptSiteWindow *)this;
        AddRef();
        return NOERROR;
    }
    if (riid == IID_IActiveScriptSite)
    {
        *ppvObject = (IActiveScriptSite *)this;
        AddRef();
        return NOERROR;
    }
    return E_NOINTERFACE;
}

static HHOOK hHook = 0;
static bool HideInput = false;

static LRESULT CALLBACK InputBoxProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode < HC_ACTION)
        return CallNextHookEx(hHook, nCode, wParam, lParam);

    if (nCode = HCBT_ACTIVATE)
    {
        if (HideInput == true)
        {
            HWND TextBox = FindWindowExA((HWND)wParam, NULL, "Edit", NULL);
            SendDlgItemMessage((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, '*', 0);
        }
    }

    if (nCode = HCBT_CREATEWND)
    {
        if (!(GetWindowLongPtr((HWND)wParam, GWL_STYLE) & WS_CHILD))
            SetWindowLongPtr((HWND)wParam, GWL_EXSTYLE, GetWindowLongPtr((HWND)wParam, GWL_EXSTYLE) | WS_EX_DLGMODALFRAME);
    }

    return CallNextHookEx(hHook, nCode, wParam, lParam);
}

static char *InputBoxHelper(char *Prompt, char *Title, char *Default)
{
    HRESULT hr = S_OK;
    hr = CoInitialize(NULL);

    // Initialize
    CSimpleScriptSite *pScriptSite = new CSimpleScriptSite();
    CComPtr<IActiveScript> spVBScript;
    CComPtr<IActiveScriptParse> spVBScriptParse;
    hr = spVBScript.CoCreateInstance(OLESTR("VBScript"));
    hr = spVBScript->SetScriptSite(pScriptSite);
    hr = spVBScript->QueryInterface(&spVBScriptParse);
    hr = spVBScriptParse->InitNew();

    // Replace quotes with double quotes
    string strPrompt = StringReplaceAll(Prompt, "\"", "\"\"");
    string strTitle = StringReplaceAll(Title, "\"", "\"\"");
    string strDefault = StringReplaceAll(Default, "\"", "\"\"");

    // Create evaluation string
    string Evaluation = "InputBox(\"" + strPrompt + "\", \"" + strTitle + "\", \"" + strDefault + "\")";
    Evaluation = CPPNewLineToVBSNewLine(Evaluation);
    tstring WideEval = StringWiden(Evaluation);

    // Run InpuBox
    CComVariant result;
    EXCEPINFO ei = {};

    DWORD ThreadID = GetCurrentThreadId();
    HINSTANCE ModHwnd = GetModuleHandle(NULL);
    hr = pScriptSite->SetWindow(GetAncestor(GetActiveWindow(), GA_ROOTOWNER));
    hHook = SetWindowsHookEx(WH_CBT, &InputBoxProc, ModHwnd, ThreadID);
    hr = spVBScriptParse->ParseScriptText(WideEval.c_str(), NULL, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, &result, &ei);
    UnhookWindowsHookEx(hHook);


    // Cleanup
    spVBScriptParse = NULL;
    spVBScript = NULL;
    pScriptSite->Release();
    pScriptSite = NULL;

    CoUninitialize();
    static string strResult;
    _bstr_t bstrResult = (_bstr_t)result;
    strResult = StringShorten((wchar_t *)bstrResult);
    return (char *)strResult.c_str();
}

char *InputBox(char *Prompt, char *Title, char *Default)
{
    HideInput = false;

    return InputBoxHelper(Prompt, Title, Default);
}

char *PasswordBox(char *Prompt, char *Title, char *Default)
{
    HideInput = true;

    return InputBoxHelper(Prompt, Title, Default);
}

创建上述两个文件,然后将它们添加到Visual Studio项目中。

在您想要输入或密码框功能的任何文件中(位于标题中),只需包含标题:

#include "inputbox.h"

// use functions here

我还摆脱了VBScript InputBox标题栏中的默认Windows应用程序图标,因为我见过的很多人都抱怨看到它在那里是多么的丑陋。

如果您有任何疑问,请告诉我。

答案 8 :(得分:0)

following article描述了如何将此类InputBox实施为小型静态库的一部分,该静态库可在没有资源的情况下从任何Win32 c ++程序使用。源代码位于Github