0

I'm trying to draw lines over my JTable using a Painter object that I've made, but for some reason table.getGraphics() returns null.

Painter class:

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JTable;

public class Painter extends JTable {

    public Painter(){

    }

    public void paintSudokuLines(Graphics g){
        paintComponent(g);
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setStroke(new BasicStroke(3));
        g2.drawLine(0, 300, 400, 250);
    }
}

I'm calling the method with:

private Painter paint = new Painter();
paint.paintSudokuLines(table.getGraphics());

I have no idea why this is the case, so I need some explanation.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Zulfe
  • 820
  • 7
  • 25
  • 3
    Simply rule. Don't use `getGraphics` and NEVER call `paintComponent` yourself. This is not how painting works in Swing – MadProgrammer Mar 06 '15 at 03:45
  • Where is `table` defined? – CinCout Mar 06 '15 at 03:46
  • 1
    @GargAnkit `getGraphics` can return `null` if the component is not attached to a displayable native peer. Basic rule is, never try and do your own painting within Swing, work within Swing's paint updates accordingly. Sorry, but where the table is defined will be irrelevant to any possible answer, as they OP is fundementally breaking the painting rules – MadProgrammer Mar 06 '15 at 03:51
  • To be frank, I'm indifferent to Swing. I just wanted to help the OP, and as a developer, `table` appeared to be undefined! – CinCout Mar 06 '15 at 03:55
  • 1
    @GargAnkit And we appreciate the help, but in this, it's just irrelevant – MadProgrammer Mar 06 '15 at 04:03
  • Can you please explain what exact output you want? – Ranjitsinh Mar 06 '15 at 04:04
  • @Ranjitsinh I suspect a [Sudoku](http://simple.wikipedia.org/wiki/Sudoku) grid...based on the requirements from the OP's [previous question](http://stackoverflow.com/questions/28891250/specifying-side-borders-on-individual-cells-in-jtable) – MadProgrammer Mar 06 '15 at 04:08
  • Do you want to draw a rectangle table? – Ranjitsinh Mar 06 '15 at 04:13
  • @Ranjitsinh No, I was attempting to highlight the block borders found on a standard Sudoku puzzle. I was hoping that it would be possible to just draw thick lines over it, but it seems that such a task was beyond my ability. – Zulfe Mar 06 '15 at 04:16
  • There are [a few good resources](http://docs.oracle.com/javase/tutorial/uiswing/painting/step2.html) on swing painting out there. – Obicere Mar 06 '15 at 04:21

1 Answers1

5

Never use getGraphics, it can return null (as you've found) and isn't how custom painting should be done. You should NEVER have a need to call paintComponent yourself. If when printing, you wouldn't call it directly, at the best, you'd break the paint chain and introduce no end of additional issues and artifacts.

For a better understanding of how painting works see Painting in AWT and Swing.

Now, let me give you a quick demonstration of why you shouldn't try and paint over the top of a JTable like you're trying to do...

Table

Now, don't get me wrong, I'm sure with some very clever deduction work you could calculate the row/column positions so as to be able to paint the guides properly, but that's a lot of extra work.

A better solution might be to use a custom TableCellRenderer...

Table

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class SudokuTest {

    public static void main(String[] args) {
        new SudokuTest();
    }

    public SudokuTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(new SudokuTable()));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SudokuTable extends JTable {

        public SudokuTable() {
            super(new DefaultTableModel(9, 9));
            setDefaultRenderer(Object.class, new SudokuCellRender());
        }

    }

    public class SudokuCellRender extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

            int left = 0;
            int top = 0;
            int right = 0;
            int bottom = 0;

            if ((column % 3) == 0) {
                left = 2;
            } else if ((column % 3) == 2) {
                right = 2;
            }

            if ((row % 3) == 0) {
                top = 2;
            }
            if ((row % 3) == 2) {
                bottom = 2;
            }

            setBorder(new MatteBorder(top, left, bottom, right, Color.RED));

            return this;
        }

    }

}

Now, this is just a proof of concept. You may need to use a compound border to offset the cell property (so all cells have at least a 2 pixel border around them and/or reduce the border width ;))

Also, take a look at How to Use Tables for more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you so much! I'm starting to understand how this all works. I had seen other threads with similar answers, but I tried avoiding them since I didn't know how they worked. I'll have to take a look into cell render objects. – Zulfe Mar 06 '15 at 04:35
  • There's still a lot of work that needs to go into making the output right, as the `MatteBorder` is going to push the cell contents around a bit, hence my comments about using a some king `CompoundBorder` ;) – MadProgrammer Mar 06 '15 at 04:49
  • Thanks again for all your help, MadProgrammer. My program is (almost) finished, but I'd like for you to check it out and tell me what you think! https://github.com/zulfe/sudoku – Zulfe Mar 06 '15 at 04:56