除非首先创建,否则首先创建的对话框会变得无法响应?

时间:2010-04-29 03:05:06

标签: c++ winapi dialog

创建完全正常的初始对话框后,我在按下加入游戏按钮时创建另一个对话框。该对话框已创建并成功显示,但我无法键入编辑框甚至按下或退出对话框。有谁知道如何解决这个或为什么会发生?我确保通过从应用程序的主循环创建和显示对话框本身不是问题。当我以这种方式创建它时它工作正常。那么为什么从另一个对话框创建时会出错呢? 我的代码如下。

此代码用于每个对话框使用的DLGPROC函数。

#define WIN32_LEAN_AND_MEAN
#include "Windows.h"
#include ".\Controllers\Menu\MenuSystem.h"
#include ".\Controllers\Game Controller\GameManager.h"
#include ".\Controllers\Network\Network.h"
#include "resource.h"
#include "main.h"
using namespace std;
extern GameManager g;
extern bool men;
NET_Socket server;
extern HWND d;
HWND joinDlg;
char ip[64];

void JoinMenu(){
 joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), NULL, (DLGPROC)GameJoinDialogPrompt);
 SetFocus(joinDlg);
// ShowWindow(joinDlg, SW_SHOW);
 ShowWindow(d, SW_HIDE);
}
LRESULT CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
 switch(Message){
  case WM_COMMAND:{ 
   switch(LOWORD(wParam)){
    case IDCONNECT:{
      GetDlgItemText(joinDlg, IDC_IP, ip, 63);
      if(server.ConnectToServer(ip, 7890, NET_UDP) == NET_INVALID_SOCKET){
       LogString("Failed to connect to server! IP: %s", ip);
       MessageBox(NULL, "Failed to connect!", "Error", MB_OK);
       ShowWindow(joinDlg, SW_SHOW);
       break;
      }
       }
     LogString("Connected!");
     break;
    case IDCANCEL:
     ShowWindow(d, SW_SHOW);
     ShowWindow(joinDlg, SW_HIDE);
     break;
   }
   break;
  }
  case WM_CLOSE:
   PostQuitMessage(0);
   break;
 }
 return 0;
}
LRESULT CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
 switch(Message){
 case WM_PAINT:{
   PAINTSTRUCT ps;
   RECT rect;
   HDC hdc = GetDC(Dialogwindow);
      hdc = BeginPaint(Dialogwindow, &ps);
   GetClientRect (Dialogwindow, &rect);
   FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 0, 0)));
      EndPaint(Dialogwindow, &ps);
      break;
      }
  case WM_COMMAND:{
   switch(LOWORD(wParam)){
    case IDC_HOST:
     if(!NET_Initialize()){
      break;
     }
     if(server.CreateServer(7890, NET_UDP) != 0){
      MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
      PostQuitMessage(0);
      return -1;
     }
     ShowWindow(d, SW_HIDE);
     break;
    case IDC_JOIN:{
     JoinMenu();
     }
     break;
    case IDC_EXIT:
     PostQuitMessage(0);
     break;
    default:
     break;
   }
   break;
  }
 return 0;
 }
}

我使用以下代码调用第一个对话框

void EnterMenu(){
// joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), g_hWnd, (DLGPROC)GameJoinDialogPrompt);//
 d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU), g_hWnd, (DLGPROC)GameMainDialogPrompt);

}

默认情况下,对话框不是DISABLED,默认情况下它们是可见的。一切都设置为在创建时处于活动状态,并且没有代码停用对话框或对话框本身上的项目。

3 个答案:

答案 0 :(得分:2)

首先,确保为对话程序编写正确的签名:

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, 
                            WPARAM wParam, LPARAM lParam);

(见http://msdn.microsoft.com/en-us/library/ms645469(v=VS.85).aspx

因此,您的对话程序应如下所示:

INT_PTR CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
    { /* ... */ }
INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
    { /* ... */ }

然后你应该能够在没有警告或错误的情况下这样做:

void EnterMenu()
{     
    d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU),
                     g_hWnd, &GameMainDialogPrompt);
    // Note the ampersand. Also note that no cast is needed. You should
    // not need to use a cast to pass in the address of the function.
}     

请参阅http://blogs.msdn.com/oldnewthing/archive/2004/01/15/58973.aspx了解为什么正确使用函数签名非常重要。

话虽这么说,你的joinDlg应该是一个模态对话框,因为它要求用户提供信息:

void JoinMenu()
{
    // DialogBox() creates a modal dialog box. It "blocks" its owner until
    // it closes. On the other hand, CreateDialog() creates a non-modal
    // dialog box.
    joinDlg = DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO),
        d, &GameJoinDialogPrompt);
    // Again, note the ampersand and the lack of a cast when passing in
    // the address of the dialog procedure. Also, the main dialog box is
    // serving as the owner of this dialog box.
} 

另请注意,对话框过程与Windows过程不同,如果对话过程处理了消息TRUE,则它们会返回FALSETRUEFALSE。 。 (有一些“怪异”消息违反了这条规则,但你没有处理这些消息)

所以你的对话程序应该是这样的:

INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
                                      WPARAM wParam, LPARAM lParam)
{ 
    switch(Message)
    { 
    case WM_PAINT:
        /* Do painting */
        return TRUE; // We handled the paint message
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case IDC_HOST:
            /* Do command */
            return TRUE; // We handled this particular command.
        case IDC_JOIN:
            /* Do command */
            return TRUE; // We handled this particular command.
        case IDC_EXIT:
            /* Do command */
            return TRUE; // We handled this particular command.
        }
        return FALSE; // The command wasn't handled.
    }
    return FALSE; // The message wasn't handled.
} 

对话程序致电DefWindowProc(),也不返回0

答案 1 :(得分:0)

另外,对于其他优秀的帖子,你也在做愚蠢的事情:

if(server.CreateServer(7890, NET_UDP) != 0){
  MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
  PostQuitMessage(0);

在WM_COMMAND处理程序中。这是一段可怕的代码,因为它会停止对话框模态循环而不会禁用它,或者弹出消息框。

如果从不同的窗口(或对话框)消息中调用模态窗口,则必须禁用停顿的窗口。实际上,将Windows HWND传递给MessageBox调用。

答案 2 :(得分:0)

如果所有其他方法都失败了,请重新开始:

resource.h

#define IDD_DIALOG1                     101
#define IDD_DIALOG2                     102
#define ID_OPEN                         1001
#define ID_MESSAGE                      1002

在资源文件中:

#include <winres.h>
#include "resource.h"

IDD_DIALOG1 DIALOGEX 0, 0, 300, 200
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
    WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Main Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON "Open Secondary Dialog", ID_OPEN, 73 ,49, 133, 64
END

IDD_DIALOG2 DIALOGEX 0, 0, 200, 150
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
    WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Secondary Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON "Message Box", ID_MESSAGE, 50, 49, 88, 50
END

在源文件中:

#include <windows.h>
#include "resource.h"

INT_PTR CALLBACK SecondaryDialogProc(HWND hwnd, UINT msg,
                                     WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_INITDIALOG:
        return TRUE;
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_MESSAGE:
            // Show a message box. Note that we're passing in our own HWND into
            // the function, so we "block" this dialog box until the user
            // dismisses this message box.
            ::MessageBox(hwnd, "Hello World!", "Greetings", MB_OK);
            return TRUE;
        }
        return FALSE;
    case WM_CLOSE:
        // Because this is a modal dialog box (we used ::DialogBox()), we
        // use ::EndDialog() instead of ::DestroyWindow() to destroy this
        // dialog box.
        ::EndDialog(hwnd, 0);
        return TRUE;
    }
    return FALSE;
}

INT_PTR CALLBACK MainDialogProc(HWND hwnd, UINT msg,
                                WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_INITDIALOG:
        return TRUE;
    case WM_COMMAND:
        switch(LOWORD(wParam))
        {
        case ID_OPEN:
            // Open a modal dialog box. This will block the main dialog box
            // until the secondary dialog box is closed.
            ::DialogBox(::GetModuleHandle(NULL),
                MAKEINTRESOURCE(IDD_DIALOG2), hwnd, &SecondaryDialogProc);
            return TRUE;
        }
        return FALSE;
    case WM_CLOSE:
        // We close this dialog box with ::DestroyWindow(). This causes the
        // WM_DESTROY message to be sent.
        ::DestroyWindow(hwnd);
        return TRUE;
    case WM_DESTROY:
        // Since the main dialog box is being destroyed, we quit
        // the application.
        ::PostQuitMessage(0);
        return TRUE;
    }
    return FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nShowCmd)
{
    // Open a non-modal dialog box using ::CreateDialog().
    HWND mainDlg = ::CreateDialog(::GetModuleHandle(NULL),
        MAKEINTRESOURCE(IDD_DIALOG1), NULL, &MainDialogProc);
    // The first ::ShowWindow() call should use nShowCmd.
    ::ShowWindow(mainDlg, nShowCmd);

    MSG msg;
    while (::GetMessage(&msg, NULL, 0, 0) > 0)
    {
        // So our main dialog behaves properly.
        if(!::IsDialogMessage(mainDlg, &msg))
        {
            ::TranslateMessage( & msg );
            ::DispatchMessage( & msg );
        }
    }
    return msg.wParam;
}

在这里,这只是打开主对话框的简单代码,带有一个用于打开另一个对话框的按钮。看看这是否有效,然后添加您的业务逻辑。