【问题标题】:Prompting a user with an input box? [C++]用输入框提示用户? [C++]
【发布时间】:2011-05-11 05:25:43
【问题描述】:

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

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

但是,创建一个接受输入的弹出窗口涉及更多内容,并且没有直接的方法来做到这一点。我在 Google 上找到的所有结果都是 2001 年到 2005 年的某个时间段。我想我在这里问的是近年来是否出现了一些更直接的解决方案。

希望能像 Java 那样简单直接:

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

如果不是这样,我能否简要说明如何操作?


编辑:我什么也做不了。 :( 我最终写了代码用 Java 完成这项工作,然后写了一行 C++ 代码来调用 .jar 文件。:-/ 由于这个问题是时间敏感的,所以总比没有好。

【问题讨论】:

  • tinyfiedialogs 提供了向任何 C 或 C++ 项目添加输入框的最简单方法。它是一个 C 文件(+header)。它还包括与其他语言的绑定。 sourceforge.net/projects/tinyfiledialogs(我是作者)

标签: c++ winapi inputbox


【解决方案1】:

如果您使用 Visual C++ Express,有许多免费的资源编辑器可用于创建对话框。 ResEdit 是我发现的更好的之一。

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

然后,调用DialogBox 是一个非常简单的例子——它会从你的资源文件中加载对话框并将其放置在屏幕上。传入的 DialogProc 将被调用并带有许多通知。通常,您希望对所有内容都返回 FALSE,但将 WM_INITDIALOG 处理为使用文本初始化编辑控件的地方,并且单击按钮时将发送 WM_COMMAND。

【讨论】:

    【解决方案2】:

    纯 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/

    【讨论】:

    • 我已经下载了SDK和VS2010插件;您知道将此功能添加到现有项目的最佳方法吗?
    【解决方案3】:

    Microsoft 认为您的用例不够普遍,无法针对 MessageBox 进行优化。他们希望您布置一个带有许多控件的对话框,可能与控件进行一些复杂的交互,并且仅在对话框完全填充后才响应。您所要求的只是其简化版本。

    资源编辑器是创建对话框的最简单方法,但它不包含在 Visual Studio 的免费 Express 版本中。您将设计带有用于提示的文本控件和供用户填写的编辑控件的对话框。您使用DialogBox Windows 函数呈现对话框,当用户点击 OK 按钮或对话框的一角。微软有一些文档here

    有一些平台试图让这个过程变得更容易,例如 MFC、WTL、Qt 和 wx,但这是使用纯 Windows API 的方式。

    【讨论】:

      【解决方案4】:

      我的回答基于 Stephen Quan 对How to load & call a VBScript function from within C++? 的回答添加了完整的 UTF-8 支持,您可以从 CPP 文件中的代码 cmets 中收集。与使用 Microsoft Script Control 创建 InputBox 不同,这可用于 x86 x64 可执行文件、库和控件。

      “输入框.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 *)"");
      

      “输入框.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::wstring;
      using std::vector;
      
      static wstring StringWiden(string Str) {
        const size_t wchar_tCount = Str.size() + 1;
        vector<wchar_t> Buffer(wchar_tCount);
        return wstring { Buffer.data(), (size_t)MultiByteToWideChar(CP_UTF8, 0, Str.c_str(), -1, Buffer.data(), wchar_tCount) };
      }
      
      static string StringShorten(wstring 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] == '\r' || NewLine[Position] == '\n')
            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);
            SendDlgItemMessageW((HWND)wParam, GetDlgCtrlID(TextBox), EM_SETPASSWORDCHAR, L'\x25cf', 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) {
        // Initialize
        HRESULT hr = S_OK;
        hr = CoInitialize(NULL);
        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);
        wstring 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();
      
        // Result
        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 输入框标题栏中默认的 Windows 应用程序图标,因为我见过很多人抱怨在那里看到它有多难看。

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

      【讨论】:

      • 我知道这是旧的,但在这个例子中,出于某种原因,按下“f”键会使程序变砖。我将代码放入了一个名为函数的全新项目中,输入了“asdf”,但“f”从未出现,我不得不终止调试器并重新运行
      • @P-Squiddy 挺有意思的,今天晚些时候有时间我会尽力调查这个问题
      • @P-Squiddy 我似乎无法重现这一点。试试这个示例程序,看看它是否仍然为您工作:github.com/time-killer-games/Visual-CPP-InputBox(该 exe 至少需要传递一个参数)。
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        为此,您可以使用标准库的工具,例如 cincout

        【讨论】:

        • 通常我会,但我正在使用一个不容易实现的预先存在的代码库。
        【解决方案7】:

        与 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");
        

        【讨论】:

        • 太好了。易于使用。
        【解决方案8】:

        试试这个: 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;
        }
        

        【讨论】:

        • 这需要安装 Microsoft .NET 运行时。您可能应该在这里提到这一点。
        猜你喜欢
        • 1970-01-01
        • 2019-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多