class WeatherApp : App(WeatherView::class)
class WeatherView : View("十五天天气预报") {
val weatherVM: WeatherViewModel by inject()
val controller: WeatherController by inject()
var hdata: XYChart.Series<String, Number> by singleAssign()
var ldata: XYChart.Series<String, Number> by singleAssign()
override val root = borderpane {
bottom = hbox(4) {
progressbar(controller.taskProgress)
label(controller.taskMessage)
visibleWhen { controller.taskRunning }
paddingAll = 4
}
left = vbox(4) {
// button("refresh") {
// action {
// controller.refresh()
// }
// }
textfield(weatherVM.city)
listview(controller.cities) {
bindSelected(weatherVM.city)
onUserSelect(1) {
controller.refresh()
}
}
}
center = tableview(controller.weathers) {
column("date", Weather::dateProperty)
column("type", Weather::typeProperty)
column("高温℃", Weather::highProperty)
column("低温℃", Weather::lowProperty)
column("风向", Weather::fxProperty)
bindSelected(weatherVM)
smartResize()
}
right = linechart("十五天天气预报", CategoryAxis(), NumberAxis()) {
id="lc"
prefWidth=600.0
// 设置成false可避免在第一次显示数据时,x轴的下标堆积在一起
animated=false
series("高温") {
hdata = this
}
series("低温") {
ldata = this
}
}
}
}
class WeatherController : Controller() {
val api: Rest by inject()
val weathers = observableListOf<Weather>()
val cities = observableListOf<String>()
val weatherVM: WeatherViewModel by inject()
val v: WeatherView by inject()
val taskRunning = booleanProperty()
val taskMessage = stringProperty()
val taskProgress = doubleProperty()
fun refresh() {
v.title = weatherVM.city.value.split(",").first().plus(" 未来十五天天气预报")
val t = task {
loadWeathers(weatherVM.city.value.toString().split(",").last())
updateMessage("Loading weathers")
updateProgress(0.4, 1.0)
}
t.run()
taskRunning.bind(t.runningProperty())
taskMessage.bind(t.messageProperty())
taskProgress.bind(t.progressProperty())
}
// 文件中读取城市列表
// fun loadCities1() = GlobalScope.launch {
// cities.clear()
// // 使用hutool的FileUtil工具类,可正常读取resources下的资源文件
//// FileUtil.readLines("city.csv", "gbk").forEach {
//// cities.add(it)
//// }
//
// // 使用tornadofx框架的resources无法读取文件内容,原因不明
//// File(resources.url("city.csv").toExternalForm()).readLines().forEach {
//// cities.add(it)
//// }
//
// File(javaClass.getResource("/city.csv").toURI()).readLines().forEach {
// cities.add(it)
// }
// }
// 从文件中读取城市名称及其代码数据,填充到listview中
fun loadCities() {
cities.clear()
run {
File(javaClass.getResource("/city.csv").toURI()).readLines().forEach {
cities.add(it)
}
}
}
// citykey:城市ID,如:"101030100"
fun loadWeathers(citykey: String) {
// 更新前清空数据
weathers.clear()
v.hdata.data.clear()
v.ldata.data.clear()
// 安徽 101030100
val json = api.get(citykey).one()
val dates = JsonPath.read(json.toString(), "$.data.forecast[*].ymd") as List<String>
val types = JsonPath.read(json.toString(), "$.data.forecast[*].type") as List<String>
val city = JsonPath.read(json.toString(), "$.cityInfo.city") as String
val time = JsonPath.read(json.toString(), "$.time") as String
val quality = JsonPath.read(json.toString(), "$.data.quality") as String
val wendu = JsonPath.read(json.toString(), "$.data.wendu") as String
val shidu = JsonPath.read(json.toString(), "$.data.shidu") as String
val pm25 = JsonPath.read(json.toString(), "$.data.pm25") as Double
val pm10 = JsonPath.read(json.toString(), "$.data.pm10") as Double
val highs = JsonPath.read(json.toString(), "$.data.forecast[*].high") as List<String>
val lows = JsonPath.read(json.toString(), "$.data.forecast[*].low") as List<String>
val fxs = JsonPath.read(json.toString(), "$.data.forecast[*].fx") as List<String>
dates.indices.forEach {
val w = Weather()
w.date = dates[it]
w.type = types[it]
w.fx = fxs[it]
w.city = city
w.quality = quality
w.time = time
w.high = highs[it].split(" ").last().trimEnd('℃')
w.low = lows[it].split(" ").last().trimEnd('℃')
weathers.add(w)
val date = dates[it].split("-").drop(1).joinToString("/")
v.hdata.data(date, w.high.toInt()) {
node.add(Text(w.high))
node.tooltip(w.type)
// Tooltip.install(node, Tooltip(w.high))
}
v.ldata.data(date, w.low.toInt()) {
node.add(Text(w.low))
}
}
// 通过控件id 找到要操作的控件
(primaryStage.scene.lookup("#lc") as LineChart<String,Number>).title=v.title
// (v.root.right as LineChart<String,Number>).title=v.title
v.title+=" 当前天气:$quality, 更新时间:$time, 温度:$wendu, 湿度:$shidu, pm25:$pm25, pm10:$pm10"
// read(json, "$.store.book[*].author")
// val d=json.get("data")
// val forecast= JSONUtil.parseObj(d).get("forecast")
// println(forecast.toString())
// println(JSONUtil.parseObj().get("ymd"))
// weathers.addAll(api.get("101030100").list().toModel())
}
fun loadWeathers1(citykey: String) {
weathers.clear()
// 此方法无法正确得到想要的数据
weathers.addAll(api.get(citykey).list().toModel())
}
init {
api.baseURI = "http://t.weather.sojson.com/api/weather/city/"
loadCities()
}
}
class Weather : JsonModel {
val cityProperty = stringProperty("")
var city by cityProperty
val dateProperty = stringProperty()
var date by dateProperty
val typeProperty = stringProperty()
var type by typeProperty
val timeProperty = stringProperty()
var time by timeProperty
val highProperty = stringProperty()
var high by highProperty
val lowProperty = stringProperty()
var low by lowProperty
val shiduProperty = stringProperty("34%")
var shidu by shiduProperty
val qualityProperty = stringProperty("良")
var quality by qualityProperty
val wenduProperty = stringProperty("16")
var wendu by wenduProperty
val fxProperty = stringProperty("西风")
var fx by fxProperty
override fun toString() = "$city"
override fun updateModel(json: JsonObject) = with(json) {
}
}
class WeatherViewModel : ItemViewModel<Weather>() {
val city = bind(defaultValue = "") { item?.cityProperty }
val type = bind { item?.typeProperty }
val date = bind{ item?.dateProperty }
val time = bind { item?.timeProperty }
val high = bind { item?.highProperty }
val low = bind { item?.lowProperty }
val fx = bind { item?.fxProperty }
val quality = bind { item?.qualityProperty }
}