我有一个表格视图,并且可以按单列e.g.
进行搜索当我有很多列并且每列必须有很多文本字段时,问题就开始了。有没有简单的方法可以使表格视图中的第一行是可编辑搜索框的行?
答案 0 :(得分:0)
如果需要一行文本字段,每列一个,则可能需要在TableView上方放置一个HBox容器,并将TextField实例放入HBox。为了获得正确的大小调整,您可以将文本字段(首选!)的宽度绑定到相应的列宽,并将HBox(首选!)的宽度绑定到TableView的宽度:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
*
* @author kids
*/
public class game extends javax.swing.JFrame {
private PaintSurface canvas;
int x_position = 0;
int y_position = 580;
int x_speed = 7;
int enemy_posX = 0;
int enemy_posY = 560;
int x_pos = 0;
int y_pos = 0;
int x_pos2 = -1200;
int x_position2 = -1200;
int enemy_posX2 = -1150;
int enemy_posY2 = 560;
int cloudOnex = 30;
int cloudOney = 70;
int cloud2x = -1150;
int cloud2y = 70;
int cloud3x = 700;
int cloud3y = 70;
int cloud4x = -600;
int cloud4y = 70;
int playerx =400;
int playery = 540;
/**
* Creates new form game
*/
public game() {
JPanel btnPanel = new JPanel(new FlowLayout());
JButton btnUp = new JButton("Move Up ");
btnPanel.add(btnUp);
btnUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
playery += 10;
canvas.repaint();
requestFocus(); // change the focus to JFrame to receive KeyEvent
}
});
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
// "super" JFrame fires KeyEvent
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent evt) {
switch (evt.getKeyCode()) {
case KeyEvent.VK_UP:
playery -= 22;
repaint();
break;
}
}
});
this.setTitle("Scrolling Game");
this.setSize(1200, 650);
// super.setBackground(Color.YELLOW);
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
this.add(new PaintSurface(), BorderLayout.CENTER);
this.setVisible(true);
canvas = new PaintSurface();
this.add(canvas, BorderLayout.CENTER);
//settings for the form, handling things such as exiting and size
Timer timer = new Timer(10, e -> {
canvas.movement();
canvas.check();
canvas.repaint();
});
timer.start();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
class PaintSurface extends JComponent {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle2D background = new Rectangle2D.Float(x_pos, y_pos, 1200, 650);
g2.setColor(Color.CYAN);
g2.fill(background);
Rectangle2D ground = new Rectangle2D.Float(x_position, y_position, 1200, 30);
g2.setColor(Color.GREEN);
g2.fill(ground);
Rectangle2D cloudOne = new Rectangle2D.Float(cloudOnex, cloudOney, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudOne);
Rectangle2D cloudThree = new Rectangle2D.Float(cloud3x, cloud3y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudThree);
Rectangle2D background2 = new Rectangle2D.Float(x_pos2, y_pos, 1200, 650);
g2.setColor(Color.CYAN);
g2.fill(background2);
Rectangle2D ground2 = new Rectangle2D.Float(x_position2, y_position, 1200, 30);
g2.setColor(Color.GREEN);
g2.fill(ground2);
Rectangle2D cloudTwo = new Rectangle2D.Float(cloud2x, cloud2y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudTwo);
Rectangle2D cloudFour = new Rectangle2D.Float(cloud4x, cloud4y, 70, 70);
g2.setColor(Color.WHITE);
g2.fill(cloudFour);
Rectangle2D player = new Rectangle2D.Float(playerx, playery,40,40);
g2.setColor(Color.red);
g2.fill(player);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
/**
* @param args the command line arguments
*/
}
public void movement(){
cloudOnex += 10;
cloud2x += 10;
cloud3x += 10;
cloud4x += 10;
x_position += 10;
x_pos += 10;
x_position2 += 10;
x_pos2 += 10;
enemy_posX += 10;
enemy_posX2 += 10;
try { Thread.sleep(20); } /* this will pause for 50 milliseconds */
catch (InterruptedException e) { System.err.println("sleep exception"); }
}
public void check(){
if (x_pos == 1200 ) {
x_pos = -1200;
//x_position = -1200;
repaint();
}
if (x_pos2 == 1200) {
x_pos2 = -1200;
// x_position2 = -1200;
repaint();
}
if (x_position == 1200) {
x_position = -1200;
repaint();
}
if (x_position2 == 1200) {
x_position2 = -1200;
repaint();
}
if (cloudOnex == 1200) {
cloudOnex = -1150;
repaint();
}
if (cloud2x == 1200){
cloud2x = -1150;
repaint();
}
// if (x_position2 > 1300) {
// x_position2 = -600;
// repaint();
// }
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(game.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new game().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
一种非常简单但有效的过滤方法是将TableView数据包装在FilteredList中,如果其中一个搜索框内的文本发生更改,则更新过滤谓词:
hbox.prefWidthProperty().bind(tableview.widthProperty());
textfield1.prefWidthProperty().bind(col1.widthProperty());
textfield2.prefWidthProperty().bind(col2.widthProperty());
如果您的列不适合TabelView的视口,那么您可能希望将搜索框放在列标题中,即将TextFields作为图形属性设置为TableColumn:
ObservableList<Person> data = FXCollections.observableArrayList();
data.add(....); // add data ...
// wrap the data collection in a filterd list:
filteredList = new FilteredList<>(data);
filteredList.setPredicate(p -> true); // Initial: show all rows
// set the FilteredList as TableView data:
tableview.itemsProperty().set(filteredList);
// Create a changelistener for the search box:
// "dataObject" is an instance of your data class/entity etc.
textfield1.textProperty().addListener((observable, oldValue, newValue) -> {
updatePredicate();
});
textfield2.textProperty().addListener((observable, oldValue, newValue) -> {
updatePredicate();
});
首先,图形节点将隐藏列标题。您可以尝试通过css样式(只是一个提示,我需要检查一下)来纠正此问题,或者您将新的Label和文本字段一起包装在HBox中,该HBox将成为列标题的图形节点。
更新过滤谓词的方法:
col1.setGraphic(textfield1);
col2.setGraphic(textfield2);
希望有帮助:-)
答案 1 :(得分:0)
这是一个草稿示例,其中的搜索通过“与”逻辑进行,即所有搜索文本均已考虑在内。
假设您有一个人作为数据模型:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import javafx.beans.property.SimpleStringProperty;
class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
String getFirstName() {
return firstName.get();
}
String getLastName() {
return lastName.get();
}
String getEmail() {
return email.get();
}
}
该表的设计如下:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051.MyCellValueFactory?>
<AnchorPane prefHeight="400.0"
prefWidth="600.0"
xmlns="http://javafx.com/javafx/8.0.171"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051.Controller">
<TableView fx:id="tableView" prefWidth="600">
<columnResizePolicy>
<TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
<columns>
<TableColumn text="First Name">
<cellValueFactory>
<MyCellValueFactory property="firstName"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name">
<cellValueFactory>
<MyCellValueFactory property="lastName"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="E-mail">
<cellValueFactory>
<MyCellValueFactory property="email"/>
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</AnchorPane>
我们有自定义表格行类。
MyTableRowData:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
public abstract class MyTableRowData<T> {
public abstract T firstNameProperty();
public abstract T lastNameProperty();
public abstract T emailProperty();
}
SearchTableRowData:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class SearchTableRowData extends MyTableRowData<ObjectProperty<String>> {
private final ObjectProperty<String> firstName = new SimpleObjectProperty<>();
private final ObjectProperty<String> lastName = new SimpleObjectProperty<>();
private final ObjectProperty<String> email = new SimpleObjectProperty<>();
@Override
public ObjectProperty<String> firstNameProperty() {
return firstName;
}
@Override
public ObjectProperty<String> lastNameProperty() {
return lastName;
}
@Override
public ObjectProperty<String> emailProperty() {
return email;
}
}
PersonTableRowData:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
class PersonTableRowData extends MyTableRowData<ObjectProperty<String>> {
private final ObjectProperty<String> firstName;
private final ObjectProperty<String> lastName;
private final ObjectProperty<String> email;
PersonTableRowData(final Person person) {
this.firstName = new SimpleObjectProperty<>(person.getFirstName());
this.lastName = new SimpleObjectProperty<>(person.getLastName());
this.email = new SimpleObjectProperty<>(person.getEmail());
}
@Override
public ObjectProperty<String> firstNameProperty() {
return firstName;
}
@Override
public ObjectProperty<String> lastNameProperty() {
return lastName;
}
@Override
public ObjectProperty<String> emailProperty() {
return email;
}
}
MyCellValueFactory 类是所有魔术的心脏:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import java.lang.reflect.Method;
import javafx.beans.NamedArg;
import javafx.beans.Observable;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Node;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.util.Callback;
public class MyCellValueFactory<P extends MyTableRowData<?>, S extends Node>
implements Callback<TableColumn.CellDataFeatures<P, S>, ObservableValue<S>> {
private final String property;
public MyCellValueFactory(@NamedArg("property") final String property) {
this.property = property;
}
@Override
public ObservableValue<S> call(final TableColumn.CellDataFeatures<P, S> param) {
final P tableRowData = param.getValue();
if (tableRowData instanceof SearchTableRowData) {
return new SimpleObjectProperty<>(buildSearchTextBox(tableRowData));
} else if (tableRowData instanceof PersonTableRowData) {
return new SimpleObjectProperty<>(buildText(tableRowData));
}
return new SimpleObjectProperty<>();
}
@SuppressWarnings("unchecked")
private S buildText(final P tableRowData) {
final Text text = new Text();
text.textProperty().bind(extractProperty(tableRowData));
return (S) text;
}
@SuppressWarnings("unchecked")
private S buildSearchTextBox(final P tableRowData) {
final TextField searchTextField = new TextField();
searchTextField.promptTextProperty().set(property);
searchTextField.textProperty().bindBidirectional(extractProperty(tableRowData));
return (S) searchTextField;
}
@SuppressWarnings("unchecked")
private <T extends Observable> T extractProperty(final P tableRowData) {
try {
final Class<?> c = Class.forName(tableRowData.getClass().getName());
final Method method = c.getDeclaredMethod(property + "Property");
return (T) method.invoke(tableRowData);
} catch (final Exception exc) {
throw new RuntimeException(exc);
}
}
}
控制器类:
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
import org.apache.commons.lang3.StringUtils;
public class Controller {
@FXML
private TableView<MyTableRowData<?>> tableView;
private final ObservableValue<? extends ObservableList<MyTableRowData<?>>> observableRows =
new SimpleListProperty<>(FXCollections.observableArrayList());
private final SearchTableRowData searchTableRowData = new SearchTableRowData();
private final List<Person> originalPersons = Arrays.asList(
new Person("A", "B", "c@c.com"),
new Person("AA", "BB", "cc@c.com"),
new Person("AAA", "BBB", "ccc@c.com"),
new Person("AAAA", "BBBB", "cccc@c.com"));
@FXML
void initialize() {
tableView.itemsProperty().bind(observableRows);
observableRows.getValue().add(searchTableRowData);
searchTableRowData.firstNameProperty().addListener((o, oldValue, newValue) -> fillPersons());
searchTableRowData.lastNameProperty().addListener((o, oldValue, newValue) -> fillPersons());
searchTableRowData.emailProperty().addListener((o, oldValue, newValue) -> fillPersons());
fillPersons();
}
private void fillPersons() {
((ObservableList) observableRows).remove(1, ((ObservableList) observableRows).size());
observableRows
.getValue()
.addAll(originalPersons
.stream()
.filter(getFirstNamePredicate())
.filter(getLastNamePredicate())
.filter(getEmailPredicate())
.map(PersonTableRowData::new)
.collect(Collectors.toList()));
}
private Predicate<Person> getFirstNamePredicate() {
final String value = searchTableRowData.firstNameProperty().get();
return StringUtils.isNoneEmpty(value) ?
person -> StringUtils.containsIgnoreCase(person.getFirstName(), value) :
person -> true;
}
private Predicate<Person> getLastNamePredicate() {
final String value = searchTableRowData.lastNameProperty().get();
return StringUtils.isNoneEmpty(value) ?
person -> StringUtils.containsIgnoreCase(person.getLastName(), value) :
person -> true;
}
private Predicate<Person> getEmailPredicate() {
final String value = searchTableRowData.emailProperty().get();
return StringUtils.isNoneEmpty(value) ?
person -> StringUtils.containsIgnoreCase(person.getEmail(), value) :
person -> true;
}
}
最后,您将通过此 Main 类一起运行所有
package com.dmaslenko.stackexchange.stackoverflow.javafx.q54280051;
import java.net.URL;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import com.dmaslenko.stackexchange.stackoverflow.q54033646.CsvReader;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
@SuppressWarnings("Duplicates")
public void start(final Stage stage) throws Exception {
final URL fxmlFileResource =
CsvReader.class.getResource("/com/dmaslenko/stackexchange/stackoverflow/javafx/q54280051/main.fxml");
final FXMLLoader loader = new FXMLLoader(fxmlFileResource);
final Parent rootPane = loader.load();
loader.getController();
final Scene scene = new Scene(rootPane, 600, 400);
stage.setScene(scene);
stage.show();
}
}
这是草稿但有效的示例,没有太多优化。
需要改进的已知领域: