thumbnail toolbars
В продолжении темы изучения возможностей панели задачи windows 7 решил изучить как добавлять кнопки в превью окон панели задач и обрабатывать их нажатия. Заодно узнал как реализовывать окошко проводника в своих приложениях. Для добавления подобных кнопок в превью, нам понадобится интерфейс ITaskBarList3. Вобще после создания экземпляра такого интерфейса пользоваться им можно только после того как от системы получено сообщение о создании кнопки на панели задач. Согласно MSDN для этого требуется зарегистрировать у себя сообщение RegisterWindowMessage('TaskbarButtonCreated') и после его прихода уже проводить свои действия с интерфейсом. Поэтому добавим переменную в которой сохраним код нашего сообщения, и в событии создания главной формы зарегистрируем сообщение.
var tbCreate : Cardinal; procedure TmainForm.FormCreate(Sender: TObject); begin tbCreated := RegisterWindowMessage('TaskbarButtonCreated'); end;
Далее в обработчике сообщений нам надо отследить приход данного сообщения и вызвать нашу процедуру создания кнопок InitTaskBar(). Для этого перепишем стандартный обработчик сообщений формы DefaulHandler.
TMainForm = class(TForm) private procedure defaultHandler(var msg); override; end; .. procedure TMainForm.defaultHandler(var msg); begin inherited; with TMessage(msg) do begin if msg = tbCreated then InitTaskBar(self); end; end;
В процедуре InitTaskBar сначала создадим экземпляр ITaskBar3 который сохраним в private нашей формы с именем tb. Максимальное количество создаваемых кнопок равно семи. Для описания кнопок используется структура TThumbButton, и поскольку кнопки создаются все сразу, то нам требуется массив данных структур. Иконки кнопок можно устанавливать как с помощью imageList так и отдельно. код кнопки, который будет передаваться при обработке ее нажатия содержится в поле iID, индекс иконки в imageList содержится в поле iBitmap. Набор полей который используется задается в dwMask.
procedure TmainForm.InitTaskBar(Sender: TObject); var i:integer; pButtons : array[0..1] of TThumbButton; begin tb := CreateComObject(CLSID_TaskBarList) as ITaskBarList3; for i in [0,1] do begin pButtons[i].iId := i; pButtons[i].iBitmap :=i+1; pButtons[i].dwMask := THB_BITMAP + THB_TOOLTIP; end; pButtons[0].szTip := 'Назад'; pButtons[1].szTip := 'Вперед'; tb.ThumbBarSetImageList(handle, imageList.Handle); tb.ThumbBarAddButtons(handle, 2, @pButtons); end;
Теперь при запуске приложения мы получаем две кнопки в превью, с картинками(1,2) из imageList. Обработка нажатия на кнопки проводится в обработчике сообщения WM_COMMAND. если старшее слово параметра wparam равно THBN_CLICKED следовательно была нажата одна из кнопок, и код нажатой кнопки содержится во младшем слове.
procedure wmCommand(var msg:TMessage);message WM_COMMAND; ... procedure TMainForm.wmCommand(var msg: TMessage); begin inherited; if msg.WParamHi= THBN_CLICKED then begin case msg.WParamLo of 0: BackButtonClick(nil); 1: ForwardButtonClick(nil); end; end; end;
ах да. наши кнопки будут выполнять действия Вперед и Назад. На данном этапе мы поучили следующее:
Теперь предадим некоторый смысл нашему приложению. Допустим наша программа будет являться некоторым файловым менеджером и будет отрывать в себе окна проводника. добавим в приложение TToolBar c тремя кнопками: создание окна(NewWindowButton), навигация вперед(ForwardButton), навигация назад(BackButton). Окна проводника будут открываться как дочерние во вкладках, и с использованием интерфейса IExplorerBrowser представлять проводник windows. Стиль главной формы приложения сделаем fsMDIForm, добавим на форму browserTab : TTabControl, добавим в проект новую форму, которая будет дочерней fsMDIChild - TBrowserForm. При нажатии на кнопку создания нового окна, создадим собственно новое окно, вкладку для него, причем в stringList вкладок добавим так же ссылку на саму форму этого окна:
procedure TmainForm.NewWindowButtonClick(Sender: TObject); var index : Integer; child : TBrowserForm; begin child := TBrowserForm.create(self); index := self.MDIChildCount - 1; BrowserTabs.Tabs.AddObject(intToStr(index),child); browserTabs.tabIndex := index; end;
при переключении вкладок требуется отображать нужные окна, делать это будем сравнивая как раз таки сохраненные объекты.
procedure TmainForm.BrowserTabsChange(Sender: TObject); var child : TBrowserForm; i:integer; begin child := browserTabs.tabs.Objects[browserTabs.TabIndex] as TBrowserForm; for i:=0 to MDIChildCount - 1 do begin if MDIChildren[i] = child then MDIChildren[i].Show; end; end;
Теперь перейдем к дочерней форме. Для отображения окна проводника нам понадобится экземпляр интерфейса IExplorerBrowser, который мы опишем в private секции формы. в процедуре создания окна выполним следующие действия: создадим экземпляр eb:IExplorerBrowser, заполним структуру fs:TFolderSettings для установки параметров отображения папки, установим размер области отображения, установим начальную папку для отображения (для этого сначала получим IShellItem, из которого уже получим структуру PItemIDList, которая используется для установки отображаемой директории.)
procedure TBrowserForm.FormCreate(Sender: TObject); var fs : TFolderSettings; rect : TRect; pidl : PItemIDList; item : IShellItem; begin eb := CreateComObject(CLSID_ExplorerBrowser) as IExplorerBrowser; fs.ViewMode := FVM_DETAILS; fs.fFlags := 0; rect := self.GetClientRect; eb.SetOptions(EBO_SHOWFRAMES); if S_OK eb.Initialize(handle, rect, fs) then begin showMessage('init err'); exit; end; SHCreateItemFromParsingName('C:\', nil, IID_ISHellItem, item); SHGetIDListFromObject(item, pidl); eb.BrowseToIDList(pidl,0); ilFree(pidl); end;
при закрытии окна необходимо вызвать метод destroy нашего IExplorerBrowser, а при изменении размеров окна, соответственно изменить и его размеры. поэтому добавим:
procedure TBrowserForm.FormDestroy(Sender: TObject); begin eb.Destroy; end; procedure TBrowserForm.FormResize(Sender: TObject); var pdwp: Cardinal; begin pdwp :=0; eb.SetRect(pdwp, self.GetClientRect); end;
При закрытии основного окна, вручную вызовем методы destroy дочерних форм, при этом учтем, что список дочерних форм сразу перестраивается, поэтому перебор дочерних окон следует осуществлять с конца.
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); var i:integer; begin for i:=MDIChildCount - 1 downto 0 do MDIChildren[i].Destroy; end;
При вызове функции BrowseTOIdList не обязательно передавать структуру PItemIDList, можно также с помощью второго аргумента, определить переход например к предыдущей папке. Для этого добавим две процедуры в раздел public дочерней формы.
procedure TBrowserForm.NavigateBack; begin eb.BrowseToIDList(nil,SBSP_NAVIGATEBACK); end; procedure TBrowserForm.NavigateForward; begin eb.BrowseToIDList(nil,SBSP_NAVIGATEFORWARD); end;
ну и чтобы завершить процесс использования кнопок в превью, поскольку при нажатии на них происходит вызов обработчиков нажатий кнопок BackButton & ForwardButton из главного тулбара, то добавим эти обработчики в код главной формы.
procedure TmainForm.ForwardButtonClick(Sender: TObject); begin if MDIChildCount = 0 then exit; with mdiChildren[0] as TBrowserForm do navigateForward(); end; procedure TmainForm.BackButtonClick(Sender: TObject); begin if MDIChildCount = 0 then exit; with mdiChildren[0] as TBrowserForm do navigateBack(); end;
Логично было бы отображать в заголовках вкладок названия текущей папки (: но для этого надо изучить как обращаться с IExplorerBrowserEvents, чего я еще немного не понял.