Думаю, многим поднадоели стандартные, серые кнопки. Иногда хочется при разработке интерфейса сделать свою программу более красивой и нестандартной. В принципе, ничего сложного в этом нет. В этой статье я расскажу, как можно обозначить любую кнопку на вашей форме в виде нужного вам рисунка.
Возьмем как пример следующее изображение.
Основные принципы:
У нашего стандартного класса Button есть замечательное свойство регион (Region), которое задает область построения контрола. То есть форму, если по-русски. Регион можно построить несколькими способами, но на данный момент буду использовать GraphicsPath.
GraphicsPath – это последовательность соединенных линий и кривых (с) MSDN. В данном случае мы будем последовательно соединять прямоугольники толщиной в 1 пиксель. То есть создадим новый экземпляр класса GraphicsPath и будем толкать туда прямоугольники следующим образом.
Представим увеличенное изображение синего круга на красном фоне:
Сейчас наша задача состоит в том, что бы отсечь все красное, а синие запихнуть в наш GraphicsPath. Для начала определяем цвет, который нам нужно отсечь. Делаем это с помощью функции GetPixel(0,0). Она «запоминает» цвет первого левого пикселя. Дальше создаем 2 цикла, которые будут проверять каждый пиксель справа налево. Если встречается «непрозрачный» пиксель, то запускается следующий цикл, который так же проходит дальше по изображению и считает количество непрозрачных пикселей. Как только он наталкивается на прозрачный, цикл обрывается, и в наш GraphicsPath забивается прямоугольник шириной 1px и длинной в количество найденных пикселей. И так по всей картинке. В итоге мы будем иметь только контур нашего синего круга. И так, мы получили GraphicsPath, сделали из него регион, и обозначили его в кнопку. Осталось только обозначить background нашего контура нужным рисунком (тем же, из которого стряпали регион). В общих чертах все, разберем на нашем примере.
Класс UnStdControl
Создадим класс UnStdControl, в котором и будет лепиться наша кнопка. Создадим в нем для начала функцию, возвращающую GraphicsPath, с входящим параметром в виде Bitmap, в который заключен ваш рисунок:
private static GraphicsPath ControlGraphicsPath (Bitmap bmp ) { GraphicsPath gp = new GraphicsPath (); Color transparentColor = bmp. GetPixel(0, 0); int colOpaquePixel = 0; for (int row = 0; row < bmp. Height; row++ ) { colOpaquePixel = 0; for (int col = 0; col < bmp. Width; col++ ) { if (bmp. GetPixel(col, row ) != transparentColor ) { colOpaquePixel = col; int nextCol = col; for (nextCol = colOpaquePixel; nextCol < bmp. Width; nextCol++ ) if (bmp. GetPixel(nextCol, row ) == transparentColor ) break; gp. AddRectangle(new Rectangle (colOpaquePixel, row, nextCol - colOpaquePixel, 1)); col = nextCol; } } } return gp; }Syhi-подсветка кода
transparentColor – это цвет первого пикселя, который будем считать за прозрачный и впоследствии отсекать.
colOpaquePixel – положение первого попавшегося непрозрачного пикселя по оси X (т.е номер столбца).
Заводим сначала цикл, который будет пробегать все строки сверху вниз (row - строка), затем в нем цикл, который будет в этих строках проверять все столбцы(col). При переводе курсора на новую строку переменная colOpaquePixel обнуляется. В последнем цикле и происходит самое интересное. Если попадается наконец-то непрозрачный пиксель, то переменной colOpaquePixel задается значение положения столбца, заводится новая переменная (nextCol), которая будет считать количество непрозрачных пикселей. Для подсчета создается следующий цикл, который будет переходить от пикселя к пикселю, увеличивая значение nextCol на единицу, пока не упрется в прозрачный пиксель. После этого в наш GraphicsPath добавляется прямоугольник с параметрами:
- Координата X: colOpaquePixel – номер столбца первого найденного непрозрачного пикселя
- Координата Y: row – номер соответственно строки.
- Длинна (width) : разница количества найденных пикселей (nextCol) и номера столбца первого найденного непрозрачного пикселя. Тут необходимо заметить, что переменная nextCol считает количество символов от начала строки до прозрачного пикселя.
- Ширина (height): единица.
Далее переводим курсор цикла по столбцам на положение найденного прозрачного пикселя (col = nextCol).По окончанию всех циклов получаем наш контур (GraphicsPath) и возвращаем его.
Теперь создаем функцию, которая будет делать из нашей кнопки нужную нам конфетку. Входящие параметры функции – контрол (кнопка) и Bitmap с нашим рисунком.
public static void CreateControlRegion (Control control, Bitmap bmp ) { control. Width = bmp. Width; control. Height = bmp. Height; if (control is Button ) { Button button = (Button )control; button. Text = ""; button. BackgroundImage = bmp; GraphicsPath gp = ControlGraphicsPath (bmp ); button. Cursor = Cursors. Hand; button. Region = new Region (gp ); } }Syhi-подсветка кода
Для начала кнопке задаем параметры длины и ширины, равных параметрам рисунка. Далее проверяем с кнопкой ли мы собрались работать, если да, то объявляем ее и выставляем новые параметры. Обнуляем текст. Затем фоном ставим нашу картинку, что бы контур был не пустой (вернее не со стандартной картинкой баттона). Объявляем GraphicsPath с помощью описанной выше функции с входящим параметром в виде нашего изображения, указываем нужный вид курсора, и, наконец, задаем регион кнопки с помощью нового GraphicsPath. Все, кнопка готова, осталось только нарисовать ее на форме и преобразить.
Основной класс формы.
В основном классе формы мы для начала объявляем картинку, с которой будем рисовать кнопку:
Изображение в данном случае должно находиться в корне папки Debug. Ну и далее применяем все, что было описано выше для отображения нужной кнопки в заданном виде:
И напоследок...
Нужные картинки лучше рисовать с фоновым цветом, резко отличающимся от цвета самого изображения. Вообще-то это не самый лучший способ для создания нестандартных форм, но, для понимания процесса, я думаю, подходит.
Скачать исходник
|