当前位置: 首页 > 知识库问答 >
问题:

填充TableView与观察地图JavaFX

洪飞扬
2023-03-14

我想知道是否可以使用observeMap来填充表格视图?我使用了observateMap而不是observateList,因为我需要经常添加和删除,所以我需要最小化成本。

我的hashMap使用一个大整数作为键字段,一个具有许多属性的类型作为值字段。在我的tableView中,我只想显示每个属性都有一列的值。我希望你说清楚了

谢谢

共有2个答案

夔桐
2023-03-14

我将映射表侦听器打包到TableView的一个子类中。

package tablemap;

import java.util.AbstractMap;
import java.util.Map;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.scene.control.TableView;

public class MapTableView<K,V> extends TableView<Map.Entry<K,V>>{
    private final ObservableList<Map.Entry<K,V>> obsList;
    private final ObservableMap<K,V> map;
    private final MapChangeListener<K,V> mapChange;
    private final ListChangeListener<Map.Entry<K,V>> listChange;

    public MapTableView(ObservableMap<K,V> map) {
        this.map = map;
        obsList = FXCollections.observableArrayList(map.entrySet());
        setItems(obsList);

        mapChange = new MapChangeListener<K, V>() {
            @Override
            public void onChanged(MapChangeListener.Change<? extends K, ? extends V> change) {
                obsList.removeListener(listChange);
                if (change.wasAdded())
                    obsList.add(new AbstractMap.SimpleEntry(change.getKey(),change.getValueAdded()));
                if (change.wasRemoved()){
                    //obsList.remove(new AbstractMap.SimpleEntry(change.getKey(),change.getValueRemoved()));
                    // ^ doesn't work always, use loop instead
                    for (Map.Entry<K,V> me : obsList){
                        if (me.getKey().equals(change.getKey())){
                            obsList.remove(me);
                            break;
                        }
                    }
                }
                obsList.addListener(listChange);
            }
        };

        listChange = (ListChangeListener.Change<? extends Map.Entry<K, V>> change) -> {
            map.removeListener(mapChange);
            while (change.next()){
                //maybe check for uniqueness here
                if (change.wasAdded()) for (Map.Entry<K, V> me: change.getAddedSubList())
                    map.put(me.getKey(),me.getValue());
                if (change.wasRemoved()) for (Map.Entry<K, V> me: change.getRemoved())
                    map.remove(me.getKey());
            }
            map.addListener(mapChange);
        };

        map.addListener(mapChange);
        obsList.addListener(listChange);
    }

    //adding to list should be unique
    public void addUnique(K key, V value){
        boolean isFound = false;
        //if a duplicate key just change the value
        for (Map.Entry<K,V> me : getItems()){
            if (me.getKey().equals(key)){
                isFound = true;
                me.setValue(value);
                break;//only first match 
            }
        }
        if (!isFound) // add new entry
            getItems().add(new AbstractMap.SimpleEntry<>(key,value));
    }

    //for doing lenghty map operations
    public void removeMapListener(){
        map.removeListener(mapChange);
    }

    //for resyncing list to map after many changes
    public void resetMapListener(){
        obsList.removeListener(listChange);
          obsList.clear();
          obsList.addAll(map.entrySet());
        obsList.addListener(listChange);
        map.addListener(mapChange);
    }

}

到目前为止似乎还管用。我使用以下代码创建:

final ObservableMap<String, LineItem> obsMap = FXCollections.observableHashMap();
final MapTableView<String,LineItem> mtv = new MapTableView(obsMap);

你甚至可以编辑关键点。

final TableColumn<Map.Entry<String,LineItem>,String> keyCol = new TableColumn("Key");
keyCol.setCellValueFactory(
    (TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) -> 
        new SimpleStringProperty(p.getValue().getKey()));
keyCol.setCellFactory(TextFieldTableCell.forTableColumn());
keyCol.setOnEditCommit((CellEditEvent<Map.Entry<String,LineItem>, String> t) -> {
    final String oldKey = t.getOldValue();
    final LineItem oldLineItem = obsMap.get(oldKey);
    obsMap.remove(oldKey);//should remove from list but maybe doesn't always
    obsMap.put(t.getNewValue(),oldLineItem);
});

您可以看到,我添加了一个方法来删除和重新添加映射侦听器。添加和删除100k条目的过程需要0.65秒(带监听器)和5.2秒(带监听器)。

这是pastebin上一个文件中的全部内容。http://pastebin.com/NmdTURFt

马凡
2023-03-14

我一直在努力做到这一点。我猜这篇帖子很老了,但我在网上什么地方都看不到答案。示例对列使用映射键,然后对每行使用映射列表。我希望将行视为键及其关联值。这是一个很长的例子。

package tablemap;

import static java.lang.Math.random;
import java.util.Map;
import java.util.TreeMap;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableMap extends Application {

    @Override
    public void start(Stage primaryStage) {
        VBox root = new VBox();
        Map<String,LineItem> mapData = new TreeMap<>();
        for (int i = 0; i < 3; i++)
            mapData.put(String.valueOf(random()), new LineItem(String.valueOf(i),"i"));

        ObservableList<Map.Entry<String,LineItem>> listData = 
                FXCollections.observableArrayList(mapData.entrySet());
        TableView<Map.Entry<String,LineItem>> tv = new TableView(listData);

        TableColumn<Map.Entry<String,LineItem>,String> keyCol = new TableColumn("Key");
        keyCol.setCellValueFactory(
            (TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) -> 
                new SimpleStringProperty(p.getValue().getKey()));

        TableColumn<Map.Entry<String,LineItem>,String> lineNoCol = new TableColumn("Line No");
        lineNoCol.setCellValueFactory(
            (TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) -> 
                new SimpleStringProperty(p.getValue().getValue().getLineNo()));

        TableColumn<Map.Entry<String,LineItem>,String> descCol = new TableColumn("Desc");
        descCol.setCellValueFactory(
            (TableColumn.CellDataFeatures<Map.Entry<String,LineItem>, String> p) -> 
                new SimpleStringProperty(p.getValue().getValue().getDesc()));

        descCol.setCellFactory(TextFieldTableCell.forTableColumn());

        descCol.setOnEditCommit((CellEditEvent<Map.Entry<String,LineItem>, String> t) -> {
             t.getTableView().getItems().get(t.getTablePosition().getRow())
                     .getValue().setDesc(t.getNewValue());
        });

        tv.getColumns().addAll(keyCol,lineNoCol, descCol);
        tv.setEditable(true);
        tv.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        Button btnOut = new Button("out");
        btnOut.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                for (Map.Entry<String,LineItem> me : mapData.entrySet()){
                    System.out.println("key "+me.getKey()+" entry "+me.getValue().toCSVString());
                }
                for (Map.Entry<String,LineItem> me : listData){
                    System.out.println("key "+me.getKey()+" entry "+me.getValue().toCSVString());
                }
            }
        });

        root.getChildren().addAll(tv,btnOut);
        Scene scene = new Scene(root, 300, 200);

        primaryStage.setTitle("Map Table Test");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

和LineItem类代码

package tablemap;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

/* LineItem class */

public class LineItem {
    private final StringProperty lineNo = new SimpleStringProperty();
    private final StringProperty desc = new SimpleStringProperty();

    public LineItem(String ln, String dsc) {
        lineNo.set(ln); desc.set(dsc);
    }

    public String getLineNo() {return (lineNo.getValue() != null) ?lineNo.get():"";}
    public void setLineNo(String lineNo) {this.lineNo.set(lineNo);}
    public StringProperty lineNoProperty() {return lineNo;}

    public String getDesc() {return (desc.getValue() != null) ?desc.get():"";}
    public void setDesc(String desc) {this.desc.set(desc);}
    public StringProperty descProperty() {return desc;}

    public String toCSVString(){
        return lineNo.getValueSafe()+","+
                desc.getValueSafe()+"\n"; 
    }
}

在编辑数据并单击out后,您可以看到列表中的更改反映在地图中。我仍然需要以另一种方式检查并处理插入和删除,但这应该不会太难。

 类似资料:
  • 我正在尝试用来自可观察列表的数据填充TableView。我以前做过这个,但由于某种原因我现在无法让它工作。我没有得到任何异常或任何东西,但它根本不会向表添加任何东西。 这个问题很相似,但我发现了JPA引起的另一个问题,这使得提到的的构造函数永远不会执行。相反,JPA会神奇地分配值。 这是我的代码-我剪下了与问题无关的代码: FXML 主要的Java语言 修改Java语言 任何帮助解决这个问题将不胜

  • 我试图从数据(ObservableList)中填充tableview2(fx:id tableview)行。但当它完成时,tableview2只显示空记录。在控制台中,我看到数据中的所有行(ObservableList)。我知道stackoverflow中有很多关于这方面的问题,很抱歉(还有我的英语),但请你问我代码中的错误在哪里?感谢您的帮助或关注)。 更新(添加MainPayer.java和更

  • 我无法用地图填充TableView 我有一个类,它拥有一个以产品名称为键、以正常价格为值的地图。我创建了一个tableView,其中一列是名称,一个主列是价格,分为两列normal和new,如下所示。 我已经做了这个方法使地图成为一个可观察列表。 这就是我卡住的地方。我不知道如何用这个可观察列表填充每个单元格。我确实知道我必须以某种方式使用“setCellFactory”。有人有什么建议吗?如何制

  • //控制器类Mainguicontroller.java

  • 我有一个用SceneBuilder生成的TableView,所有列都是从其他视图导入的FXML,直到没有问题为止,但列没有填充宽度。 我试图用scene builder和FXML来解决这个问题,但没有运气,所有的大小都是计算出来的。 我尝试用一个change listener对其进行编码,它在每次窗口改变大小以适应列的大小时都会进行检查。 这样可以工作,并且列的大小调整到适当的宽度(基本上我得到了

  • 我正在用一个库编程,我不知道代码,只知道方法,我不能修改它。我试着制作一个“航班”的表格视图,但我不知道如何为每个航班命名(或ID)。有人能帮我吗?谢谢此处有一些代码: