ddl是第一生产力,此言不虚,ddl过后偶然想把一些东西mark down ,纪念最近ddl下支配的恐惧【哭笑】
界面近来一直用javafx来写,对fx的整体框架清晰了不少(特别是不依赖scene builder进行类似于swing的界面编写),主要说一下fx中图表的特点吧。
关于javafx画图
fx里的图表是基于一个个series来显示其中的内容,包括series下的数据和node(可以理解成一棵树,最上面是Group,下面可以放各种node),然后需要在chart的data中放入事先定义的series(当然series也有getData方法得到之前塞进去的数据,这些数据就是用来显示的)
chart.getData().add(series)
Data<String , Number> data = series.getData();
关于Data,构造方法最多只有3个参数,如果需要自定义比较复杂的显示,就把除了x,y值之外的东西打成一个Javabean放到第三个参数里,之后绘图的时候再取出来用(用fx自带的图表应该直接用就行了不像自己画得那么麻烦)
/**
* Creates an instance of XYChart.Data object and initializes the X,Y
* data values and extraValue.
*
* @param xValue The X axis data value.
* @param yValue The Y axis data value.
* @param extraValue Chart extra value.
*/
public Data(X xValue, Y yValue, Object extraValue) {
setXValue(xValue);
setYValue(yValue);
setExtraValue(extraValue);
setCurrentX(xValue);
setCurrentY(yValue);
setCurrentExtraValue(extraValue);
}
然后是关于创建图的执行顺序:
先是调用series的add方法,然后调用item的add方法把node塞进series,第一个series塞完后再add第二个series,以此类推。
然后等series塞完后更新坐标轴范围,调用updateAxisRange方法,这个不一定要重写看需要吧。
最后调用layoutPlotChildren方法,相当于是在画布上设置一个个node的位置把它画出来,算是显示最关键的一步。
@Override
protected void dataItemAdded(Series<String, Number> series,
int itemIndex, Data<String, Number> item) {
Node candle = creatNode(item);
getPlotChildren().add(candle);
}
@Override
protected void dataItemRemoved(Data<String, Number> item,
Series<String, Number> series) {
}
@Override
protected void dataItemChanged(Data<String, Number> item) {
}
@Override
protected void seriesAdded(Series<String, Number> series,
int seriesIndex) {
if(seriesIndex == SPECTIALINDEX)
for (Data item : series.getData()) {
Node kNode = creatNode(item);
getPlotChildren().add(kNode);
}
}
else {
Path path = new Path();
series.setNode(path);
getPlotChildren().add(path);
}
}
@Override
protected void seriesRemoved(Series<String, Number> series) {
Path path = (Path) series.getNode();
path.setVisible(false);
}
@Override
protected void layoutPlotChildren() {
if (getData() == null) {
return;
}
.......(略过)
}
@Override
protected void updateAxisRange() {
........
}
继承XYChart的自定义图表需要实现series的增删方法和series中item 的增删改方法(必须有series增加和item增加啊不然没东西显示)。当然还有layoutPlotChildren。一般自己动手画也就是把一些元素组合起来,比如k线图就是各类path再加bar(Region),然后bar上加一条线(Line)。PS:也是参考demo的。
关于lambda表达式
算是尝试着在java中用lambda写点东西,特别是双目符号(::)的使用(java中应该也叫这个吧)顿时feel到了c++的函数指针用法。
一般在fx的initialize方法中设定对应关系都会用lambda表达式
peColumn.setCellValueFactory(cell -> newSimpleDoubleProperty(cell.getValue().pe));
pbColumn.setCellValueFactory(cell -> new SimpleDoubleProperty(cell.getValue().pb));
参数和返回值的对应关系。。我暂时这样理解。在做监听的时候也省去了匿名内部类
choiceBox.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> {
calculate();
});
类似的还用过lambda写线程等等,应用的方面挺多。
调用逻辑层方法的遇到了一个问题,一些接口的参数列表和返回值都是相同的,比如根据起始终止条件得到一个Collection<…>。每次判断再显式调用方法就显得很冗余,扩展性不好。于是就试着用::
interface MACDSource {
Collection<MacdVO> getData(String stockCode, LocalDate startDate,
LocalDate endDate) throws NetworkConnectionException;
}
/**
* 获得MACD数据
*/
private void getMACDData(LocalDate startDate, LocalDate endDate,
MACDSource source) {
Collection<MacdVO> macdVOs = null;
try {
macdVOs = source
.getData(stockVO.getStockCode(), startDate, endDate);
} catch (NetworkConnectionException e) {
new NetExceptionTips("Please check the net");
e.printStackTrace();
}
...
}
逻辑层的接口
/**
...
*/
Collection<MacdVO> getMacdD(String stockCode, LocalDate begin, LocalDate end) throws NetworkConnectionException;
Collection<MacdVO> getMacdW(String stockCode, LocalDate begin, LocalDate end) throws NetworkConnectionException;
Collection<MacdVO> getMacdM(String stockCode, LocalDate begin, LocalDate end) throws NetworkConnectionException;
声明的interface里只有一个方法,保证参数列表和返回值和需要实际调用的方法相同。这样,就可以把传入这个接口,把接口当成一个函数指针,用::的方式表明这个地方传入的是哪个函数的“指针”
getMACDData(beginDate, endDate, stockAnalysis::getMacdW);
getMACDData(beginDate, endDate, stockAnalysis::getMacdD);
这样就算之后有变动也好处理很多。
anyway,暂时想到这些。然后,身体最重要,远离ddl。。。