Como fazer uma Jtable vertical

Estou fazendo um programa de estoque e preciso de uma tabela para exibir os dados de um palet, que são, id, laço, altura, total, cerveja e ultima modificação, só que para ficar mais bem distribuido na tela eu gostaria que ao invés destes itens ficassem na horizontal como normalmente ficam, eles ficassem na vertical divindo os itens pelas linhas.

É possível? se sim como faço?

Por padrão os elementos de uma JTable já são renderizados na vertical.
Imagino que você queira renderizar na horizontal.

Pois bem, basta você escrever o seu próprio TableModel e inverter a lógica de renderização das linhas e colunas.

Vou postar um exemplo hipotético pra você se basear.

Imagino que você tenha uma classe pra representar os seus pallets, deve ser algo mais ou menos assim:

import java.util.Date;

public class Pallet {

    private long id;
    private double laco;
    private double altura;
    private double total;
    private String cerveja;
    private Date ultimaModificacao;

    public Pallet() {}

    public Pallet(long id, double laco, double altura, double total, String cerveja, Date ultimaModificacao) {
        this.id = id;
        this.laco = laco;
        this.altura = altura;
        this.total = total;
        this.cerveja = cerveja;
        this.ultimaModificacao = ultimaModificacao;
    }

    public double getAltura() {
        return altura;
    }

    public String getCerveja() {
        return cerveja;
    }

    public long getId() {
        return id;
    }

    public double getLaco() {
        return laco;
    }

    public double getTotal() {
        return total;
    }

    public Date getUltimaModificacao() {
        return ultimaModificacao;
    }

    public void setAltura(double altura) {
        this.altura = altura;
    }

    public void setCerveja(String cerveja) {
        this.cerveja = cerveja;
    }

    public void setId(long id) {
        this.id = id;
    }

    public void setLaco(double laco) {
        this.laco = laco;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public void setUltimaModificacao(Date ultimaModificacao) {
        this.ultimaModificacao = ultimaModificacao;
    }
}

Agora segue um exemplo de telinha hipotética que cria uma JTable com um TableModel específico pra renderizar objetos Pallet:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class TelaExemplo extends JFrame {

    public static void main(String[] args) {
        TelaExemplo tela = new TelaExemplo();
        tela.setDefaultCloseOperation(EXIT_ON_CLOSE);
        tela.setVisible(true);
    }

    private class PalletCellRenderer implements TableCellRenderer {

        private JLabel label = new JLabel();

        @Override
        public Component getTableCellRendererComponent(JTable table, Object conteudo, boolean selecionado, boolean focado, int lin, int col) {
            label.setText(String.valueOf(conteudo));
            if (col == 0) {
                label.setHorizontalAlignment(SwingConstants.CENTER);
                label.setBackground(table.getTableHeader().getBackground());
                label.setOpaque(true);
            } else {
                label.setOpaque(false);
                switch (lin) {
                    case 0:
                    case 1:
                    case 2:
                        label.setHorizontalAlignment(SwingConstants.RIGHT);
                        break;
                    case 3:
                        label.setHorizontalAlignment(SwingConstants.LEFT);
                        break;
                    case 4:
                        label.setHorizontalAlignment(SwingConstants.CENTER);
                        break;
                }
            }
            return label;
        }
    }

    private class PalletTableModel extends AbstractTableModel {

        // a Jtable chama esse método pra saber quantas colunas ela tem
        @Override
        public int getColumnCount() {
            return 1 + pallets.size(); // uma coluna pra ser o "cabeçalho" e mais uma coluna pra cada pallet da lista
        }

        // a Jtable chama esse método pra saber o nome do cabeçalho da coluna informada
        @Override
        public String getColumnName(int col) {
            if (col == 0) {
                return "ID";
            }
            Pallet pallet = pallets.get(col - 1);
            return String.valueOf(pallet.getId());
        }

        // a Jtable chama esse método pra saber quantas linhas ela tem
        @Override
        public int getRowCount() {
            return 5; // uma linha pra cada atributo do pallet exceto o ID, que será o cabeçalho
        }

        // a Jtable chama esse método pra saber o valor a ser renderizado na linha e coluna informados
        @Override
        public Object getValueAt(int lin, int col) {
            if (col == 0) {
                switch (lin) {
                    case 0:
                        return "LAÇO";
                    case 1:
                        return "ALTURA";
                    case 2:
                        return "TOTAL";
                    case 3:
                        return "CERVEJA";
                    case 4:
                        return "MODIFICAÇÃO";
                }
            }
            Pallet pallet = pallets.get(col - 1);
            switch (lin) {
                case 0:
                    return pallet.getLaco();
                case 1:
                    return pallet.getAltura();
                case 2:
                    return pallet.getTotal();
                case 3:
                    return pallet.getCerveja();
                case 4:
                    return new SimpleDateFormat("dd/MM/yyyy").format(pallet.getUltimaModificacao());
            }
            return null;
        }
    }

    private List<Pallet> pallets;

    public TelaExemplo() {
        super("Tela de Exemplo");
        setMinimumSize(new Dimension(800, 600));
        pallets = carregarPallets();

        JTable tablePallets = new JTable(new PalletTableModel());
        tablePallets.setDefaultRenderer(Object.class, new PalletCellRenderer());
        tablePallets.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        add(new JScrollPane(tablePallets), BorderLayout.CENTER);
    }

    // exemplo hipotético que cria 50 pallets dentro de um laço
    // ná prática você vai buscar essas informações do banco de dados
    private List<Pallet> carregarPallets() {
        List<Pallet> pallets = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            pallets.add(new Pallet(i, i, i, i, "Cerveja " + i, new Date()));
        }
        return pallets;
    }
}

O aspecto dessa tela vai ser assim:

Óbvio que na prática talvez você vá customizar os TableCellRenderer para tratar os alinhamentos e cores de fundo.

3 curtidas

Valeu mesmo, para falar a verdade ficou até melhor do que eu estava pensando, muito obrigado!
Só que tem um outro porém kkk
Eu queria que os valores além de serem listados, pudessem ser editados para fazer uma modificação no estoque.
Eu tenho uma função para listar a tabela do DB e uma para editar só que tenho que implementar essas de um jeito que funcionem na Jtable. Eu saberia fazer caso fosse Jtext mas ainda sou novo com o swing e ainda n to sabendo muito lidar com as tabelas.
(No caso eu tenho um botão para cada palet que é passado um ID e vai fazer uma tabela apenas para aquele palet)

As funções são as seguintes:

public static void update_palet_Prepared_Statement(Palet palet) {

	String sql = "UPDATE `DB_Estoque`.`Palet` SET `laco`= ?, `altura`= ? , `total`= ? , `cerveja_id`= ? , `ultima_mod`= ? WHERE `id`= ? ;";

	Connection conn = Conexao.getConnection();

	try {
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setInt(1, palet.getLaco());
		ps.setInt(2, palet.getAltura());
		ps.setInt(3, palet.getTotal());
		ps.setInt(4, palet.getCerveja_id());
		ps.setString(5, palet.getUltima_mod());
		ps.setInt(6, palet.getId());
		ps.executeUpdate();
		Conexao.Fechar_Conexao(conn, ps);
		JOptionPane.showMessageDialog(null, "Registro atualizado com sucesso.");
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

public static List<Palet> Search_by_id_palet_Prepared_Statement(int id) {

	String sql = "SELECT id, laco, altura, total, cerveja_id FROM DB_Estoque.Palet where id like ?";
	Connection conn = Conexao.getConnection(); // Abrindo conexão
	List<Palet> ListaPalet = new ArrayList<>();

	try {
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setInt(1, id);
		ResultSet rs = ps.executeQuery();
		while (rs.next()) {
			ListaPalet.add(new Palet(rs.getInt("id"), rs.getInt("laco"), rs.getInt("altura"), rs.getInt("total"), rs.getInt("cerveja_id")));
		}
		Conexao.Fechar_Conexao(conn, ps, rs); // Fechando conexão
		return ListaPalet;
	} catch (SQLException e) {
		e.printStackTrace();
	}
	return null;
}

Feitas algumas modificações do seu codigo o meu ficou assim, por enquanto eu estou chamando a função só para listar:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

import classes.Palet;
import main.Teste_funcs;

public class Teste_Palet extends JFrame {

/**
 * 
 */
private static final long serialVersionUID = 1L;

public static void main(String[] args) {
	Teste_Palet tela = new Teste_Palet();
	tela.setDefaultCloseOperation(EXIT_ON_CLOSE);
	tela.setVisible(true);
}

private class PalletCellRenderer implements TableCellRenderer {

	private JLabel label = new JLabel();

	@Override
	public Component getTableCellRendererComponent(JTable table, Object conteudo, boolean selecionado, boolean focado, int lin, int col) {
		label.setText(String.valueOf(conteudo));
		if (col == 0) {
			label.setHorizontalAlignment(SwingConstants.CENTER);
			label.setBackground(table.getTableHeader().getBackground());
			label.setOpaque(true);
		} else {
			label.setOpaque(false);
			switch (lin) {
			case 0:
			case 1:
			case 2:
				label.setHorizontalAlignment(SwingConstants.RIGHT);
				break;
			case 3:
				label.setHorizontalAlignment(SwingConstants.LEFT);
				break;
			case 4:
				label.setHorizontalAlignment(SwingConstants.CENTER);
				break;
			}
		}
		return label;
	}
}

protected static List<Palet> palets;

public Teste_Palet() {
    super("Modificação Estoque");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setMinimumSize(new Dimension(300, 350));
    palets = Teste_funcs.Busca_com_id_palet_PS(1);

    JTable tablePallets = new JTable(new PalletTableModel());
    tablePallets.setDefaultRenderer(Object.class, new PalletCellRenderer());
    tablePallets.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    getContentPane().add(new JScrollPane(tablePallets), BorderLayout.CENTER);
}
}

class PalletTableModel extends AbstractTableModel {

/**
 * 
 */
private static final long serialVersionUID = 1L;

// a Jtable chama esse método pra saber quantas colunas ela tem
@Override
public int getColumnCount() {
	return 2; // uma coluna pra ser o "cabeçalho" e mais uma coluna pra cada palet da lista
}

// a Jtable chama esse método pra saber o nome do cabeçalho da coluna informada
@Override
public String getColumnName(int col) {
	if (col == 0) {
		return "ID";
	}
	Palet pallet = Teste_Palet.palets.get(col - 1);
	return String.valueOf(pallet.getId());
}

// a Jtable chama esse método pra saber quantas linhas ela tem
@Override
public int getRowCount() {
	return 5; // uma linha pra cada atributo do pallet exceto o ID, que será o cabeçalho
}

// a Jtable chama esse método pra saber o valor a ser renderizado na linha e
// coluna informados
@Override
public Object getValueAt(int lin, int col) {
	if (col == 0) {
		switch (lin) {
		case 0:
			return "LAÇO";
		case 1:
			return "ALTURA";
		case 2:
			return "TOTAL";
		case 3:
			return "CERVEJA";
		case 4:
			return "ÚLTIMA MODIFICAÇÃO";
		}
	}
	Palet palet = Teste_Palet.palets.get(col - 1);
	switch (lin) {
	case 0:
		return palet.getLaco();
	case 1:
		return palet.getAltura();
	case 2:
		return palet.getTotal();
	case 3:
		return palet.getCerveja_id();
	case 4:
		return palet.getUltima_mod();
	}
	return null;
}
}

Basicamente eu queria que ficasse algo semelhante a isso:
Capturar

Tira o static da sua lista de pallets, não faz sentido ser static.

É só você sobrescrever os métodos isCellEditable(int lin, int col) e setValueAt(Object conteudo, int lin, int col) do seu TableModel, o exemplo abaixo é baseado no código que eu te postei antes, não peguei o seu código:

    // a JTable chama este método pra saber se a célula informada pelos parametros lin e col pode ser editada ou não
    @Override
    public boolean isCellEditable(int lin, int col) {
        if (col == 0) { // os campos da coluna 0 são o "cabeçalho" da nossa table, então não pode editar
            return false;
        }
        return true; // as células das outras coluna pode editar
    }

    // a JTable chama este método pra aplicar o valor que foi inserido na célula informada pelos parametros lin e col
    @Override
    public void setValueAt(Object conteudo, int lin, int col) {
        try {
            Pallet pallet = pallets.get(col - 1);
            switch (lin) {
                case 0:
                    pallet.setLaco(Double.parseDouble((String) conteudo));
                    break;
                case 1:
                    pallet.setAltura(Double.parseDouble((String) conteudo));
                    break;
                case 2:
                    pallet.setTotal(Double.parseDouble((String) conteudo));
                    break;
                case 3:
                    pallet.setCerveja((String) conteudo);
                    break;
                case 4:
                    pallet.setUltimaModificacao(new SimpleDateFormat("dd/MM/yyyy").parse((String) conteudo));
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Dessa forma você vai conseguir alterar as propriedades dos objetos Pallet, aí na hora de salvar, basta você fazer um laço e chamar aquele seu método de update pra cada um deles.

É só você editar o TableModel pra trazer os itens nessa ordem.
faz um switchdo parâmetro linha e trata cada case adequadamente:

case 0: retorna cerveja;
case 1: retorna o laço;
case 2: retorna a altura;
case 3: retorna a quantidade;
case 4: retorna a quantidade de vendas;
case 5: retorna o preço;
case 6: retorna a data de modificação;

é por que na classe PalletTableModel ele não identifica a variável quando chama em :

O PalletTableModel é pra ser uma inner class, isto é, uma classe declarada dentro da classe Teste_Palet, da mesma forma que a classe PalletCellRenderer.

E mesmo que você queira tornar ela uma outer class, sua lista de pallets não deve ser static.

De qualquer jeito eu consegui, fiz umas modificações e ficou exatamente como eu queria, estou tentando implementar o update mas isso é o de menos, muito obrigado.