I am having trouble with one a custom ListCellRenderer on a JList. When there is only 1 item in the List the cell is displayed correctly, but when there is more than 1 item, each cell seams to be painted with the content of all cells overlapping each other, like this:
My CellRenderer looks like this:
public class SendungsCellRenderer extends JPanel implements ListCellRenderer {
private EmptyBorder eb = new EmptyBorder(5, 2, 5, 2);
private LineBorder lb = new LineBorder(new Color(255,255,255), 5);
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
uiSendungsbutton p = (uiSendungsbutton) value;
if(isSelected){
this.setBackground(new Color(200,200,250));
this.setBorder(new CompoundBorder(lb, new StrokeBorder(new BasicStroke())));
}else{
this.setBackground(new Color(252,252,252));
this.setBorder(lb);
}
this.setLayout(p.getLayout());
this.add(p.getNamePnl(),BorderLayout.NORTH);
this.add(p.getKdnrPnl(), BorderLayout.CENTER);
return this;
}
}
and it is set using
list_Sendung = new JList(getSendungen().toArray());
list_Sendung.setVisibleRowCount(1);
list_Sendung.setValueIsAdjusting(true);
list_Sendung.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list_Sendung.setCellRenderer(new SendungsCellRenderer());
The method getSendungen() returns an ArrayList of uiSendungsbutton.
How do I get the JList to display each item in a cell of its own correctly?
The problem is that the same cell renderer is being used for all cells, and for each new cell, you add the components to this again. To fix this problem, remove all components from this each time, using removeAll. Your code would look like this after it was fixed:
public class SendungsCellRenderer extends JPanel implements ListCellRenderer {
private EmptyBorder eb = new EmptyBorder(5, 2, 5, 2);
private LineBorder lb = new LineBorder(new Color(255,255,255), 5);
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
this.removeAll();
uiSendungsbutton p = (uiSendungsbutton) value;
if(isSelected){
this.setBackground(new Color(200,200,250));
this.setBorder(new CompoundBorder(lb, new StrokeBorder(new BasicStroke())));
}else{
this.setBackground(new Color(252,252,252));
this.setBorder(lb);
}
this.setLayout(p.getLayout());
this.add(p.getNamePnl(),BorderLayout.NORTH);
this.add(p.getKdnrPnl(), BorderLayout.CENTER);
return this;
}
}
Related
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();
}
}
}
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.
I have a JList in Java. Whenever the user clicks on an element,
I would like to add a specific borderLine in that element.
Is that possible?
I have the following code in Java:
DefaultListModel listModel = new DefaultListModel();
listModel.addElement("element1");
listModel.addElement("element2");
listModel.addElement("element3");
list = new JList(listModel);
list.addListSelectionListener(this);
For the listener i have:
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (list.getSelectedIndex() == -1) {
;
} else {
CurrentIndex = list.getSelectedIndex();
//set Current's Index border, how can i do that?
}
}
}
Create a custom renderer for the list and add a Border to the item that is selected.
Read the section from the Swing tutorial on How to Use Lists for more information and examples.
You can use a custom ListCellRender. Then in the if (isSelected) just add the border.
public class MyListCellRenderer implements ListCellRenderer{
private final JLabel jlblCell = new JLabel(" ", JLabel.LEFT);
Border lineBorder = BorderFactory.createLineBorder(Color.BLACK, 1);
Border emptyBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2);
#Override
public Component getListCellRendererComponent(JList jList, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
jlblCell.setOpaque(true);
if (isSelected) {
jlblCell.setForeground(jList.getSelectionForeground());
jlblCell.setBackground(jList.getSelectionBackground());
jlblCell.setBorder(new LineBorder(Color.BLUE));
} else {
jlblCell.setForeground(jList.getForeground());
jlblCell.setBackground(jList.getBackground());
}
jlblCell.setBorder(cellHasFocus ? lineBorder : emptyBorder);
return jlblCell;
}
}
Then instantiate the render.
MyListCellRenderer renderer = new MyListCellRenderer();
JList list = new JList();
list.setCellRenderer(renderer);
The renderer will return a JLabel. So you can do anything you want to that label and that's what will appear in cell.
See ListCellRenderer javadoc
I have set the default font in my JTable as show below
myTable.setFont(new java.awt.Font("Verdana", 1, 10));
I wanted to show a bigger font in my JTable,while some data is being typed into the cells.So I used MyTableCellEditor custom class.
public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {
JComponent component = new JTextField();
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int rowIndex, int vColIndex) {
((JTextField) component).setText((String) value);
((JTextField) component).setFont(new Font("Verdana", 1, 12));
return component;
}
public Object getCellEditorValue() {
return ((JTextField) component).getText();
}
}
Below is the code where I attached the CustomCellEditor to my table.
myTable.getColumnModel().getColumn(1).setCellEditor(new MyTableCellEditor());
But this code do not seem to work.The cells font becomes small while editing and once I finish editing and hit enter,the default JTable font which I set ( Verdana 10 ) takes effect.Why is this happening ? I have already set CustomCellEditor font as ( Verdana 12 ) to my cells.
Don't create a new class for this. Just change the property of the DefaultCellEditor:
JTextField textField = new JTextField();
textField.setFont(new Font("Verdana", 1, 12));
textField.setBorder(new LineBorder(Color.BLACK));
DefaultCellEditor dce = new DefaultCellEditor( textField );
myTable.getColumnModel().getColumn(1).setCellEditor(dce);