• Advertisement
Sign in to follow this  

DirectX and Dialog Windows

This topic is 4341 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a very frustrating problem with my dialog windows when using them in conjunction with a directx client area. Here is what i have: Master Item List Dialog The "Master Item List" (on the left) Dialog is a child of the DirectX client area window and works fine except for the one problem. if i click on an item from the list or the window itself, the directx client area appears to loose focus (as it should) but the mouse click is still processed by the DirectX window and it and adds an object to the map behind the dialog window. However: Edit Item Dialog When i edit an item in the master item list (which calls up a child dialog of the master item list dialog called "Edit Item"), clicking does not affect the directx client area- which is what i want for both this dialog window AND the master item list dialog window. Both Dialogs have the same properties except for their parenting. I am using direct input for the mouse/keyboard.

Share this post


Link to post
Share on other sites
Advertisement
well, they are both responding to the same msgs. can't u just say "if dlg is open && they click in the dlg, 3d ignore" ?

-programmer_tom

Share this post


Link to post
Share on other sites
Quote:
Original post by programmer_tom
well, they are both responding to the same msgs. can't u just say "if dlg is open && they click in the dlg, 3d ignore" ?

-programmer_tom


That should be the solution.

Share this post


Link to post
Share on other sites
I considered that, however i get the same problem with the menu at the top too, so i couldnt check if the mouse was in that menu with a box like i could for the dialog windows becuase when they drop down they overlap the directx client area as well.

The dialog windows and the client area are not using the same window proc but are using the same message proc.

the co-operartive level for the direct input device is set to DISCL_FOREGROUND | DISCL_NONEXCLUSIVE (default).

Im less experienced with window programming than directx itself, so any help would be great.

Share this post


Link to post
Share on other sites
I think i have solved this, i am kind of doing what you said programmer_tom. I didnt realise there was a WM_MOUSEMOVE case that says wether the mouse is over a window or not, i was reluctant to do it with a bounding box as i have seen in an example i read. So now all i do is check if that case is true and only allow the user to edit the map if the mouse isnt over the dialog window.

Share this post


Link to post
Share on other sites
You are using IsDialogMessage() in your window loop, aren't you? It should look something like:

while(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if(IsDialogMessage(hWndDialog, &msg))
continue;

TranslateMessage(&msg);
DispatchMessage(&msg);
}

Share this post


Link to post
Share on other sites

void Application::messageLoop()
{
MSG Msg;
// Enter the message pump
ZeroMemory(&Msg, sizeof(MSG));
while(Msg.message != WM_QUIT)
{
// Handle Windows messages (if any)
if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {

if(IsDialogMessage(dlgHWnd, &Msg))
{
clientAreaFocus = false;
OutputDebugString("IN CLIENT AREA \n");
MessageBeep(2);
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

else
{
clientAreaFocus = true;
OutputDebugString("IN DIALOG \n");
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

} else {
// Do per-frame processing, break on FALSE return value
if(frame() == FALSE)
break;
}
}




Evil Steve - I tried your method and the WM_MOUSEMOVE and both have a similar result. They are not accurate enough for some reaon. as you can see it outputs "IN CLIENT AREA" or "IN DIALOG" depending on if the message is for the client area or the dialog window. However it somehow isnt very accurate. and the initial problem still occurs. (it should only edit the map when clientAreaFocus = false)

Share this post


Link to post
Share on other sites
You shouldn't call TranslateMessage or DispatchMessage if IsDialogMessage returns non-zero.

I don't think this is a DirectX problem if that helps narrow it down at all. DirectX doesn't care about client areas really, Windows will send the messages to where they're supposed to go.

Share this post


Link to post
Share on other sites
Thanks for helping. I changed it as you said:


void Application::messageLoop()
{
MSG Msg;
// Enter the message pump
ZeroMemory(&Msg, sizeof(MSG));
while(Msg.message != WM_QUIT)
{
// Handle Windows messages (if any)
if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {

if(IsDialogMessage(dlgHWnd, &Msg))
{
clientAreaFocus = false;
OutputDebugString("IN DIALOG\n");
continue;
}

else
{
clientAreaFocus = true;
OutputDebugString("IN CLIENT AREA \n");
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

} else {
// Do per-frame processing, break on FALSE return value
if(frame() == FALSE)
break;
}
}
}



but holding the mouse over the dialog box i still get a strange result:

IN DIALOG
IN DIALOG
IN DIALOG
IN DIALOG
IN DIALOG
IN DIALOG
IN DIALOG
IN DIALOG
IN CLIENT AREA
IN DIALOG
IN CLIENT AREA
IN CLIENT AREA
IN CLIENT AREA
IN CLIENT AREA
IN CLIENT AREA
IN DIALOG
IN CLIENT AREA
IN DIALOG
IN DIALOG

and so on.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Instead of continue try return 0; to let windows know you have handled this message(s).

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Instead of continue try return 0; to let windows know you have handled this message(s).
That's only within the message procedure, not in the message pump.

I can't see anything wrong with that code. Could we see your window message proc?

Share this post


Link to post
Share on other sites
I made the map editor and the item list componenets as seperate projects to beigin with and then merged them.

The Main.cpp makes the Master Item List (MIL) window and tells the mapEditor class to construct its own window (mapEditor.initialiseWindows()). Here is the message loops for the master item list which also calls those for the map editor:


////////////////////////////////////////////////////////
// MASTER ITEM LIST
////////////////////////////////////////////////////////

#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include "MILEdit.h"
#include "MapEditor.h"
#include "MILResource.h"
#include "MapICSResource.h"
#include "Item.h"
#include <windows.h>

// Application prototypes ///////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow);
long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK ModifyDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK About(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

OPENFILENAME g_ofn; // Open/Save dialog data
char g_szClass[64]; // Class name
long selecteditem = -1;

//HWND g_hWnd; // Window handle
HWND dialogHWND;
MILEdit milEdit(dialogHWND);
MapEditor mapEditor;
// Application //////////////////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
{
WNDCLASS wc;

strcpy(g_szClass,"MILEDIT");

// Register window class
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = (LPCSTR)ID_MAINFRAME;
wc.lpszClassName = g_szClass;
RegisterClass(&wc);

mapEditor.initialiseWindows(); \\ TESLLS THE MAP EDITOR TO MAKE ITS WINDOW
// Create the dialog box window and show it
dialogHWND = CreateDialog(hInst, MAKEINTRESOURCE(IDD_EDIT), mapEditor.hWnd, NULL);


UpdateWindow(dialogHWND);
ShowWindow(dialogHWND, nCmdShow);
milEdit.g_hWnd = dialogHWND;

// Force a load of items from default.csv
strcpy(milEdit.g_MILFile, "..\\Data\\Default.csv");
milEdit.LoadItems(milEdit.g_MILFile);
mapEditor.setMIL(milEdit.g_Items);
mapEditor.setDialog(dialogHWND);

// Clean up
//UnregisterClass(g_szClass, hInst);

return mapEditor.loop(); \\ TELLS THE MAP EDITOR TO LOOP
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int wmId;


switch(uMsg)
{

break;

case WM_COMMAND:
{
wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{

case MIL_FILE_EXIT:
{
if(MessageBox(NULL,"un-saved Items will be lost","Warning",1) == TRUE)
{
DestroyWindow(dialogHWND);
}
}
break;

case MIL_ITEM_ADD:
{
milEdit.addBlankItem(dialogHWND);
}
break;

case MIL_ITEM_CLEAR:
{
if(milEdit.clearItem(dialogHWND) == TRUE)
{
milEdit.updateItemList(dialogHWND);
mapEditor.removeItembyNum(selecteditem);
milEdit.Save();
mapEditor.update();

}
}
break;

case MIL_ITEM_EDIT:
{
milEdit.editItem(dialogHWND, ModifyDialogProc);
milEdit.updateItemList(dialogHWND);
}
break;

case MIL_HELP_ABOUT:
{
DialogBox(NULL, (LPCTSTR)IDD_ABOUTBOX, dialogHWND, (DLGPROC)About);
break;
}
break;
case MIL_FILE_SAVE_AS:
{
milEdit.SaveMILAS(milEdit.g_MILFile, &g_ofn);
}
break;

case MIL_FILE_OPEN:
{
milEdit.LoadMIL(milEdit.g_MILFile, &g_ofn);
}
break;

case MIL_FILE_NEW:
{
milEdit.NewMIL();
}
}

switch(LOWORD(wParam))
{
// New blank MIL Item
case IDC_ADD:
{
milEdit.addBlankItem(dialogHWND);
}
break;

// Edit an entry
case IDC_ITEMS:
{
if(HIWORD(wParam) == LBN_DBLCLK)
{
milEdit.editItem(dialogHWND, ModifyDialogProc);
milEdit.updateItemList(dialogHWND);
}
selecteditem = SendMessage(GetDlgItem(dialogHWND, IDC_ITEMS), LB_GETCURSEL, 0, 0);
if(selecteditem != -1 && milEdit.numitems > 0)
{
mapEditor.ItemNum = selecteditem;
}

}
break;

case IDC_EDIT:
{
milEdit.editItem(dialogHWND, ModifyDialogProc);
milEdit.updateItemList(dialogHWND);
}

// Clear an entry
case IDC_CLEAR:
{
if(milEdit.clearItem(dialogHWND) == TRUE)
{
milEdit.updateItemList(dialogHWND);
milEdit.Save();
mapEditor.update();
}
}
break;
}
break;
}

case WM_CREATE:
{
// Initialize the save/load dialog box info
ZeroMemory(&g_ofn, sizeof(OPENFILENAME));
g_ofn.lStructSize = sizeof(OPENFILENAME);
g_ofn.nMaxFile = MAX_PATH;
g_ofn.nMaxFileTitle = MAX_PATH;
g_ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT;

}
break;

case WM_DESTROY:
{
PostQuitMessage(0);
}
break;

default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
{
return 0;
}
break;
}

}

BOOL CALLBACK ModifyDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{

switch(uMsg)
{
case WM_INITDIALOG:
{
return milEdit.InitialiseDialogue(hWnd);

case WM_COMMAND:
switch(LOWORD(wParam))
{

case IDC_OK:
{
if (milEdit.UpdateEntry(hWnd, milEdit.g_EditItem) == TRUE)
{
EndDialog(hWnd, FALSE);
}
milEdit.updateItemList(hWnd);
milEdit.Save();
mapEditor.update();

return TRUE;
}
break;

case IDC_CANCEL:
{
milEdit.DisableAllDlg(hWnd);
EndDialog(hWnd, FALSE);
return TRUE;
}
break;

case IDC_CATEGORY:
{
if(HIWORD(wParam) ==TRUE)// LBN_DBLCLK)
{
milEdit.UpdateDialogue(hWnd);
}
return TRUE;
}
break;
}
}
break;
}
return FALSE;
}

// Message handler for about box.
LRESULT CALLBACK About(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK) {
EndDialog(hWnd, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}





The MapEditor class is the child of a more general Application class. The application class has the functions initialiseWindows and Loop(which makes the client area window and is called in the code above /\):

InitialiseWindows:

OOL Application::initialiseWindows()
{
// Save instance handle
pApplication = this;


// Get the instance handle
hInst = GetModuleHandle(NULL);

// Set a default window class and caption
strcpy(m_Class, "LogicEngine");
if(Caption == NULL)
strcpy(Caption, "Logic Game Engine");

// Set default window style, position, width, height
winStyle = WS_OVERLAPPEDWINDOW;
winXPos = 0;
winYPos = 0;

// Set default WNDCLASSEX structure
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_CLASSDC;
wcex.lpfnWndProc = AppWindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = MenuName;
wcex.lpszClassName = m_Class;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);


// Register window class
if(!RegisterClassEx(&wcex))
return FALSE;

// Create the Main Window
hWnd = CreateWindow(m_Class, Caption,
winStyle,
winXPos, winYPos,
screenWidth, screenHeight,
NULL, NULL, hInst, NULL);


if(!hWnd)
return FALSE;

}





Loop:


BOOL Application::loop()
{

#ifdef _XBOX

base = Base::Instance();
if(! base->intitailise())
{
return FALSE;
}

if(initialise() == TRUE)
{
while(frame())
{
}
}
shutdown();

#elif _WIN32


#ifdef _XBOX
#elif _WIN32

#endif

// Create the base
base = Base::Instance();

initialiseWindows();

if(! base->intitailise(hWnd,hInst,screenWidth,screenHeight))
{
return FALSE;
}

// Make sure client area is correct size
setWindowSize(screenWidth, screenHeight);

// Show and update the window
ShowWindow(hWnd, SW_NORMAL);
UpdateWindow(hWnd);

// Initialize COM
CoInitialize(NULL);

if(initialise() == TRUE) {
// Enter the message pump
messageLoop();
}

shutdown();

//Destroy the Base
base->DestroyInstance();

// Shutdown COM
CoUninitialize();

// Unregister the window class
UnregisterClass(m_Class, hInst);
#endif

return TRUE;
}





The Applications window message loop (inherited by the mapeditor) is what we were discussing before:


void Application::messageLoop()
{
MSG Msg;
// Enter the message pump
ZeroMemory(&Msg, sizeof(MSG));
while(Msg.message != WM_QUIT)
{
// Handle Windows messages (if any)
if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {

if(IsDialogMessage(dlgHWnd, &Msg))
{
clientAreaFocus = false;
OutputDebugString("IN DIALOG\n");
continue;
}

else
{
clientAreaFocus = true;
OutputDebugString("IN CLIENT AREA \n");
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

} else {
// Do per-frame processing, break on FALSE return value
if(frame() == FALSE)
break;
}
}
}






The Map Editors class overwrites the applications general message proc with its more specific one:


FAR PASCAL MapEditor::MsgProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
int wmId;

switch(umsg)
{
break;

case WM_COMMAND:
{
wmId = LOWORD(wparam);
// Parse the menu selections:
switch (wmId)
{

case MapICS_FILE_OPEN:
{
LoadMap("..\\Data\\Maps\\City1\\City1.map");
}
break;

case MapICS_FILE_EXIT:
{
PostQuitMessage(0);
return 0;
}
break;

case MapICS_FILE_SAVE_AS:
{
SaveMap();
return 0;
}
break;

/*case MapICS_FILE_CLEAR:
{
clearScene();
return 0;
}
break;*/


case MapICS_VIEW_GRID:
{
map->showGrid = !map->showGrid;
return 0;
}
break;

case MapICS_VIEW_WIREFRAME:
{
wireframe= !wireframe;
return 0;
}
break;
}
break;
}
default:
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}





Sorry to chuck so much code on here, but its needed if you want the whole picture.

Share this post


Link to post
Share on other sites
The only problems I can see immediately are MapEditor::MsgProc and WindowProc return undefined values if you process a message, there's no return FALSE; at the end of the function. What compiler are you using? I'm amazed that it didn't catch that error...

Share this post


Link to post
Share on other sites
Quote:
Original post by michaelbeirne
Im using Visual Studio .NET 2003 (7.1). Why would there be a "return FALSE;" if the functions are void?
They're not void:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
And:
FAR PASCAL MapEditor::MsgProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) (No return type implies int, but should generate a warning)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement