I'm creating GUI in java using swing. I use JTable that looks like this.
I need to make cells of last column("Popis") to be scrollable as there will be description so String containing this description has variable lenght for each row.
This is how I created my JTable.
this.tableModel = new DefaultTableModel(
new Object[][] { },
new String[] {"ID", "Nazov", "Naplnena kapacita / kapacita", "Popis"}
);
this.table1.setModel(this.tableModel);
I add data to table using this.tablemodel.addRow();
Is there a way to make cells of last column of my table scrollable?
It would be difficult and awkward to embed a scrolling component inside a JTable. A common approach to showing long cell values is to make the cell’s tooltip (hover text) display the full value:
table1.setModel(tableModel);
table1.getColumnModel().getColumn(3).setCellRenderer(
new DefaultTableCellRenderer() {
#Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean selected,
boolean focused,
int row,
int column) {
Component component = super.getTableCellRendererComponent(
table, value, selected, focused, row, column);
if (component instanceof JComponent) {
((JComponent) component).setToolTipText(
Objects.toString(value, null));
}
return component;
}
});
(Objects is the java.util.Objects class.)
It can be solved by creating private class that extends AbstractCellEditor and implements TableCellEditor. Then create and customize the scrollbar. Here is example.
public class MainForm {
private JTable table1;
private JPanel panel1;
private JTextArea text = new JTextArea();
public MainForm() {
text.setEditable(false);
DefaultTableModel tableModel = new DefaultTableModel(new Object[][]{}, new String[]{"Meno", "Priezvisko", "Datum", "Popis"});
table1.setModel(tableModel);
table1.setRowHeight(40);
tableModel.addRow(new Object[]{"Jaimi", "Parker", "2022", "fdjfadufaouifasoifjasifhasiofa \nasdasdasdasdasdasdas \nasdasdasdasdasdasd\nasdasdasdasd "});
tableModel.addRow(new Object[]{"William", "Mcdonald", "2021", "fdjfadufaouasfadfdsfafifasoifjasifhasiofa"});
tableModel.addRow(new Object[]{"Matt", "Ashley", "2020", "asfasfafdsfgdafgdfgasgsdg"});
tableModel.addRow(new Object[]{"Ariana", "Burns", "2019", "fdjfadufaouifasfdsgdgagsgsdgsdgsdagsdgsdgsdgsagsdgoifjasifhasiofa"});
TableColumn column = table1.getColumn("Popis");
column.setCellEditor(new HScrollableTCE());
}
public static void main(String[] args) {
JFrame frame = new JFrame("MainForm");
frame.setContentPane(new MainForm().panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private class HScrollableTCE extends AbstractCellEditor implements TableCellEditor
{
JScrollPane scroll = new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int rowIndex, int vColIndex)
{
if (value != null) {
scroll.setHorizontalScrollBar(scroll.createHorizontalScrollBar());
scroll.getHorizontalScrollBar().setPreferredSize(new Dimension(0, 5));
scroll.setBorder(new EmptyBorder(0,0,0,0));
scroll.setToolTipText(value.toString());
text.setText(value.toString());
return scroll;
}
return null;
}
public Object getCellEditorValue()
{
return text.getText();
}
}
}
Related
I try to make the list of JPanel with buttons, edittext fields and other Swing components but cant find the examples of making listviews in swing. I tried to do this with jTable that has one column whith JPanel in cells but my label fields changes in all jPanel elements after click of button
Here is the code, that i made from different examples. This class has render and editor methods. I try to change the text of label when button is clicked. But all labels (I want to change only one that is needed) change their text... May be i set onMouseListener not in that place...
public class RssFeedCell extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
JPanel panel;
JLabel text;
JButton showButton;
JLabel label;
RssFeed feed;
public RssFeedCell() {
label = new JLabel();
text = new JLabel();
showButton = new JButton("View Articles");
showButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
label.setText("ed");
}
});
panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel.add(text);
panel.add(showButton);
panel.add(label);
}
private void updateData(RssFeed feed, boolean isSelected, JTable table) {
this.feed = feed;
text.setText("" + feed.name + "" + feed.url + "Articles " + feed.articles.length + "");
if (isSelected) {
panel.setBackground(table.getSelectionBackground());
} else {
panel.setBackground(table.getBackground());
}
}
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
RssFeed feed = (RssFeed) value;
updateData(feed, true, table);
return panel;
}
public Object getCellEditorValue() {
return null;
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
RssFeed feed = (RssFeed) value;
updateData(feed, isSelected, table);
return panel;
}
}
There is only one label. You need to incorporate the cell state into the TableModel data.
I already add a picture with JLabel in my JTable with TableCellRenderer. But how to add a border to the JLabel when mouse moves over the cell, on specific column and row?
This is the 1st renderer class:
public class RenderTabel implements TableCellRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object
value,boolean isSelected, boolean hasFocus,int row, int column){
JLabel gambar=new JLabel();
String url="D:\\Kuliah Semester 4\\Pemrograman Berorientasi Objek\\DINUS BOOKSTORE\\image";
ImageIcon img=scalegmbr(url+"\\"+table.getModel().getValueAt(row, 0)+".png");
gambar.setIcon(img);
gambar.setText("");
gambar.setHorizontalAlignment(SwingConstants.CENTER);
table.setRowHeight(row, 50);
table.getColumnModel().getColumn(column).setPreferredWidth(80);
return gambar;
}
public ImageIcon scalegmbr(String file){
Image image=new ImageIcon(file).getImage();
return new ImageIcon(image.getScaledInstance(80,50,SCALE_SMOOTH));
}
}
This is 2nd renderer class:
public class RenderTabel1 implements TableCellRenderer{
#Override
public Component getTableCellRendererComponent(JTable table, Object
value,boolean isSelected, boolean hasFocus,int row, int column){
JLabel gambar=new JLabel();
String url="D:\\Kuliah Semester 4\\Pemrograman Berorientasi Objek\\DINUS BOOKSTORE\\image";
ImageIcon img=scalegmbr(url+"\\"+table.getModel().getValueAt(row, 0)+".png");
gambar.setIcon(img);
gambar.setText("");
gambar.setHorizontalAlignment(SwingConstants.CENTER);
gambar.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(200, 100, 52), 2));
table.setRowHeight(row, 50);
table.getColumnModel().getColumn(column).setPreferredWidth(80);
return gambar;
}
public ImageIcon scalegmbr(String file){
Image image=new ImageIcon(file).getImage();
return new ImageIcon(image.getScaledInstance(80,50,SCALE_SMOOTH));
}
}
and this is how I set the mouse enter and mouse clicked in my JTable:
private void tblbukuMouseEntered(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
tblbuku.getColumnModel().getColumn(6).setCellRenderer( new RenderTabel1());
}
private void tblbukuMouseExited(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
tblbuku.getColumnModel().getColumn(6).setCellRenderer( new RenderTabel());
}
But this adds a border to all cells in column 6 when mouse moves ofer a cell of that column. How to change it only into specific row and column when mouse entered that row and column?
So, for a particular column of your table, you want to paint a border on the cell that is hovered by the mouse (only the hovered cell, only in this column).
(edit: after clarification it appears that this question has been asked before -- I'm leaving my answer below as it might still help)
don't change the cell renderer dynamically, have only 1 renderer for that column, and handle that situation within the single renderer.
don't add listeners on the Component that is returned by the renderer: such listeners won't be triggered, as the component is only used for its paint()-ing logic.
instead, add a mouse motion listener on the table itself, and compute the coordinates of hovered cells with JTable's methods rowAtPoint and columnAtPoint, when mouse moves over table, or exits the area.
(irrelevant to problem at hand, but deserves a mention) Avoid creating a new JLabel for each call of your renderer, this is wasteful. Swing is single-thread, it's safe to reuse the same object (provided you don't forget to reset all its properties that might have changed between 2 calls)
Small demo that shows the effect:
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class SimpleTableDemo extends JPanel {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(SimpleTableDemo::createAndShowGUI);
}
private int
hoveredRow = -1,
hoveredColumn = -1;
SimpleTableDemo() {
super(new GridLayout(1,0));
String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"};
Object[][] data = {
{"Kathy", "Smith", "Snowboarding", 5, Boolean.FALSE},
{"John", "Doe", "Rowing", 3, Boolean.TRUE},
{"Sue", "Black", "Knitting", 2, Boolean.FALSE},
{"Jane", "White", "Speed reading", 20, Boolean.TRUE},
{"Joe", "Brown", "Pool", 10, Boolean.FALSE}
};
final JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
table.setFillsViewportHeight(true);
table.getColumn("Sport").setCellRenderer(new MyCellRenderer());
table.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
hoveredRow = table.rowAtPoint(p);
hoveredColumn = table.columnAtPoint(p);
table.repaint();
}
public void mouseExited(MouseEvent e) {
hoveredRow = hoveredColumn = -1;
table.repaint();
}
});
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
SimpleTableDemo newContentPane = new SimpleTableDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
private class MyCellRenderer extends DefaultTableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hoveredColumn == column && hoveredRow == row) {
label.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2));
}
else {
label.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
}
return label;
}
}
}
Note 1: I'm using the default cell renderer, unlike you, but the same idea applies. The demo above is a generic example, that will be more useful as example to keep here than a specific solution for your case (for example, in my interpretation of the problem, I understand the details about icon are irrelevant).
Note 2: In the demo I repaint the whole visible area each time, but if you want to optimize it should be possible to repaint only 2 cells, that's an entire new question, see here for help about that.
Hi i want to show new line in DefaultTableModel but i dont know why table doesn't show enters.
How to enable enters? If i have a string "stss\nsdd" it shows "stsssdd" but i want new line.
public class Main extends JFrame {
DefaultTableModel model = new DefaultTableModel(
new Object[][]{{"some", "text"}, {"any", "text"},
{"even", "more"}, {"text", "str\nings"},
{"and", "other"}, {"text", "values"}}, new Object[]{
"Column 1", "Column 2"});
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTable table = new JTable(model);
table.setRowHeight(40);
getContentPane().add(new JScrollPane(table), BorderLayout.CENTER);
pack();
}
public static void main(String arg[]) {
new Main().setVisible(true);
}
}
That's because the DefaultTableCellRenderer uses JLabel as the component to paint the cells. And labels can't have new lines. You have to use your own TableCellRenderer that uses a TextComponent that accepts new lines, for example JTextArea.
final JTextArea textArea = new JTextArea(); // or static field
//...
table.setDefaultRenderer(Object.class, new TableCellRenderer()
{
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
textArea.setText(value.toString());
return textArea;
}
});
Try copying and pasting a text of a couple of lines, to see it work. Now you might want to cahnge the cellEditor and prevent the Enter key from finalizing the edition so it can be used to write new lines in the cells.
I did this in easy way
JLabel l = new JLabel("<html>Hello World!<br>blahblahblah</html>", SwingConstants.CENTER)
I am able to display the buttons fine in a JTable; but I am having problems clicking on the button. I tried implementing a mouse listener for the JPanel but that does not work.
This is how i create my table:
Object[] columnnames = {
"ID", "Resource Name", "Incident", "Owner", "Action"
};
Object[][] sentByMe = //get data;
sentByMeTable =
new JTable(sentByMe, columnnames){
public TableCellRenderer getCellRenderer( int row, int column ) {
return new PlusMinusCellRenderer();
}
};
And this is my PlusMinusCellRenderer
class PlusMinusCellRenderer extends JPanel implements TableCellRenderer {
public Component getTableCellRendererComponent(
final JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
this.add( new JLabel( value.toString() ) );
JButton button = new JButton("+");
this.add(button);
return this;
}
So what i am having trouble with is being able to click on the buttons.
Thanks for all your help in advance.
JComboBox in TableCellEditor remember last selected value among different rows and even different TableModels. For example select a value on one row, then go to another row, start cell editing and JComboBox will have as its current value last select value on the previos row.
How can it fixed?
Set the value in the getTableCellEditorComponent(..) method.
Example:
public static void main(String... args) {
JFrame frame = new JFrame("Test");
JTable table = new JTable(10, 2);
JComboBox box = new JComboBox(new String[] {"A", "B", "C"});
table.setDefaultEditor(Object.class, new DefaultCellEditor(box) {
#Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
return super.getTableCellEditorComponent(
table,
table.getValueAt(Math.max(row-1, 0), column),
isSelected,
row,
column);
}
});
frame.add(table);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setVisible(true);
}