Виртуальный GUI на Scala



Рассмотрим создание приложения с графическим интерфейсом, которое может работать на рабочем столе, в браузере и под Android без изменения кода Live Demo c с моего сайта.

Естественно, нам понадобятся библиотеки-фасады, которые инкапсулируют разницу между библиотеками контролов этих систем (JavaFX, Android, DOM)

Для создания таких фасадов прекрасно подходят implicit классы. Например:
implicit class TextFieldExt(txt: Text) {
    def text=txt.getText
    def text_=(a: Any) = txt.setText(a.toString)
}
Так мы сможем создать GUI не только на методах, но и на свойствах:
btHello.text=”Hello”
Но не в DOM, не в Android нет готового контрола Table. Доработка существующих уже там виджетов на implicit классах невозможна,необходимо сохранять состояние. Поэтому Table – это обычный класс. Кроме этого в Android для табличных данных необходим
ещё класс адаптера. Среди стандартных адаптеров нет такого,что умеет работать с Array, ArrayList ,ArrayBuffer в которых сохраняются классы данных. Пришлось написать свой ItemAdapter.
Для обработки структур данных в которых виджет это поле,в котором могут быть различные классы виджетов:
val card=Array(new Card{id=txtName, prop=TEXT,....},new Card{id=cbCat, prop=INDEX...},....)
нас выручит мощный механизм сопоставления с образцом :
for(c<-card :text="" c.id="" case="" match="" text="">text.text=...
	    case combo: Combo => combo.index=...
	    ….....
	}
}
Ещё одной проблемой есть то,что в каждой из трёх систем свой механизм инициализации графического интерфейса.
Возможно стабилизация API макросов и моё свободное время решат эту проблему в будущем. А пока что так))

Посмотреть код для Android:
class MorgFx extends AppCompatActivity  {
	override def onCreate(savedInstanceState: Bundle)={
    		super.onCreate(savedInstanceState)
		setContentView(R.layout.hello_app)
		val context:Context = this
		val root=this

		val btHello = root.elem(R.layout.btHello).asInstanceOf[Button]
		val cbHello = root.elem(R.layout.cbHello).asInstanceOf[Combo]
		val txtHello = root.elem(R.layout.txtHello).asInstanceOf[Text]
		cbHello.fill(Array("man","woman"), context)
		btHello.onSelect(btSelect)
		def btSelect(sender:Any){
  			context.showMessage(txtHello.text)
		}		
	}
}

Посмотреть код для браузера:
object HelloApp extends JSApp {
 	def main(): Unit = {  
		val context=startGUI("divHello")
		val root=context

		val btHello = root.elem("#btHello").asInstanceOf[Button]
		val cbHello = root.elem("#cbHello").asInstanceOf[Combo]
		val txtHello = root.elem("#txtHello").asInstanceOf[Text]
		cbHello.fill(Array("man","woman"), context)
		btHello.onSelect(btSelect);
		def btSelect(sender:Any){
  			context.showMessage(txtHello.text)
		}
	}
}

Посмотреть код для рабочего стола:
object HelloApp {
	def main(args: Array[String]): Unit ={
    		Application.launch(classOf[HelloApp], args: _*)
  	}
}
class HelloApp  extends  Application {
	type Combo = ComboBox[String]
  	override def start(stage: Stage): Unit = {
    		val context = stage
    		val root = context.startGUI("divHello")
    		
		val btHello = root.elem("#btHello").asInstanceOf[Button]
		val cbHello = root.elem("#cbHello").asInstanceOf[Combo]
		val txtHello = root.elem("#txtHello").asInstanceOf[Text]
		btHello.onSelect(btSelect);
		def btSelect(sender:Any){
  			context.showMessage(txtHello.text)
		}
	}
}

Ссылка на GHub:s https://github.com/anatoly62/scala-gui

Комментарии

  1. Виртуальный GUI - это хорошо. Какие мысли о инкапсуляции синхронности/ асинхронности?

    ОтветитьУдалить
  2. Есть не мысли, есть реализация в рабочем проекте. Future c функцией onComplete разной для Java и JavaScript. Напишу про это статью в начале июля.

    ОтветитьУдалить

Отправить комментарий

Популярные сообщения из этого блога

Работа с глобальными переменными в Rust

IUP - библиотека элементов GUI

Виртуальный GUI на Rust