如下图所示,你有对列表中的数据选中后进行上下移动排序吗?
选中一条数据和选中多条数据的排序算法一样吗?怎么实现的呢?
最近有这么一个需求,写了一个排序算法。在写的过程中发现,选中一条数据,上下移动是非常简单的。选中多条数据,再进行上下移动就没有那么容易了,需要动脑想一想。现在就把这段算法的实现分享一下。排序算法在该类中的最后一个方法中。
代码实现:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.util.StringUtils;
import com.example.demo.tableview.Sex;
import com.example.demo.tableview.User;
import javafx.application.Application;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ChoiceBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
* 参考官网:https://docs.oracle.com/javafx/2/ui_controls/table-view.htm
* 可编辑tableview示例
* @author 程就人生
* @Date
*/
@SuppressWarnings("restriction")
public class TableViewOrderSamle extends Application {
// tableview列表
private TableView tableView = new TableView();
// 用户获取
private final ObservableList data =
FXCollections.observableArrayList(
new User("张三","001",1),
new User("李四","002",1),
new User("王五","003",1),
new User("alice","004",1),
new User("andy","005",1),
new User("feng","006",1),
new User("zhang","007",1),
new User("1111","008",1),
new User("33333","009",1));
final HBox hb = new HBox();
// 被选中的uid
private List uids = new ArrayList();
// 上移按钮
private Button upButton;
// 下移按钮
private Button downButton;
// 下移按钮
private Button saveButton;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("用户信息");
stage.setWidth(450);
stage.setHeight(550);
// 设置为可编辑
tableView.setEditable(true);
// 复选框
TableColumn checkboxCol = new TableColumn("");
checkboxCol.setMinWidth(50);
// 展示值设置
checkboxCol.setCellValueFactory(new PropertyValueFactory("uid"));
// 多选框展示
checkboxCol.setCellFactory(new Callback, TableCell>() {
@Override
public TableCell call(TableColumn param) {
TextFieldTableCell cell = new TextFieldTableCell(){
@Override
public void updateItem(String item, boolean empty) {
// 不为空时再展示
if(!StringUtils.isEmpty(item) && !empty){
CheckBox checkBox = new CheckBox();
if(uids.contains(item)){
checkBox.setSelected(true);
}
HBox hbox = new HBox();
hbox.setAlignment(Pos.CENTER);
hbox.getChildren().add(checkBox);
// 增加监听
checkBox.selectedProperty().addListener(new ChangeListener() {
@Override
public void changed(ObservableValue extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if(newValue){
uids.add(item);
}else{
uids.remove(item);
}
}
});
this.setGraphic(hbox);
}
}
};
return cell;
}
});
// 员工号的展示和编辑
TableColumn uidCol = new TableColumn("员工号");
uidCol.setMinWidth(100);
uidCol.setCellFactory(TextFieldTableCell.forTableColumn());
uidCol.setCellValueFactory(new PropertyValueFactory("uid"));
// 姓名的展示和编辑
TableColumn nameCol = new TableColumn("姓名");
nameCol.setMinWidth(100);
nameCol.setCellFactory(TextFieldTableCell.forTableColumn());
nameCol.setCellValueFactory(new PropertyValueFactory("name"));
TableColumn sexCol = new TableColumn("性别");
sexCol.setMinWidth(50);
sexCol.setCellValueFactory(new PropertyValueFactory("sex"));
// 性别下拉框的展示
sexCol.setCellValueFactory(new Callback, ObservableValue>() {
public ObservableValue call(CellDataFeatures p) {
// 通过产品名称获取产品型号编码
return new ReadOnlyObjectWrapper(Sex.getValue(p.getValue().getSex()));
}
});
// 性别的获取
sexCol.setCellFactory(ChoiceBoxTableCell.forTableColumn(FXCollections.observableArrayList(Sex.valueList())));
// 数据填充
tableView.setItems(data);
tableView.getColumns().add(checkboxCol);
tableView.getColumns().add(uidCol);
tableView.getColumns().add(nameCol);
tableView.getColumns().add(sexCol);
final Button orderButton = new Button("排序");
orderButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
upButton.setVisible(true);
downButton.setVisible(true);
saveButton.setVisible(true);
orderButton.setVisible(false);
}
});
upButton = new Button("上移");
upButton.setVisible(false);
upButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
upMove();
}
});
downButton = new Button("下移");
downButton.setVisible(false);
downButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
downMove();
}
});
saveButton = new Button("保存排序");
saveButton.setVisible(false);
saveButton.setOnAction(new EventHandler() {
@Override
public void handle(ActionEvent e) {
upButton.setVisible(false);
downButton.setVisible(false);
saveButton.setVisible(false);
orderButton.setVisible(true);
// 保存排序
saveOrder();
}
});
final Label label = new Label("用户列表");
label.setFont(new Font("Arial", 20));
HBox hb2 = new HBox();
hb2.setSpacing(5);
// 设置padding 上、右、低、左
hb2.setPadding(new Insets(10, 0, 0, 10));
hb2.getChildren().addAll(label,orderButton,upButton, downButton, saveButton);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(hb2, tableView);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
/**
* 上移操作
*/
private void upMove(){
order(-1);
}
/**
* 下移操作
*/
private void downMove(){
order(1);
}
/**
* 保存排序
*/
private void saveOrder(){
// 清空所选
uids.clear();
// 表格刷新
tableView.refresh();
}
/**
* 排序
* @param flag
*/
private void order(int flag){
// 数据总量
int size = data.size();
// 需要移动的数据
User findSensor;
// 被移动的数据
User tempSensor;
// 定义一个数组,获取被选中数据的实际顺序
String[] orderUsers = new String[size];
// 默认填充null
Arrays.fill(orderUsers, null);
for(String uid : uids){
findSensor = data.stream().filter(sensor->sensor.getUid().equals(uid)).findFirst().get();
orderUsers[data.indexOf(findSensor)] = uid;
}
// 向上移动
if(flag == -1){
for(int i=0;i -1){
tempSensor = data.get(i + flag);
findSensor = data.get(i);
// 互换位置
data.set(i, tempSensor);
data.set(i + flag, findSensor);
}
}
}
}else{
// 向下移动
for(int i = size -1; i > -1 ; i--){
if(!StringUtils.isEmpty(orderUsers[i])){
if(i < size-1 && i + flag < size){
tempSensor = data.get(i + flag);
findSensor = data.get(i);
data.set(i, tempSensor);
data.set(i + flag, findSensor);
}
}
}
}
// 排序后,列表展示刷新
tableView.refresh();
}
}
说明:该类中的最后一个方法,是上下移动排序的算法。我们对于要选择的数据,是没有规则的,有可能先勾选这条数据,然后再勾选那条数据,既有可能点击向上移动,又有可能点击向下移动。
因此,在本算法中,先查找每条选中数据在所有数据中的索引。然后再看是上移,还是下移。如果是上移,把每条数据和所在索引的上一条数据互换位置即可。如果是下移,那么就需要反向变换位置,先移动索引在下面的数据,再移动索引在上面的数据,把数据所在索引和下一条索引的数据互换位置即可。
写在最后
除此之外,我们还可能遇到依据某个字段排序,升序排,降序排。对List集合排序,如果想要按照某个字段升序、降序排序,在现有数据上排序,可以直接使用JDK中的工具类,而不必再去查询一次数据库。
// 对list排序
Collections.sort(data, Comparator.comparing(User::getUid).reversed());
Collections.sort(data, Comparator.comparing(User::getUid));
JavaFx 相关资料参考:
JavaFx TableView 实现的基于桌面应用的增删改查
如何使用2020版IDEA开发JavaFx8,IDEA的配置及一些小技巧
SpringBoot整合JavaFx、Jfoenix开发第一个简单的应用,登录及页面跳转
安装IDEA 2018.3.6,打开个JavaFx桌面小应用,踩到的一些坑