NO

Author Topic: Tabbed dialogs and its controls.  (Read 8136 times)

PauloH

  • Guest
Tabbed dialogs and its controls.
« on: June 30, 2009, 01:59:56 AM »
Hello,

I started to play with tabbed dialogs and I have a problem. When I press the tab key on my keyboard, the selected controls are just the tab title and the "Cancel" button, this one from the main dialog. I would like to change this behaviour and be able to select buttons or edit controls within current dialog. What is wrong with my program?
The source is attached .

Thanks in advance,

PauloH.
« Last Edit: June 30, 2009, 02:10:55 AM by PauloH »

nicolas.sitbon

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #1 on: June 30, 2009, 12:37:42 PM »
Code: [Select]
iResult = DialogBox(hInstance, TEXT("MainDialog"), NULL, (DLGPROC) MainDlgProc);You don't need to cast MainDlgProc, you need to learn C programming rules:
Quote
The DLGPROC type defines a pointer to this callback function. DialogProc is a placeholder for the application-defined function name.
Code: [Select]
INT_PTR CALLBACK DialogProc(     
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
);
http://blogs.msdn.com/oldnewthing/archive/2004/01/15/58973.aspx

MsgErr() function isn't TCHAR correct.
ELEMS can be replaced by _countof macro
NTABS should be defined like this:
Code: [Select]
enum nTabDialogs {TAB1, TAB2, NTABS};you don't need to repeat function's prototype, it is error prone, instead, put functions before main.

nicolas.sitbon

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #2 on: June 30, 2009, 02:11:17 PM »
this version corrects the errors I mentioned but not your problem:
Code: [Select]
#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <commctrl.h>
#include "res.h"

#define DLGLEN 20

#ifndef _countof /* not defined by Pelles C */
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#endif

enum nTabDialogs
{
#define ITEM(x) x,
#include "tab.h"
#undef ITEM
   NTABS
};

static HWND hTab = NULL; // Handle to tab control.
static HWND hTabDlg[NTABS] = {0}; // Array of handle to tab dialogs.

static TCHAR szTabDialogs [][DLGLEN] = // Tab title.
{
#define ITEM(x) _T(#x),
#include "tab.h"
#undef ITEM
};

static inline void MsgErr(LPCTSTR lpErrMessage)
{
   MessageBox(NULL, lpErrMessage, _T("Error"), MB_OK);
}

static INT_PTR OnCommand(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
   switch (LOWORD(wParam))
   {
      case IDCANCEL:
         SendMessage(hDlg, WM_CLOSE, 0, 0);
         return TRUE;
      case IDOK:
         MsgErr(_T("LISTAGEM CERTA"));
         return TRUE;
      default:
         return FALSE;
   }
}

static INT_PTR CALLBACK Tab1_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   static TCHAR szBuffer[MAX_PATH];

   switch(uMsg)
   {
      case WM_COMMAND:
         if(HIWORD(wParam) == BN_CLICKED)
         {
            switch(LOWORD(wParam))
            {
               case IDC_BTN_TAB1_GET:
                  GetWindowText(GetDlgItem(hTabDlg[TAB1], IDC_EDT1), szBuffer, _countof(szBuffer));
                  break;
               case IDC_BTN_TAB1_SHOWMESSAGE:
                  SendMessage(hTabDlg[TAB1], WM_COMMAND, MAKEWPARAM(IDC_BTN_TAB1_GET, BN_CLICKED),
                              (LPARAM)GetDlgItem(hTabDlg[TAB1], IDC_EDT1));

                  if(szBuffer[0] == '\0')
                  {
                     break;
                  }

                  MessageBox(NULL, szBuffer, _T("Hello!"), MB_OK);
            }
         }

         return TRUE;

      case WM_INITDIALOG:
         ZeroMemory(szBuffer, sizeof szBuffer);
         return TRUE;

      default:
         return FALSE;

   }
}

static INT_PTR CALLBACK Tab2_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
      case WM_COMMAND: /* fall through */
      case WM_INITDIALOG:
         return TRUE;
      default:
         return FALSE;
   }
}

static INT_PTR OnInitMainDialog(HWND hDlg, HINSTANCE l_Inst)
{
   TCITEM tci =
   {
      .mask       = TCIF_TEXT,
      .iImage     = -1,
      .pszText    = szTabDialogs[TAB1],
      .cchTextMax = _countof(szTabDialogs[TAB1])
   };

   TCHAR szBuffer[MAX_PATH] = {0};
   LPCTSTR szTabErr = _T("Can't create tab dialog.");

   hTab = GetDlgItem(hDlg, IDC_TAB);

   SendMessage(hTab, TCM_INSERTITEM, TAB1, (LPARAM)&tci);

   tci.pszText    = szTabDialogs[TAB2];
   tci.cchTextMax = _countof(szTabDialogs[TAB2]);

   SendMessage(hTab, TCM_INSERTITEM, TAB2, (LPARAM)&tci);

   hTabDlg[TAB1] = CreateDialogParam(l_Inst, szTabDialogs[TAB1], hTab, Tab1_DlgProc, 0);

   if(hTabDlg[TAB1] == NULL)
   {
      MsgErr(szTabErr);
      SendMessage(hDlg, WM_CLOSE, 0, 0);
   }

   hTabDlg[TAB2] = CreateDialogParam(l_Inst, szTabDialogs[TAB2], hTab, Tab2_DlgProc, 0);

   if(hTabDlg[TAB2] == NULL)
   {
      MsgErr(szTabErr);
      SendMessage(hDlg, WM_CLOSE, 0, 0);
   }

   if(SetFocus(GetDlgItem(hTabDlg[TAB1], IDC_EDT1)) == NULL)
   {
      return TRUE;
   }

   return FALSE;
}

static INT_PTR CALLBACK MainDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch(uMsg)
   {
      case WM_COMMAND:
         return OnCommand(hDlg, wParam, lParam);

      case WM_CLOSE:
         EndDialog(hDlg, 0);
         return TRUE;

      case WM_INITDIALOG:
         return OnInitMainDialog(hDlg, GetModuleHandle(NULL));

      case WM_NOTIFY:
         switch(((LPNMHDR)lParam)->code)
         {
            case TCN_SELCHANGE:
            {
               static int iTab = 0;
               int iSelTab = SendMessage(hTab, TCM_GETCURSEL, 0, 0);

               if(iTab != iSelTab)
               {
                  /* assert(iTab < NTABS  &&  iTab >= 0  && iSelTab < NTABS  &&  iSelTab >= 0); */
                  ShowWindow(hTabDlg[iTab], SW_HIDE);
                  ShowWindow(hTabDlg[iSelTab], SW_SHOWNORMAL);
                  iTab = iSelTab;
               }

               if(iSelTab == TAB1)
               {
                  SetFocus(GetDlgItem(hTabDlg[TAB1], IDC_EDT1));
               }
               return TRUE;
            }
         }
   }

   return FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
   INITCOMMONCONTROLSEX icex = {sizeof icex, ICC_TAB_CLASSES | ICC_STANDARD_CLASSES};
   InitCommonControlsEx(&icex);
   DialogBox(hInstance, _T("MainDialog"), NULL, MainDlgProc);

   return 0;
}

tab.h
Code: [Select]
ITEM(TAB1)
ITEM(TAB2)

Offline DMac

  • Member
  • *
  • Posts: 272
Re: Tabbed dialogs and its controls.
« Reply #3 on: June 30, 2009, 09:16:29 PM »
No one cares how much you know,
until they know how much you care.

PauloH

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #4 on: June 30, 2009, 09:51:44 PM »
Hi,

DMac:
Thank you for your links. I have followed the msdn explanation success yet. I'll try the codeproject one.

nicolas.sitbon:
Thank you for your comments and the insight about MsgErr.

I'll try your suggestions and keep you informed.

Kind regards,

PauloH.


PauloH

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #5 on: July 04, 2009, 03:15:49 AM »
Hi,

I found the errors:
1 - Tab dialogs must have the DS_CONTROL and WS_CHILD window styles.
2 - The correct sequence to create the control is first call CreateDialogParam and later call SendMessage (or SendDlgItemMessage) to associate the tab dialog with the tab control.

The corrected project is attached.

Kind regards.

nicolas.sitbon

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #6 on: July 04, 2009, 09:12:40 AM »
I gave you some errors, and you introduce them again in your code, boring...
- ZeroMemory() is misused, it takes a size in bytes, not in character, use sizeof
- SetWindowLong() is not 64 bits correct, use SetWindowLongPtr instead of
- limit the scope of identifier as I do in MainDlgProc()
- writing twice the prototype of static functions is error prone.
- why don't you use tab.h as I do

PauloH

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #7 on: July 04, 2009, 12:44:45 PM »
Hi nicolas.sitbon,

Thanks for your comments. But I have some too ( and your enlightments are always welcome):

- ZeroMemory() is misused, it takes a size in bytes, not in character, use sizeof --> Correct, I will do it. Need some time.

- SetWindowLong() is not 64 bits correct, use SetWindowLongPtr instead of --> Good point, I will do it.

- limit the scope of identifier as I do in MainDlgProc() --> I'll do it.

- writing twice the prototype of static functions is error prone. --> I like prototype and I always learn the contrary of this. See this link. Also, the book Advanced C by Peter D. Hipson teachs the same.

- why don't you use tab.h as I do. --> Because I do not want spread the code into 2 files since I can have 1 file. The definitions are more accessible in this case. I can't see much change here for this simple project. Certanly in the final project I have in mind this can be done.

Could you suggest me some reading? I'd appreciate it.

Kind regards,
PauloH

nicolas.sitbon

  • Guest
Re: Tabbed dialogs and its controls.
« Reply #8 on: July 04, 2009, 01:45:17 PM »
- limit the scope of identifier as I do in MainDlgProc() --> I'll do it.
take a look at my function MainDlgProc() and compare it with yours, you'll see difference!!

- writing twice the prototype of static functions is error prone. --> I like prototype and I always learn the contrary of this. See this link. Also, the book Advanced C by Peter D. Hipson teachs the same.

I didn't say prototype is bad, I said writing twice prototype is bad, so again take a look at my code and do as I do.

- why don't you use tab.h as I do. --> Because I do not want spread the code into 2 files since I can have 1 file. The definitions are more accessible in this case. I can't see much change here for this simple project. Certanly in the final project I have in mind this can be done.
The problem is not the number of file, rather the modularity: if you use my code, and you want to add a tab, you need only one modification.