Сегодня я напишу как в javafx создаются (наследуются) классы, как работать с массивами и немного всякой всячины. Сделаю я это на примере меню, которое будет оформлено в стиле MacOS дока. Итак поехали. Часть 1 — Создаем свои кнопки
Создадим новый JavaFX class который будет представлять из себя кастомную кнопку в доке. делается это легко и просто (импорты я упущу ибо бумагу надо экономить): ImageButton.fx
package lesson2;
publicclassImageButtonextendsCustomNode { // Подпись кнопки publicvar title:String; // Изображение из которого будем делать кнопку publicvar buttonImage:Image; // URL того самого изображения <b>*</b> publicvar imageUrl:String on replace { buttonImage =Image{ url: imageUrl }; } // Степень увеличения размера когда курсор не наведен (больше единицы //уменьшение реального размера, меньше увеличение измеряются в процентах) publicvar nonRolloverScale:Number=0.9; // Степень прозрачности когда курсор не наведен publicvar nonRolloverOpacity:Number=.80; // параметр который нам пригодится когда будем менять размер // кнопки которая активна publicvar fade:Number=1.0; // параметр, который говорит курсор мыши на объекте или нет var mouseInside =false;
//собственно анимация <b>**</b> publicvar fadeTimeLine = Timeline{ keyFrames:[ KeyFrame{ time:0ms values:[ fade =>0.0 ] }, KeyFrame{ time:600ms values:[ fade =>1.0 tween Interpolator.LINEAR ] } ] }; //функция которая будет выполнятся при клике на кнопку //у нас она не будет делать ничего. publicvar action:function():Void; //подпись кнопки publicvar textRef:Text; }
Теперь немного пояснений по пунктам. *on replace означает что при изменении параметра imageUrl нужно изменить сам параметр buttonImage ** Класс Timeline отвечает за изменение некоторых параметров с течением времени. Должен содержать массив объектов KeyFrame — которые отвечают за изменение определенных параметром с течением времени. В нашем простом случае будет 2 KayFrame`а логика действия следующая. Когда вызывается метод стартующий анимацию (у нас он будет написан чуть позже play() или playFromStart())вызывается первый KeyFrame (c минимальным значением параметра time)в нем будет изменет параметр (fade => 0.0), затем через 600ms вызывается второй и меняет параметр на 1.0 линейно. Если бы был третий KeyFrame то затем вызвался бы он. Все до безобразия просто. Надо отметить что по-умолчанию все переменные имею модификатор видимости script-only т.е. private.
Перейдем к последнему методу который вы должны обязятельно реализовать если наследуете класс CustomNode — метод create(). ImageButton.fx
//функция create которая должна вернуть объект типа Node overridepublicfunction create():Node{ // мы же вернем группу (т.е. несколько виджетов объединены в один) returnGroup{ content:[ // выделяем прямоугольник размером с картинку Rectangle{ width: bind buttonImage.width height: bind buttonImage.height opacity:0.0 }, //затем добавляем собственно картинку. ничего интересного с точки зрения //изучения языка тут нет кроме обработки событий мыши, которые я поясню ниже <b>*</b> ImageView{
* если вы хотите обрабатывать то или иное событие то просто нужно вписать свою функцию-обработчик в нужное вам поле. Функция обязательно должна принимать событие которым вызвана (т.е. у нас принимается me:MouseEvent, т.к. обрабатываем события мыши). При нажатии на нашу кнопку будет использован эффект Glow (осветление). Часть 2 — создаем панельку в которой будут кнопки DockNode.fx
package lesson2;
publicclassDockNodeextendsCustomNode{
//Высота панели publicvar height:Float; //Ширина панели publicvar widght:Float; var spacing =9; publicvar buttons:ImageButton[]; //Уже известный нам метод create() overridepublicfunction create():Node{ height =0.0; //Мы впервые используем цикл :) <b>*</b> for(i in buttons){ widght = widght + buttons[{indexof i}].buttonImage.width +3*spacing; var loc_height = buttons[{indexof i}].buttonImage.height*2+16; if(height<loc_height) height = loc_height; } //Возвращаем горизонтальную патель с эффектом отражения returnHBox{ hpos:HPos.CENTER vpos:VPos.CENTER spacing: spacing content: buttons effect:Reflection{ fraction:0.75 topOffset:0.0 topOpacity:0.5 bottomOpacity:0.0 } }
}; }
Тут по большому счету ничего интересного нет, кроме того что мы использовали цикл for. Формат этого оператора может быть либо
for(<variable>in<sequence>){ // Тело цикла }
ну или
for(i in[1..100]){ println("Iteration: {i}"); }
Первый случай похож на реализацию for`а в языке lua — на каждой итерации вы получаете очередное значение из последовательности (массива). Узнать положение элемента a в массиве array можно так: array[indexof a].
Во втором случае вы просто указываете что переменная i изменяется от 1 до 100.
Ну и наконец главный скрипт который будет все это запускать: Main.fx
Тут в пояснениях может нуждаться только запись вида __DIR__. Так же как и __FILE__ означают директорию и файл сответственно, скрипта в котором это написано.
В результате таких мучений у нас получится что-то вроде такого:
Когда наведена мышь
Когда кликнули
Всем спасибо, за внимание. В следующем топике постараюсь ответить на пожелание Reorcs:«но так как меня мало интересует КАК это писать, кроме основных вещей. мне было бы больше интересно читать о том КАК это дизайнится, и насколько сложно поддерживается, и как БЫСТРО работает»