在JTable中使用FX进行细胞渲染

时间:2017-11-22 14:04:06

标签: java swing javafx

给定在JavaFX中实现的渲染器,将渲染器渲染到Canvas上。它运作良好。 这个渲染器需要在Swing应用程序中使用,并且由于JFXPanel组件在大多数用例中都可以正常工作,但JTable除外。如果用户想要使用给定渲染器渲染表单元格值,则应用程序会以多种不同方式开始失败。

这是一个示例应用程序:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.IOException;    
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;

public class TableRenderer {

    private JFrame frame;

    private JFrame createFrame(String title, JComponent component, int width, int height) {
        final Dimension dimension = new Dimension(width, height);
        JFrame frame = new JFrame(Util.getActiveScreenDevice().getDefaultConfiguration());
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setPreferredSize(dimension);
        frame.setSize(dimension);
        frame.add(component);
        frame.setTitle(title);

        Util.center(frame);
        frame.pack();

        return frame;
    }

    private void show() {
        try {
            init();
        } catch (IOException e) {
            e.printStackTrace();
        }
        frame.setVisible(true);
    }

    private void init() throws IOException {

        JTable table = new JTable(new TableModel());
        table.setRowHeight(200);
        table.setDefaultRenderer(Object.class, new CellRenderer());
        JScrollPane p = new JScrollPane(table);
        table.setFillsViewportHeight(true);

        frame = createFrame("Renderer Demo - JTable", p, 420, 220);
    }

    public static void main(String[] args) {

        TableRenderer app = new TableRenderer();
        SwingUtilities.invokeLater(app::show);
    }

    @SuppressWarnings("serial")
    private static class TableModel extends AbstractTableModel {

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return "this is cell at ("+columnIndex+"; "+rowIndex+")";
        }

        @Override
        public int getRowCount() {
            return 3;
        }

        @Override
        public int getColumnCount() {
            return 3;
        }
    };

    private static class CellRenderer implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            Rectangle cellRect = table.getCellRect(row, column, true);
            Renderer renderer = new Renderer(cellRect.getSize(), value);
            renderer.setSize(cellRect.getSize());
            renderer.setPreferredSize(cellRect.getSize());
            renderer.setBackground(java.awt.Color.BLACK);
            return renderer;
        }

    }

    @SuppressWarnings("serial")
    private static class Renderer extends JFXPanel {

        public Renderer(Dimension cellRect, Object value) {
            super();
            Group root = new Group();
            Scene scene = new Scene(root);
            Canvas canvas = new Canvas(cellRect.getWidth(), cellRect.getHeight());
            canvas.getGraphicsContext2D().setFill(Color.RED);
            canvas.getGraphicsContext2D().fillText(value.toString(), 10, 10);
            canvas.getGraphicsContext2D().fillOval(10, 10, 10, 10);
            root.getChildren().add(canvas);
            setScene(scene);
        }
    }
}

在这种情况下,单元格中没有任何内容,应用程序冻结。

如果在JPanel

中显示,同样的工作就可以了
import java.awt.Dimension;
import java.io.IOException;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;

public class PanelRenderer {
    private JFrame frame;

    private JFrame createFrame(String title, JComponent component, int width, int height) {
        final Dimension dimension = new Dimension(width, height);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setPreferredSize(dimension);
        frame.setSize(dimension);
        frame.add(component);
        frame.setTitle(title);

        Util.center(frame);
        frame.pack();

        return frame;
    }

    private void show() {
        try {
            init();
        } catch (IOException e) {
            e.printStackTrace();
        }
        frame.setVisible(true);
    }

    private void init() throws IOException {


        JPanel p = new JPanel();
        p.add(new Renderer(new Dimension(200, 200), "Demo"));

        frame = createFrame("Renderer Demo - JPanel", p, 200, 200);
    }

    public static void main(String[] args) {

        PanelRenderer app = new PanelRenderer();
        SwingUtilities.invokeLater(app::show);
    }

    @SuppressWarnings("serial")
    private static class Renderer extends JFXPanel {

        public Renderer(Dimension cellRect, Object value) {
            super();
            Group root = new Group();
            Scene scene = new Scene(root);
            Canvas canvas = new Canvas(cellRect.getWidth(), cellRect.getHeight());
            canvas.getGraphicsContext2D().setFill(Color.RED);
            canvas.getGraphicsContext2D().fillText(value.toString(), 10, 10);
            canvas.getGraphicsContext2D().fillOval(10, 10, 10, 10);
            root.getChildren().add(canvas);
            setScene(scene);
        }
    }
}

我尝试在JPanel中添加渲染器,并将其作为单元格渲染器组件返回,不做任何更改。

我试图同步FXThread和EDT,这是一个地狱,没有任何反应。

我尝试渲染图像,创建一个Component,覆盖paintComponent以绘制图像,并同步线程。这似乎适用于Windows,但在OSX上仍然失败。

我做错了什么,或者我应该接受这个用例是来自魔鬼而无法让它起作用?

0 个答案:

没有答案