Настройка панелей инструментов

Большинство приложений под управлением Windows используют элементы управления панелью инструментов для предоставления пользователям удобного доступа к функциям программы. Однако статические панели инструментов имеют некоторые недостатки, например слишком мало места для эффективного отображения всех доступных инструментов. Решение этой проблемы заключается в том, чтобы сделать панели инструментов приложения настраиваемыми для пользователя. Затем пользователи могут выбрать отображение только необходимых инструментов, и они могут упорядочить их таким образом, чтобы соответствовать их личному стилю работы.

Примечание.

Панели инструментов в диалоговых окнах не могут быть настроены.

 

Чтобы включить настройку, включите флаг стиля CCS_ADJUSTABLE при создании элемента управления панели инструментов. Существует два основных подхода к настройке:

  • Диалоговое окно настройки. Это диалоговое окно, предоставленное системой, является самым простым подходом. Он предоставляет пользователям графический пользовательский интерфейс, позволяющий им добавлять, удалять или перемещать значки.
  • Перетаскивание и удаление инструментов. Реализация функций перетаскивания позволяет пользователям перемещать средства в другое расположение на панели инструментов или удалять их, перетаскивая их с панели инструментов. Он предоставляет пользователям быстрый и простой способ упорядочить свою панель инструментов, но не позволяет им добавлять средства.

Вы можете реализовать любой подход или оба подхода в зависимости от потребностей приложения. Ни одно из этих двух подходов к настройке не предоставляет встроенный механизм, например кнопку "Отмена" или "Отменить", чтобы вернуть панель инструментов в прежнее состояние. Вы должны явно использовать API элементов управления панели инструментов для хранения состояния предварительной установки панели инструментов. При необходимости эту хранимую информацию можно использовать позже для восстановления панели инструментов в исходном состоянии.

Это важно знать

Технологии

Необходимые компоненты

  • C/C++
  • Программирование пользовательского интерфейса Windows

Instructions

Диалоговое окно настройки

Диалоговое окно настройки предоставляется элементом управления панели инструментов, чтобы предоставить пользователям простой способ добавления, перемещения или удаления инструментов. Пользователи могут запустить его, дважды щелкнув панель инструментов. Приложения могут запускать диалоговое окно настройки программным способом, отправив элемент управления панелью инструментов ТБ_CUSTOMIZE сообщение.

На следующем рисунке показан пример диалогового окна настройки панели инструментов.

screen shot of a window with a three-item toolbar, and a dialog box with lists of the available and current toolbar buttons

Инструменты в списке справа находятся на панели инструментов. Изначально этот список будет содержать средства, указанные при создании панели инструментов. Поле списка слева содержит средства, которые доступны для добавления на панель инструментов. Ваше приложение отвечает за заполнение этого списка (кроме разделителя, которое отображается автоматически).

Элемент управления панели инструментов уведомляет приложение о запуске диалогового окна настройки, отправив родительское окно код уведомления ТБN_BEGINADJUST, за которым следует код уведомления ТБN_INITCUSTOMIZE. В большинстве случаев приложению не нужно реагировать на эти коды уведомлений. Однако если диалоговое окно "Настройка панели инструментов" не требуется, чтобы кнопка "Справка" отображалась, обработайте ТБN_INITCUSTOMIZE, возвращая ТБNRF_HIDEHELP.

Затем элемент управления панели инструментов собирает сведения, необходимые для инициализации диалогового окна, отправляя три ряда кодов уведомлений в следующем порядке:

  • Код уведомления ТБN_QUERYINSERT для каждой кнопки на панели инструментов, чтобы определить, где можно вставить кнопки. Верните значение FALSE , чтобы предотвратить вставку кнопки слева от кнопки, указанной в сообщении уведомления. Если вы возвращаете значение FALSE для всех кодов уведомлений ТБN_QUERYINSERT, диалоговое окно не будет отображаться.
  • Код уведомления ТБN_QUERYDELETE для каждого средства, которое сейчас находится на панели инструментов. Возвращает значение TRUE , если средство может быть удалено или false , если нет.
  • Ряд кодов уведомлений ТБN_GEТБ UTTONINFO для заполнения списка доступных кнопок. Чтобы добавить кнопку в список, заполните структуру NMTOOLBAR, передаваемую кодом уведомления, и верните значение TRUE. Если у вас нет дополнительных инструментов для добавления, верните значение FALSE. Обратите внимание, что можно возвращать сведения о кнопках, которые уже находятся на панели инструментов; Эти кнопки не будут добавлены в список.

Откроется диалоговое окно, и пользователь может начать настраивать панель инструментов.

При открытии диалогового окна приложение может получать различные коды уведомлений в зависимости от действий пользователя:

  • ТБN_QUERYINSERT. Пользователь изменил расположение инструмента на панели инструментов или добавил инструмент. Верните значение FALSE , чтобы предотвратить вставку средства в этом расположении.
  • ТБN_DELETINGBUTTON. Пользователь собирался удалить инструмент на панели инструментов.
  • ТБN_CUSTHELP. Пользователь щелкнул кнопку справки.
  • ТБN_TOOLBARCHANGE. Пользователь добавил, переместил или удалил инструмент.
  • ТБN_RESET. Пользователь щелкнул кнопку "Сброс".

После уничтожения диалогового окна приложение получит код уведомления ТБN_ENDADJUST.

В следующем примере кода показан один из способов реализации настройки панели инструментов.

// The buttons are stored in an array of TBBUTTON structures. 
//
// Constants such as STD_FILENEW are identifiers for the 
// built-in bitmaps that have already been assigned as the toolbar's 
// image list.
//
// Constants such as IDM_NEW are application-defined command identifiers.

TBBUTTON allButtons[] = 
    {
        { MAKELONG(STD_FILENEW,  ImageListID), IDM_NEW,   TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"New" },
        { MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN,  TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Open"},
        { MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE,  TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Save"},
        { MAKELONG(STD_CUT,      ImageListID), IDM_CUT,   TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Cut" },
        { MAKELONG(STD_COPY,     ImageListID), IDM_COPY,  TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Copy"},
        { MAKELONG(STD_PASTE,    ImageListID), IDM_PASTE, TBSTATE_ENABLED, 0, {0}, 0, (INT_PTR)L"Paste"}
    };

// The following appears in the window's message handler.

case WM_NOTIFY: 
    {
        switch (((LPNMHDR)lParam)->code) 
        {
        
        case TBN_GETBUTTONINFO:  
            {
                LPTBNOTIFY lpTbNotify = (LPTBNOTIFY)lParam;

                // Pass the next button from the array. There is no need to filter out buttons
                // that are already used—they will be ignored.
                
                int buttonCount = sizeof(allButtons) / sizeof(TBBUTTON);
                
                if (lpTbNotify->iItem < buttonCount)
                {
                    lpTbNotify->tbButton = allButtons[lpTbNotify->iItem];
                    return TRUE;
                }
                
                else
                
                {
                    return FALSE;  // No more buttons.
                }
            }
            
            break;

            case TBN_QUERYINSERT:
            
            case TBN_QUERYDELETE:
                return TRUE; 
        }
    }

Перетаскивание и удаление инструментов

Пользователи также могут изменить порядок кнопок на панели инструментов, нажав клавишу SHIFT и перетащив кнопку в другое расположение. Процесс перетаскивания обрабатывается автоматически элементом управления панели инструментов. Он отображает фантомное изображение кнопки по мере перетаскивания и переупорядочение панели инструментов после ее удаления. Пользователи не могут добавлять кнопки таким образом, но они могут удалить кнопку, удалив ее с панели инструментов.

Хотя элемент управления панели инструментов обычно выполняет эту операцию автоматически, он также отправляет приложение два кода уведомлений: ТБN_QUERYDELETE и ТБN_QUERYINSERT. Чтобы управлять процессом перетаскивания, обработайте эти коды уведомлений следующим образом:

  • Код уведомления ТБN_QUERYDELETE отправляется сразу после того, как пользователь пытается переместить кнопку перед отображением кнопки призрака. Верните значение FALSE , чтобы предотвратить перемещение кнопки. Если вы возвращаете значение TRUE, пользователь сможет переместить средство или удалить его, удалив его с панели инструментов. Если средство можно переместить, его можно удалить. Однако если пользователь удаляет средство, элемент управления панели инструментов отправит приложение ТБN_DELETINGBUTTON код уведомления, в какой момент можно повторно ввести кнопку в исходном расположении, тем самым отменив удаление.
  • Код уведомления ТБN_QUERYINSERT отправляется, когда пользователь пытается удалить кнопку на панели инструментов. Чтобы предотвратить перемещение кнопки слева от кнопки, указанной в уведомлении, верните значение FALSE. Этот код уведомления не отправляется, если пользователь удаляет средство с панели инструментов.

Если пользователь пытается перетащить кнопку без нажатия клавиши SHIFT, элемент управления панели инструментов не будет обрабатывать операцию перетаскивания. Однако приложение отправляет код уведомления ТБN_BEGINDRAG, чтобы указать начало операции перетаскивания, а также код уведомления ТБN_ENDDRAG, указывающий конец. Если вы хотите включить эту форму перетаскивания, приложение должно обрабатывать эти коды уведомлений, предоставлять необходимый пользовательский интерфейс и изменять панель инструментов, чтобы отразить любые изменения.

Сохранение и восстановление панелей инструментов

В процессе настройки панели инструментов приложению может потребоваться сохранить сведения, чтобы можно было восстановить панель инструментов в исходном состоянии. Чтобы инициировать сохранение или восстановление состояния панели инструментов, отправьте элемент управления ТБ_SAVERESTORE сообщение со значением true. Значение lParam этого сообщения указывает, запрашивается ли операция сохранения или восстановления. После отправки сообщения существует два способа обработки операции сохранения и восстановления:

  • При использовании распространенных элементов управления версии 4.72 и более ранних версий необходимо реализовать обработчик ТБN_GEТБ UTTONINFO. Элемент управления панели инструментов отправляет этот код уведомления для запроса сведений о каждой кнопке по мере восстановления.
  • Версия 5.80 включает параметр сохранения и восстановления. В начале процесса и по мере сохранения или восстановления каждой кнопки приложение получит код уведомления ТБN_SAVE или ТБN_RESTORE. Чтобы использовать этот параметр, необходимо реализовать обработчики уведомлений, чтобы предоставить растровое изображение и сведения о состоянии, необходимые для успешного сохранения или восстановления состояния панели инструментов.

Состояния панели инструментов сохраняются в потоке данных, состоящем из блоков определенных оболочкой данных, чередующихся с блоками данных, определенных приложением. Для каждой кнопки хранится один блок данных каждого типа, а также необязательный блок глобальных данных, которые приложения могут размещать в начале потока. Во время процесса сохранения обработчик ТБN_SAVE добавляет в поток данных определенные приложением блоки. В процессе восстановления обработчик ТБN_RESTORE считывает каждый блок и предоставляет оболочке сведения, необходимые для восстановления панели инструментов.

Обработка уведомления ТБN_SAVE

Первый ТБN_SAVE код уведомления отправляется в начале процесса сохранения. Перед сохранением кнопок элементы структуры NM ТБ SAVE задаются, как показано в следующей таблице.

Элемент Параметр
iItem –1
cbData Объем памяти, необходимой для данных, определенных оболочкой.
cButtons Количество кнопок.
Pdata Вычисляемый объем памяти, необходимый для данных, определенных приложением. Как правило, вы включаете некоторые глобальные данные, а также данные для каждой кнопки. Добавьте это значение в cbData и выделите достаточно памяти для pData, чтобы сохранить все это.
pCurrent Первый неиспользуемый байт в потоке данных. Если вам не требуются сведения о глобальной панели инструментов, задайте pCurrent = pData таким образом, чтобы он указывает на начало потока данных. Если требуется глобальная панель инструментов, сохраните ее в pData, установите pCurrent в начало неиспользуемой части потока данных перед возвратом.

 

Если вы хотите добавить некоторые сведения о глобальной панели инструментов, поместите его в начало потока данных. Перенаправляемый pCurrent к концу глобальных данных, чтобы он указывает на начало неиспользуемой части потока данных и возврат.

После возвращения оболочка начнет сохранять сведения о кнопке. Он добавляет определяемые оболочкой данные для первой кнопки в pCurrent, а затем перемещает pCurrent в начало неиспользуемой части.

После сохранения каждой кнопки отправляется код уведомлений ТБN_SAVE, а NM ТБ SAVE возвращается с этими элементами, заданными следующим образом.

Элемент Параметр
iItem Отсчитываемый от нуля индекс номера кнопки.
pCurrent Указатель на первый неиспользуемый байт в потоке данных. Если вы хотите сохранить дополнительные сведения о кнопке, сохраните ее в расположении, на которое указывает pCurrent, и обновите pCurrent, чтобы указать первую неиспользуемую часть потока данных после этого.
ТБ BUTTON Структура ТБ BUTTON, описывающая сохраненную кнопку.

 

При получении кода уведомления необходимо извлечь все сведения, необходимые для кнопки, из ТБ BUTTON. Помните, что при добавлении кнопки можно использовать элемент dwData ТБ BUTTON для хранения данных, относящихся к приложению. Загрузите данные в поток данных по адресу pCurrent. Перенаправляемый pCurrent к концу данных, снова указывая на начало неиспользуемой части потока и возвращая.

Затем оболочка переходит к следующей кнопке, добавляет сведения в pData, перемещает pCurrent, загружает ТБ BUTTON и отправляет другой код уведомлений ТБN_SAVE. Этот процесс продолжается до сохранения всех кнопок.

Восстановление сохраненных панелей инструментов

Процесс восстановления в основном изменяет процесс сохранения. В начале приложение получит код уведомления ТБN_RESTORE с элементом iItem структуры NM ТБ RESTORE, равным –1. Элемент cbData имеет размер pData, а для cButtons задано количество кнопок.

Обработчик уведомлений должен извлечь глобальные сведения, которые были помещены в начале pData во время сохранения, и перейти к началу первого блока определяемых оболочкой данных. Задайте для cBytesPerRecord размер блоков данных, используемых для сохранения данных кнопки. Задайте для cButton число кнопок и вернитесь.

Следующая кнопка NM ТБ RESTORE — для первой кнопки. Элемент pCurrent указывает на начало первого блока данных кнопки, а iItem — индекс кнопки. Извлеките эти данные и продвигайте pCurrent. Загрузите данные в ТБ BUTTON и верните их. Чтобы опустить кнопку на восстановленной панели инструментов, установите для элемента idCommand ТБ BUTTON значение нулю. Оболочка повторит процесс для оставшихся кнопок. Помимо сообщений NM ТБ SAVE и NM ТБ RESTORE, можно также использовать такие сообщения, как ТБN_RESET для сохранения и восстановления панели инструментов.

Следующий пример кода сохраняет панель инструментов перед настройкой и восстанавливает ее, если приложение получает сообщение ТБN_RESET.

int               i;
LPNMHDR           lpnmhdr;
static int        nResetCount;
static LPTBBUTTON lpSaveButtons;
LPARAM            lParam;

switch( lpnmhdr->code)
{
    case TBN_BEGINADJUST: // Begin customizing the toolbar.
    {
        LPTBNOTIFY  lpTB = (LPTBNOTIFY)lparam;
       
        // Allocate memory for the button information.
        
        nResetCount   = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
        lpSaveButtons = (LPTBBUTTON)GlobalAlloc(GPTR, sizeof(TBBUTTON) * nResetCount);
      
        // In case the user presses reset, save the current configuration 
        // so the original toolbar can be restored.
        
        for(i = 0; i < nResetCount; i++)
        {
            SendMessage(lpTB->hdr.hwndFrom, 
                        TB_GETBUTTON, i, 
                        (LPARAM)(lpSaveButtons + i));
        }
    }
    
    return TRUE;
   
    case TBN_RESET:
    {
        LPTBNOTIFY lpTB = (LPTBNOTIFY)lparam;
        
        int nCount, i;
    
        // Remove all of the existing buttons, starting with the last one.
        
        nCount = SendMessage(lpTB->hdr.hwndFrom, TB_BUTTONCOUNT, 0, 0);
        
        for(i = nCount - 1; i >= 0; i--)
        {
            SendMessage(lpTB->hdr.hwndFrom, TB_DELETEBUTTON, i, 0);
        }
      
        SendMessage(lpTB->hdr.hwndFrom,      // Restore the saved buttons.
                    TB_ADDBUTTONS, 
                    (WPARAM)nResetCount, 
                    (LPARAM)lpSaveButtons);
    }
    
    return TRUE;
   
    case TBN_ENDADJUST:                // Free up the memory you allocated.
        GlobalFree((HGLOBAL)lpSaveButtons);
        
        return TRUE;
}

Использование элементов управления панели инструментов

Значения индекса изображения стандартной кнопки панели инструментов

Демонстрация общих элементов управления Windows (CppWindowsCommonControls)