Click here to Skip to main content
15,868,292 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to insert dialog boxes, as separate pages, into tab control.

I have created the dialog boxes successfully in resource editor, with all necessary styles.

Since my application uses visual styles, I ran into problem with transparency of the dialog's child controls ( radio button, trackbar and similar ).

I have found a solution in EnableThemeDialogTexture API. Calling it in WM_INITDIALOG solves transparency issues of dialog's child controls. However, this API draws portion of tab control's background as dialog's background.

After inserting the dialog box as a page, mismatch between a dialog's and tab's background appear on Windows XP. Please see this image[^].

I have asked here and on Stack Overflow[^] why is this the case and got an answer.

I have tried to reposition the dialog box to fit tab control's display area but had no success. I am off by 3 pixels.

I will submit code that reproduces my results below, and the logic behind it will be in comments.

INSTRUCTIONS FOR CREATING CODE EXAMPLE THAT REPRODUCES THE PROBLEM:

1.) Create default Win32 project in Visual Studio;

2.) Create small dialog box in resource editor and add 2 or 3 controls for each;

I have added trackbar, radio buttons, checkboxes and static controls; These are problematic when transparency is needed;

3.) Add the following dialog procedure above the // Message handler for about box. in your .cpp template:

C++
INT_PTR CALLBACK FirstTabProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG: 
        EnableThemeDialogTexture(hDlg, ETDT_ENABLETAB);
        return (INT_PTR)TRUE;
    }
    return (INT_PTR)FALSE;
}


4.) add a tab control to the About dialog box, it is in your resource editor;

5.) Add the following WM_INITDIALOG handler to INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) dialog procedure, in your .cpp template:
C++
case WM_INITDIALOG:
{
    HWND hwndTab = GetDlgItem(hDlg, IDC_TAB1);

    RECT rcTab = { 0 }, // rectangle of the entire tab's client area
        rcTabItem = { 0 }; // rectangle of the tab header's area

    GetClientRect(hwndTab, &rcTab);  // get entire client area

    // get tab control's item area
    // the bottom value of this rectangle will be the top value of rcTab
    TabCtrl_GetItemRect(hwndTab, 0, &rcTabItem);  

    TCITEM tci = { 0 };

    tci.mask = TCIF_TEXT | TCIF_PARAM;
    tci.pszText = L"First tab";

    HWND FirstPageDialogBox = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_DIALOG1),  // <--- we created IDD_DIALOG1  
        hDlg, (DLGPROC)FirstTabProc);

    ShowWindow(FirstPageDialogBox , SW_SHOW);

    // map tab's rectangle to dialog box rectangle
    // so we can properly resize dialog box

    POINT pt = { 0 };
    ClientToScreen(hwndTab, &pt);
    ScreenToClient(hDlg, &pt);

    // this macro obtains tab control's display area
    TabCtrl_AdjustRect(hwndTab, FALSE, &rcTab);

    // resize dialog box and move it into tab page
    MoveWindow(FirstPageDialogBox , 
        rcTab.left + pt.x,  // + pt.x ---> "workaround"  
        rcTabItem.bottom + pt.y + 3, // rcTabItem.bottom + p.y + 3 ---> "workaround"
        rcTab.right - rcTab.left, 
        rcTab.bottom - rcTabItem.bottom - 3, // rcTabItem.bottom - 3 ---> "workaround"
        TRUE);

    // store dialog box handle into lParam
    // this way I have access to the dialog box for notification messages
    // when user switches tabs
    tci.lParam = (LPARAM)FirstPageDialogBox;

    // add this page
    SendMessage(hwndTab, TCM_INSERTITEM, (WPARAM)0, (LPARAM)&tci);
}
    return (INT_PTR)TRUE;


6.) Now we are left with technicalities. First we shall add the following in stdafx.h just below #include <windows.h> :

C++
#include <windowsx.h>
#include <CommCtrl.h>
#include <Uxtheme.h>

#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "UxTheme.lib")
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")


7.) Next, we initialize common controls in ATOM MyRegisterClass(HINSTANCE hInstance) :

C++
INITCOMMONCONTROLSEX iccex = { 0 };
iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccex.dwICC = ICC_TAB_CLASSES | ICC_STANDARD_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&iccex);    

// below will be filled WNDCLASSEX structure and the rest of the code...

That would be all. Please remember to test the application on Windows XP to see the problem.

QUESTION:

How do I insert dialog box into tab control's display area, so their background's properly align?

Thank you.
Posted
Comments
barneyman 12-Nov-14 17:40pm    
from some distant memory of this, try doing the adjustRect and child movewindow AFTER the insertion ... the tab control changes size ISTR
AlwaysLearningNewStuff 12-Nov-14 18:26pm    
I have refined m code per your instructions and it seems that everything works!

I will edit my question with the relevant portion of the reworked code. Meanwhile, if you post your comment as an answer I will officially accept it and vote 5!

Thank you so much!

Best regards.
enhzflep 13-Nov-14 1:09am    
Just seen this thread after replying to your msg. (I'm assuming that the two are related)
Glad you worked the problem out. :) (if indeed it is, of course)
AlwaysLearningNewStuff 22-Nov-14 23:19pm    
It seems that this is not the end of my struggle with visual styles as I believed... Not to mention flickering... At this moment I feel so powerless that am about to cry :(

Can you please try to help me?

1 solution

from some distant memory of this, try doing the adjustRect and child movewindow AFTER the insertion ... the tab control changes size ISTR

BTW, you'll have to do an adjustRect, movewindow for all children after each insert (or once after a block insert), because the tabControl header resizes itself after each insertion
 
Share this answer
 
v2
Comments
AlwaysLearningNewStuff 12-Nov-14 19:07pm    
BTW, you'll have to do an adjustRect, movewindow for all children after each insert (or once after a block insert), because the tabControl header resizes after itself each insertion Good to know this, I have performed resizing and moving after inserting all the items.

Off topic, where did you get this info? I tried searching online but couldn't find anything...

Thanks again, 5ed as promised - you earned it really!

Best regards :)
barneyman 12-Nov-14 21:23pm    
trial and error - Revisiting the code, the comments are less than polite, so i guess I experienced the same frustration as you :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900