В данном примере реализации есть ограничения заключающееся в том, что поле предназначено для одно строчного ввода и нельзя переместить каретку в середину текста и начать ввод туда. Этот элемент пользовательского интерфейса состоит из 3-х элементов: текст, окантовка, каретка. Изменив которые можно добиватся необходимого результата. Начнем с окантовки, она реализована в классе GUIBorder вот код:Код public class GUIBorder extends GUIElement{ public int borderDepth; private Texture texture; private Color color; private boolean useTransparent; public GUIBorder(int x,int y,int heigth,int width,Color color) { super(x,y,heigth,width); borderDepth = 2; texture = new Texture(8, 8, color); //useTransparent = true; } public void setTexture(Texture texture) { this.texture = texture; }
@Override public void evaluteInput(InputMap inputMap) { }
@Override public void Action() { }
@Override public void Draw(FrameBuffer buffer) { //верхняя линия buffer.blit(texture, 0, 0, this.x, this.y, width, borderDepth, useTransparent); //правая линия buffer.blit(texture, 0, 0, x+width, y, borderDepth, heigth, useTransparent); //нижняя линия buffer.blit(texture, 0, 0, x, y+heigth-borderDepth, width, borderDepth, useTransparent); //левая линия buffer.blit(texture, 0, 0, x, y, borderDepth, heigth, useTransparent); } Из кода видно что класс является наследником GUIElement поэтому в нем реализованы все абстрактные методы, несмотря на то что некоторые из них в данной реализации не нужны. Для отображения рамки создается текстура размером 8х8(создать текстуру меньшего размера мне не удалось т.к. если задать ее меньше 8х8 то текстура будет 256х256) с необходимым цветом, что позволяет избежать необходимости загружать ее с диска. Теперь рассмотрим реализацию классов GUITextField и GUICaret, содержащих функционал вывода текста и отображении каретки. Код public class GUITextField extends GUIElement{ private GLFont font; //private int rowCount; private StringBuilder text; private GUICaret caret; private GUIBorder border; private boolean isFocus; private int txt_visible_start=0; public GUITextField(int x,int y,int heigth,int width) { super(x,y,heigth,width); // rowCount = 1; text = new StringBuilder(); font = new GLFont(new Font("Times New Roman", 0, 12),GLFont.RUSSIAN+GLFont.ENGLISH); caret = new GUICaret(x, y, font); //добавляем как дочерний элемент; this.Add(caret); border = new GUIBorder(x, y, heigth, width, Color.GRAY); this.Add(border); }
@Override public void evaluteInput(InputMap inputMap) { if(getVisible()) { //обрабатываем ввод для дочерних элементов for (Object child:this.getChildrens()) { ((GUIElement)child).evaluteInput(inputMap); } int xpos = inputMap.mouse_x; int ypos = inputMap.mouse_y;
if((xpos>=x)&&(xpos<=x+width)&&(ypos>=y)&&(ypos<=y+heigth)) { if (inputMap.mouse_leftbutton_down) { Game.guiManager.setFocusElement(this); inputMap.isActionMode = false; caret.setVisible(true); } } if ((!inputMap.isActionMode)&&isFocus) { this.text.append(inputMap.inputString); if (font.getStringBounds(text.toString()).width>width-border.borderDepth) { txt_visible_start=0; String tmp = text.substring(txt_visible_start); while(font.getStringBounds(tmp).width>width-border.borderDepth) { txt_visible_start++; tmp = text.substring(txt_visible_start); } } inputMap.inputString = ""; caret.setCaretPosition(text.length()); } if (inputMap.backspace&&isFocus) { if (text.length()!=0) { String tmp = text.substring(0, text.length()-1); text.delete(0, text.length()); text.append(tmp); } inputMap.backspace = false; } } }
@Override public void Action() { throw new UnsupportedOperationException("Not supported yet."); }
@Override public void Draw(FrameBuffer buffer) { String tmp_str; if (txt_visible_start>0) { tmp_str = text.substring(txt_visible_start); } else { tmp_str = text.toString(); } font.blitString(buffer, tmp_str, x+border.borderDepth+1, y+font.fontHeight, 1, Color.BLACK); //рисуем связаные элементы for(Object child:this.getChildrens()) { ((GUIElement)child).Draw(buffer); } } public void setFont(GLFont font) { this.font = font; } public void setText(String text) { StringBuilder tmp = new StringBuilder(text); this.text = tmp; caret.setCaretPosition(text.length()); } @Override public void setFocus(boolean isFocus) { this.isFocus = isFocus; caret.setVisible(isFocus); } private class GUICaret extends GUIElement { private GLFont font; private int caretPos; private Texture texture; private Timer timer; private boolean cartblit=true; public GUICaret(int x,int y,GLFont font) { //инициализируем параметры super (x,y,10,font.fontHeight); this.font = font; texture = new Texture(8, 8, Color.BLACK); timer = new Timer(700); timer.start(); setVisible(false); } @Override public void evaluteInput(InputMap inputMap) { //если активен для ввода if (getFocus()) { this.setVisible(true); setCaretPosition(text.length()); } }
@Override public void Action() { }
@Override public void Draw(FrameBuffer buffer) { if(this.getVisible()) { if (timer.getElapsedTicks()>0) { this.cartblit =!this.cartblit; } if(this.cartblit) { buffer.blit(texture, 0, 0,this.x+border.borderDepth,this.y, 1, font.getBaseLine()+font.fontHeight/2, false); } } } private void setCaretPosition(int pos) { if (caretPos!=pos) { int l; if (txt_visible_start>0) { l = font.getStringBounds(text.substring(txt_visible_start)).width; } else { l = font.getStringBounds(text.toString()).width; } this.x=getParent().x+l; caretPos = pos; } } } } Класс каретки GUICaret является внутренним для GUITextField и они оба унаследованы от GUIElement. В реализации класса основным моментом является организация ввода. Для этого в класс GUIManager была добавлена информация о элементе находящемся в фокусе ввода(функция setFocusElement позволяет корректно обрабатывать эти моменты), а также в класс GUIElement были добавлены поля и методы для хранения информации о том находится ли фокус ввода на них, это позволило унифицировать работу с ними. Также в классе собирающим информацию с устройств ввода InputMap была добавлена информация о режиме работы. Она позволяет определять куда необходимо направлять информацию в текущий фокус элемент или нет. Каретка создается из текстуры черного цвета по такому же принципу как и в классе GUIBorder, эффект моргания достигается использованием Timer c периодом 700 мс. Создание текстового поля отличается от создания GUIButton тем, что не происходит перегрузка функции Action, т.к. никаких действий не требуется. Код GUITextField tfield = new GUITextField(100, 120, 20, 200); tfield.setText("Тут"); guiManager.Add(tfield); GUITextField tfield2 = new GUITextField(300, 200, 20, 100); guiManager.Add(tfield2);
Технически возможно задать любую реакцию, но необходимо не забыть изменить также обработку в evaluteInput(), например если необходимо добавить реакцию на нажатие клавиши Enter то в функцию необходимо добавить код: Код if (inputMap.enter) { Action(); } Это все если, что то не понятно задавайте вопросы.
|