【问题标题】:(C++) MessageBox for Linux like in MS Windows(C++) 适用于 Linux 的 MessageBox,例如 MS Windows
【发布时间】:2010-11-25 22:17:25
【问题描述】:

我需要为 Linux (SDL) 应用程序实现一个简单的图形消息框,类似于 C++ 中的 Windows MessageBox (gcc/g++ 4.4.0)。它所要做的就是显示一个标题、一条消息和一个确定或关闭按钮,并在单击该按钮时返回调用函数。

SDL 只是使用 X(11) 打开一个窗口进行 (OpenGL) 渲染。

我查看了有关 GTK 实现的类似线程,但该实现似乎无法正常工作。

我也尝试过 wxWidgets 的 wxMessageBox 函数,但是编译头文件会使编译器在 include/c++/4.4.0/bits/stl_algobase.h 中抛出有关语法错误的错误消息(gcc 4.4.0 32 bits on openSuSE 11.1 32位)。使用 wxWidgets 还意味着必须链接大量库,将 STL 添加到我的应用程序(否则它不需要)以及谁知道还有什么,所以我不想使用 wxWidgets。

X11/motif (openmotif) 有我需要的东西 (XmCreate{Error|Warning|InfoDialog),但是这些需要我没有的父小部件(例如顶级窗口),并且不接受这些的 NULL 参数.

所以我现在很难过。有没有一种简单的方法可以做我想做的事?或者至少是一个简单/容易/直接的一半?如果是,那是哪一个(我们将不胜感激提供尽可能多的细节)。

【问题讨论】:

    标签: c++ linux wxwidgets x11 messagebox


    【解决方案1】:

    在 SDL2 中,您现在可以显示消息框:

    http://wiki.libsdl.org/SDL_ShowSimpleMessageBox

    int SDL_ShowSimpleMessageBox(Uint32      flags,
                                 const char* title,
                                 const char* message,
                                 SDL_Window* window)
    

    http://wiki.libsdl.org/SDL_ShowMessageBox

    int SDL_ShowMessageBox(const SDL_MessageBoxData* messageboxdata,
                           int*                      buttonid)
    

    【讨论】:

      【解决方案2】:

      我个人使用Qt4的QMessageBox

      示例:

      QMessageBox mb(QMessageBox::Question, "Title", "Message",  QMessageBox::Ok | QMessageBox::Cancel);
      if(mb.exec() == QMessageBox::Ok) { do_stuff(); }
      

      【讨论】:

      • 谢谢。请问Qt4库的名字是什么(-l)?
      • @karx11erx:Qt 不仅仅是一个小型库,它还是一个完整的跨平台 GUI(以及更多)解决方案。使用它需要的不仅仅是链接到特定的库。通常最好整体使用他们的构建系统。 Qt 通常是“全有或全无”的选择。
      • 使用 Qt4 让 gcc 4.4.0 给我抛出了很多错误,而且我不需要在我的应用程序之上添加一个庞然大物。
      • 好吧,与不使用相比,大多数 GUI 工具包都将成为“庞然大物”(想想 Win32 有多大!)。这些错误几乎可以肯定是由于没有正确使用 Qt 构建系统。
      【解决方案3】:

      看起来您必须创建一个顶级 X11/Motif 窗口。以下是一些帮助您入门的代码:

      #include <Xm/Xm.h> 
      #include <Xm/PushB.h>
      
      /* Prototype Callback function */
      
      void pushed_fn(Widget , XtPointer , 
                     XmPushButtonCallbackStruct *);
      
      
      main(int argc, char **argv) 
      
      {   Widget top_wid, button;
          XtAppContext  app;
      
          top_wid = XtVaAppInitialize(&app, "Push", NULL, 0,
              &argc, argv, NULL, NULL);
      
          button = XmCreatePushButton(top_wid, "Push_me", NULL, 0);
      
          /* tell Xt to manage button */
                      XtManageChild(button);
      
                      /* attach fn to widget */
          XtAddCallback(button, XmNactivateCallback, pushed_fn, NULL);
      
          XtRealizeWidget(top_wid); /* display widget hierarchy */
          XtAppMainLoop(app); /* enter processing loop */ 
      
      }
      
      void pushed_fn(Widget w, XtPointer client_data, 
                     XmPushButtonCallbackStruct *cbs) 
        {   
           printf("Don't Push Me!!\n");
        }
      

      这是从here 复制而来的,这可能会给您更多关于此的指示。

      【讨论】:

      • SDL 显然是在为 OpenGL 渲染创建一个顶级窗口——我在最初的问题中提到了这一点。除了修改 SDL 之外,没有其他方法可以获取它的句柄。
      • 其实我只需要让 X(11) 为我显示这样一个窗口,但是从我在 inet 上找到的关于这个编程的内容来看,X 中的任何东西都不是微不足道的。跨度>
      • 是否可以从 SDL 的 X11 窗口句柄创建 Motif Widget?
      • 好像是这样,但我真的不知道。您是否尝试将 X11 窗口句柄传递给 Message Box 函数?似乎这样会起作用。
      • 如何从程序内部终止 XtAppMainLoop,或者在用户单击我的消息框的确定按钮后使其终止?
      【解决方案4】:

      这是我的解决方案。我选择使用 Motif (OpenMotif),因为它需要相对较少的额外库(Xm、Xt、X11)。根据消息大小,我的实现会打开一个简单的消息框或更复杂的对话框,其中包含不可编辑、可滚动的文本(后者取自 Motif 程序员手册并适用于我的目的)。

      包括文件和全局数据:

      #include <Xm/Xm.h>
      #include <Xm/MwmUtil.h>
      #include <Xm/MainW.h>
      #include <Xm/CascadeB.h>
      #include <Xm/MessageB.h>
      #include <Xm/RowColumn.h>
      #include <Xm/Form.h>
      #include <Xm/PushBG.h>
      #include <Xm/LabelG.h>
      #include <Xm/PanedW.h>
      #include <Xm/Text.h>
      #include <Xm/DialogS.h>
      #include <Xm/Command.h>
      
      static XtAppContext appShell;
      

      帮助函数确定行数和最大值。短信的cols:

      static int MsgSize (char* pszMsg, int& nCols)
      {
      if (!(pszMsg && *pszMsg))
         return 0;
      int nRows = 1;
      nCols = 0;
      for (char* p = pszMsg; *p && (pszMsg = strchr (p, '\n')); nRows++, p = ++pszMsg) {
         if (nCols < pszMsg - p)
            nCols = pszMsg - p;
         }
      return nRows;
      }
      

      消息对话框关闭按钮的回调函数:

      void DestroyShell (Widget widget, XtPointer clientData, XtPointer callData)
      {
      Widget shell = (Widget) clientData;
      XtDestroyWidget (shell);
      // tell the application event loop to terminate w/o terminating the application
      XtAppSetExitFlag (appShell);
      }
      

      构建一个对话框,其中包含一个可滚动的、不可编辑的文本小部件和一个关闭按钮。取自 Motif 程序员手册并稍作修改(无图标,单个按钮),最小的窗口装饰)。

      void XmMessageDialog (const char* pszMsg, int nRows, int nCols, bool bError)
      {
          Widget       msgBox, pane, msgText, form, widget;
          void         DestroyShell(Widget, XtPointer, XtPointer);
          Arg          args [10];
          int          n = 0;
          int          i;
          Dimension    h;
      
      // Set up a DialogShell as a popup window. Set the delete window protocol response to XmDESTROY to make sure that
      // the window goes away appropriately. Otherwise, it's XmUNMAP which means it'd be lost forever, since we're not storing
      // the widget globally or statically to this function.
      Widget topWid = XtVaAppInitialize (&appShell, "D2X-XL", NULL, 0, &argc, argv, NULL, NULL);
      XtSetArg (args [0], XmNdeleteResponse, XmDESTROY);
      msgBox = XmCreateDialogShell (topWid, bError ? const_cast<char*>("Error") : const_cast<char*>("Warning"), args, 1);
      XtVaGetValues (msgBox, XmNmwmDecorations, &i, NULL);
      i &= ~(MWM_DECOR_ALL | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE | MWM_DECOR_MENU);
      XtVaSetValues (msgBox, XmNmwmDecorations, i, NULL);
      XtVaGetValues (msgBox, XmNmwmFunctions, &i, NULL);
      i &= ~(MWM_FUNC_ALL | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_CLOSE);
      XtVaSetValues (msgBox, XmNmwmFunctions, i, NULL);
      // Create a PanedWindow to manage the stuff in this dialog. PanedWindow won't let us set these to 0!
      XtSetArg (args [0], XmNsashWidth, 1);
      // Make small so user doesn't try to resize
      XtSetArg (args [1], XmNsashHeight, 1);
      pane = XmCreatePanedWindow (msgBox, const_cast<char*>("pane"), args, 2);
      // Create a RowColumn in the form for Label and Text widgets. This is the control area.
      form = XmCreateForm (pane, const_cast<char*>("form1"), NULL, 0);
      // prepare the text for display in the ScrolledText object we are about to create.
      n = 0;
      XtSetArg (args [n], XmNscrollVertical, True); n++;
      XtSetArg (args [n], XmNscrollHorizontal, False); n++;
      XtSetArg (args [n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
      XtSetArg (args [n], XmNeditable, False); n++;
      XtSetArg (args [n], XmNcursorPositionVisible, False); n++;
      XtSetArg (args [n], XmNwordWrap, True); n++;
      XtSetArg (args [n], XmNvalue, pszMsg); n++;
      XtSetArg (args [n], XmNrows, min (nRows, 30)); n++;
      XtSetArg (args [n], XmNcolumns, min (nCols, 120)); n++;
      msgText = XmCreateScrolledText (form, const_cast<char*>("help_text"), args, n);
      // Attachment values must be set on the Text widget's PARENT, the ScrolledWindow. This  is the object that is positioned.
      XtVaSetValues (XtParent (msgText),
                     XmNleftAttachment, XmATTACH_FORM,
                     XmNtopAttachment, XmATTACH_FORM,
                     XmNrightAttachment, XmATTACH_FORM,
                     XmNbottomAttachment, XmATTACH_FORM,
                     NULL);
      XtManageChild (msgText);
      XtManageChild (form);
      // Create another form to act as the action area for the dialog
      XtSetArg (args [0], XmNfractionBase, 5);
      form = XmCreateForm (pane, const_cast<char*>("form2"), args, 1);
      // The OK button is under the pane's separator and is attached to the left edge of the form. It spreads from
      // position 0 to 1 along the bottom (the form is split into 5 separate grids via XmNfractionBase upon creation).
      widget = XmCreatePushButtonGadget (form, const_cast<char*>("Close"), NULL, 0);
      XtVaSetValues (widget,
                     XmNtopAttachment, XmATTACH_FORM,
                     XmNbottomAttachment, XmATTACH_FORM,
                     XmNleftAttachment, XmATTACH_POSITION,
                     XmNleftPosition, 2,
                     XmNrightAttachment, XmATTACH_POSITION,
                     XmNrightPosition, 3,
                     XmNshowAsDefault, True,
                     XmNdefaultButtonShadowThickness, 1,
                     NULL);
      XtManageChild (widget);
      XtAddCallback (widget, XmNactivateCallback, DestroyShell, (XtPointer) msgBox);
      // Fix the action area pane to its current height -- never let it resize
      XtManageChild (form);
      XtVaGetValues (widget, XmNheight, &h, NULL);
      XtVaSetValues (form, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL);
      // This also pops up the dialog, as it is the child of a DialogShell
      XtManageChild (pane);
      }
      

      消息框'确定按钮的回调函数

      void XmCloseMsgBox (Widget w, XtPointer clientData, XtPointer callData)
      {
      XtAppSetExitFlag (appShell);
      }
      

      决定是使用简单消息框还是高级消息框,显示它们中的任何一个,并在用户单击其关闭/确定按钮时将其删除。

      void XmMessageBox (const char* pszMsg, bool bError)
      {
         Widget   topWid;
         int      nRows, nCols;
      
      nRows = MsgSize (const_cast<char*>(pszMsg), nCols);
      if ((nRows > 3) || (nCols > 360))
         XmMessageDialog (pszMsg, nRows, nCols, bError);
      else { // use the built-in message box
         topWid = XtVaAppInitialize (&appShell, "D2X-XL", NULL, 0, &argC, argv, NULL, NULL);
         // setup message box text
         Arg args [1];
         XmString xmString = XmStringCreateLocalized (const_cast<char*>(pszMsg));
         XtSetArg (args [0], XmNmessageString, xmString);
         // create and label message box
         Widget xMsgBox = bError
                          ? XmCreateErrorDialog (topWid, const_cast<char*>("Error"), args, 1)
                          : XmCreateWarningDialog (topWid, const_cast<char*>("Warning"), args, 1);
         // remove text resource
         XmStringFree (xmString);
         // remove help and cancel buttons
         XtUnmanageChild (XmMessageBoxGetChild (xMsgBox, XmDIALOG_CANCEL_BUTTON));
         XtUnmanageChild (XmMessageBoxGetChild (xMsgBox, XmDIALOG_HELP_BUTTON));
         // add callback to the "close" button that signals closing of the message box
         XtAddCallback (xMsgBox, XmNokCallback, XmCloseMsgBox, NULL);
         XtManageChild (xMsgBox);
         XtRealizeWidget (topWid);
         }
      XtAppMainLoop (appShell);
      XtUnrealizeWidget (topWid);
      XtDestroyApplicationContext (appShell);
      }
      

      【讨论】:

        【解决方案5】:

        我建议您研究支持 SDL 作为后端的 GUI 库之一。 GG 就是一个这样的库,它的类为ThreeButtonDlg。当它的 Run() 返回时,您可以查看它的 Result()。请参阅他们的 minimal 示例中的 Initial 方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-10-26
          • 2010-09-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多