37 / 0 / 2
Регистрация: 04.02.2015
Сообщений: 3
|
||||||||||||||||||||||||||||||||||||
1 | ||||||||||||||||||||||||||||||||||||
Создание компонента на основе TButton. Кнопка с иконками в стиле XP20.03.2015, 14:09. Показов 2811. Ответов 1
Метки нет (Все метки)
1. Введение. Настройка проекта для работы со стилями XP. Что же нам надо сделать для того, чтобы стандартные элементы отображались не в классическом стиле, а в стиле XP? Всего лишь использовать новую версию библиотеки Windows commctrl32.dll. Как это сделать уже много раз описывалось на просторах интернета. Самое простое, это добавить файл манифеста. Например, если исполняемый файл нашего проекта называется Project1.exe, то создаём в том же каталоге файл Project1.exe.manifest содержащий примерно следующее:
А что же сделать, чтобы наша кнопка отображалась на форме в design time тоже в стиле XP? Как же взгляд художника на форму при проектировании? Не запускать же каждый раз компиляцию, чтобы оценить труды по размещению элементов по фэншую. А всё элементарно. Разукрасим старичка Builder-a тем же самым способом. Создадим файл манифеста bcb.exe.manifest в папке Borland-a. Перезапускаем Builder и вот оно. Теперь и в нём все стандартные элементы в стиле XP. Что хотелось бы ещё заметить. Для полного понимания того что происходит, не надо стесняться читать MSDN. Поскольку данное действие это всего лишь верхушка айсберга следует изучить: 1. Концепцию манифестов. Работа с DLL без них в сложных приложениях крайне некомфортна, а в некоторых случаях и невозможна. 2. Ресурсы приложения. Можно спрятать файл манифеста внутрь файла. А так же захламить своё приложение множеством очень нужных и полезных вещей – иконками, картинками, текстами и пр., которые можно будет извлекать в процессе работы приложения по имени или идентификатору и не таскать с собой 100 маленьких файликов с иконками и т.д. 3. Стандартные элементы Windows, такие как окна, кнопки, списки и пр. Чтобы не изобретать велосипед, а пользоваться уже готовыми объектами. Например, нужна нам кнопка с картинкой вместо текста. TBitBtn или TSpeedButton? Можно. Но они самодельные. Если мы ими воспользуемся, то они останутся классического вида, а не в стиле XP. Эти элементы прорисовываются средствами VCL. Но достаточно отправить стандартной кнопке TButton два системных сообщения BM_SETSTYLE с параметром BS_BITMAP и BM_SETIMAGE с указателем на BITMAP и вот она кнопка моей мечты. 4. И собственно компилятор. В общем, вместе учим матчасть. 2. Создание собственного визуального компонента. Заголовочный файл Как создавать свои компоненты описано во множестве руководств. Создадим новый проект типа «Package». И создадим собственно компонент с именем MImageListButton на основе компонента TButton. Жмём Compile и Install и в общем-то компонент готов. Хоть сейчас добавляй его на форму. Это по сути полная копия TButton, хоть и с другим именем. Все свойства и методы унаследованы. Теперь нам надо создать свои свойства и методы. Создавать их лучше с помощью соответствующего визарда в ClassExplorer. Так будет меньше ошибок. Переменные (поля нашего класса) создаются с помощью визарда NewField. С его помощью мы добавим переменные для внутреннего использования в классе. Методы класса (в том числе конструктор и деструктор) добавляются с помощью визарда NewMetod. Если мы переопределяем родительский метод с помощью кнопочки Call Inherited вызов родительского метода автоматически добавляется. И наконец свойства класса, которые помимо всего прочего будут доступны в Object Ispector в Design time добавляются с помощью NewProperty. Там можно сразу создать поле, с которым будет связано свойство, задать обработчики его методов Set и Get. Итак, в секции privat класса создаём следующие поля:
FImageList – это ссылка на объект TImageList, из которого мы будем брать иконки для нашей кнопки. FEmptyIcon – пустая иконка, которая будет отображаться, если нам не надо показывать картинку на кнопке. По сути её можно использовать как иконку по умолчанию. FIconBorder – размер границы вокруг иконки. FIconIndexNormal (Push, Hot, Disable и Focus) – это индекс соответствующей иконки из TImageList или -1, если отображаем иконку по умолчанию (пустую). Из названий я думаю понятно какая иконка за что отвечает. Normal – обычное состояние кнопки не в фокусе, Push – кнопка нажата, Hot – курсор мыши над кнопкой, Disable – кнопка недоступна и Focus – кнопка в фокусе. Именно в этой последовательности они должны располагаться в свойстве FImageListStruct.himl. FIconAlign – расположение иконки в кнопке. Да, чуть не забыл. Зачем мы всё это делаем? А потому, что наш старый Builder не знает таких вещей. Соответственно мы должны добавить в MImageListButton.h ещё описания некоторых констант: Константы Button Control Messages, отсутствующие в файле winuser.h (или commctrl.h) Borland.
~MImageListButton – деструктор. CreateWnd – добавлена просто для демонстрации, как вызывается наследуемый метод. В этой функции можно описать действия до или после непосредственного вызова функции WinAPI CreateWindow, которая создаёт кнопку и присваивает ей Handle. В секции public общедоступные методы:
ClearStyle – возврат к классическому состоянию кнопки. Просто вызывает метод Set свойства ImageList с нулевым указателем на TImageList. GetHIML – возвращает указатель на FImageListStruct.himl. И наконец в секции __published описаны свойства, которые будут отображаться в Object Ispector:
Так же default/nodefault имеет ещё один эффект. Если значение свойства равно значению по умолчанию, то при компиляции не вызывается метод Set свойства. Т.е. мы не передадим в запущенное приложение настроенное в Object Ispector значение свойства. Параметр nodefault означает вызов метода Set в любом случае. И ещё, нельзя в методах Set свойств рассчитывать на какой-то порядок инициализации. Необходимо реализовывать метод Set таким образом, чтобы он мог вызываться индивидуально и не вызывать ошибок в приложении.
0
|
20.03.2015, 14:09 | |
Ответы с готовыми решениями:
1
Создание компонента класса TButton При добавлении компонента к примеру кнопки. В коде Button1: TButton; выдает ошибку что TButton не известно. Создание своего компонента на основе компонента Timer Создание компонента на основе TLabel |
37 / 0 / 2
Регистрация: 04.02.2015
Сообщений: 3
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20.03.2015, 14:11 [ТС] | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
3. Создание собственного визуального компонента. Реализация. Начнём реализацию методов нашего класса. Конструктор. Инициализируем в нём все значении наших полей и создаём пустую иконку. Описание создания иконки и объекта ImageList я опишу в заключительной части.
Вот в общем-то и всё. Теперь компилируем проект и инсталлируем его в палитру Borland Builder. Пробуем создать новый проект. Помещаем на форму наш MImageListButton и TImageList. Добавляем в TImageList иконки, назначаем в Object Ispector MImageListButton их номера, границу и выравнивание и если вы добавили Builder-у манифест bcb.exe.manifest, то вы увидите изменения уже в режиме design time. Компилируем и смотрим. Не запускается? Падает с ошибкой «Error reading ImageList1->Bitmap: Failed to read ImageList data from stream.»? Так вы забыли добавить к своему проекту манифест. Создаём манифест Project1.exe.manifest и всё прекрасно работает. 4. Заключение. В заключении хотелось бы рассказать о некоторых особенностях Icon и ImageList. Одну мы только что увидели, когда запускали проект без манифеста. TImageList, если его иконки используются в компоненте, использующей стили библиотеки commctrl32.dll версии 6 и выше не умеет грузить свой Bitmap из потока и вызывает остановку приложения. Помните об этом.TImageList инкапсулирует свойства стандартного ImageList. Соответственно его можно использовать в API функциях Windows через его Handle. Например, ImageList_GetIcon((_IMAGELIST*)FImageList->Handle,0, ILD_NORMAL); Кстати, заметьте, что проверка существования объекта по его Handle выполняется в Builder через вызов метода HandleAllocated(), а не обращением напрямую к Handle, так как это может привести к непреднамеренному созданию объекта. Ну, с ним вроде всё в порядке, а вот стандартный ImageList имеет особенность при создании. В MSDN сказано, что параметр cInitial в функции HIMAGELIST ImageList_Create( int cx, int cy, UINT flags, int cInitial, int cGrow ); распределяет указанное количество иконок при создании, но если вы попытаетесь воспользоваться ими, это приведёт к ошибке, а вызов ImageList_ReplaceIcon(HIMAGELIST himl, int i, HICON hicon ) вернёт значение -1 и ничего не сделает. Поэтому, в начале надо добавить cInitial количество иконок в ImageList с помощью параметра ImageList_ReplaceIcon i=-1. Значение i=-1 означает добавление иконки в конец списка. Распределённый HIMAGELIST необходимо удалять по окончании работы с ним, что мы и делаем в деструкторе функцией ImageList_Destroy( HIMAGELIST himl ). А вот объект Icon удалять совершенно не обязательно (кроме случая, если объект Icon создан с помощью функции CreateIconIndirect). Windows сделает это самостоятельно, когда иконка более не понадобится. Ну и напоследок. Объект Icon восходит к истокам. И его структура имеет свои особенности. Пустую иконку мы создали так: создали битовую маску AND, заполненную единицами и битовую маску XOR заполненную нулями. Т.е. чёрно-белую маску. Количество бит на пиксель иконки 1, количество масок XOR одна. Когда бит в маске AND 1, а в XOR 0 мы получим просто цвет фона. Удачи в разработке!
0
|
20.03.2015, 14:11 | |
20.03.2015, 14:11 | |
Помогаю со студенческими работами здесь
2
Создание класса на основе компонента Создание собственного компонента на основе TEdit Создание нового компонента на основе существующего (наследование); Пропадают иконки стандартных приложений в стиле metro и еще маленькая неприятность с иконками Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |