No meu aplicativo Win32, tenho uma barra de ferramentas que precisa ter uma caixa de combinação principal suspensa abrangendo 70% da barra de ferramentas, começando pela esquerda, e depois quaisquer botões adicionais (como neste caso Recortar/Copiar/Colar) seguindo depois — talvez depois de um pequeno separador.
[--------------------Dropdown-------------------V] | [Cut][Copy][Paste]
Neste código, primeiro crio o controle ComboBox filho para a barra de ferramentas e faço com que ele tenha 70% da largura do Toolbar Rect usando setWindowPos
e então prossigo com botões regulares. Mas apenas os 3 botões são exibidos sem o ComboBox.
Acho que tenho que fazer isso SetWindowPos
para cada um dos botões, mas quero que eles fluam naturalmente sem posicioná-los explicitamente, como aconteceria sem a caixa de combinação.
void CreateToolbar1(HWND hWndParent)
{
// Declare and initialize local constants.
const int ImageListID = 0;
const int numButtons = 3;
const int bitmapSize = 16;
const DWORD buttonStyles = BTNS_AUTOSIZE;
// Create the toolbar.
hWndToolbar1 = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | TBSTYLE_WRAPABLE | TBSTYLE_FLAT, 0, 0, 0, 0,
hWndParent, NULL, GetModuleHandle(NULL), NULL);
// Obtain toolbar's rectangle coordinates
RECT rectToolbar1;
SendMessage(hWndToolbar1, TB_GETITEMRECT, (WPARAM)0, (LPARAM)&rectToolbar1);
// Add ComboBox control to toolbar, should take up 70% of the width
HWND hWndDropdown = CreateWindowEx(WS_EX_CLIENTEDGE, WC_COMBOBOXEX, NULL, WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST, 0, 0, 100, 35, hWndToolbar1, NULL, GetModuleHandle(NULL), NULL);
SetWindowPos(hWndDropdown, NULL, rectToolbar1.left, rectToolbar1.top, 0.7 * (rectToolbar1.right - rectToolbar1.left), rectToolbar1.bottom - rectToolbar1.top, SWP_SHOWWINDOW);
// Add 3 regular buttons afterwards (Cut/Copy/Paste)
// ---
// Create the image list.
g_hImageList = ImageList_Create(bitmapSize, bitmapSize, // Dimensions of individual bitmaps.
ILC_COLOR16 | ILC_MASK, // Ensures transparent background.
numButtons, 0);
// Set the image list.
SendMessage(hWndToolbar1, TB_SETIMAGELIST,
(WPARAM)ImageListID,
(LPARAM)g_hImageList);
// Load the button images.
SendMessage(hWndToolbar1, TB_LOADIMAGES,
(WPARAM)IDB_STD_SMALL_COLOR,
(LPARAM)HINST_COMMCTRL);
// Initialize buttons Cut/Copy/Paste
TBBUTTON tbButtons[numButtons] =
{
{ MAKELONG(STD_CUT, ImageListID), IDM_CUT, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Cut" },
{ MAKELONG(STD_COPY, ImageListID), IDM_COPY, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Copy"},
{ MAKELONG(STD_PASTE, ImageListID), IDM_PASTE, 0, buttonStyles, {0}, 0, (INT_PTR)L"Paste"}
};
// Add buttons.
SendMessage(hWndToolbar1, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SendMessage(hWndToolbar1, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons);
// Resize the toolbar, and then show it.
SendMessage(hWndToolbar1, TB_AUTOSIZE, 0, 0);
ShowWindow(hWndToolbar1, TRUE);
}
Este é o resultado da colaboração de duas edições individuais:
O primeiro problema significa que, embora a caixa de combinação esteja lá, você nem consegue vê-la. Ela está completamente escondida atrás do primeiro botão da barra de ferramentas. Exceto por alterar o código para calcular a largura desejada, nada mais precisa ser feito.
A segunda questão precisa de mais atenção. Para entender os princípios básicos, aqui está a definição de um controle de barra de ferramentas :
Notavelmente, um controle de barra de ferramentas não fornece suporte dedicado para hospedar controles arbitrários. O tópico da documentação How to Embed Nonbutton Controls in Toolbars é ainda mais explícito:
Um corolário disso é que todas as informações de layout são armazenadas em um
TBBUTTON
array que é atribuído viaTB_ADDBUTTONS
mensagem. Cada elemento descreve um botão ou um separador. A solução alternativa para adicionar controles arbitrários a uma barra de ferramentas é adicionar um separador (da largura desejada em pixels) aoTBBUTTON
array para reservar espaço para o controle, por exemplo:A primeira entrada reserva espaço para o controle combo box. É literalmente um placeholder que não recebe entrada do usuário. Embora isso funcione, parece muito desajeitado.
Uma solução melhor é usar um controle Rebar . Entre outros recursos, ele oferece suporte dedicado para hospedar controles arbitrários.