I haven't been able to show a JTable inside a JPanel from dynamically generated data. I have even tried adding a layout manager so that I don't end up with a null layout manager and no table. Here is the code I'm using.
public void setReferencePanel(ArrayList<Item> items, String refFile) {
String[] columns = {"first", "last"};
String[][] data = {{"Adam", "Smith"}, {"Jon", "Bon Jovi"},{"John", "Doe"}};
JTable sample = new JTable(data, columns);
refListingPanel.add(sample);
refListingPanel.setBorder(BorderFactory.createTitledBorder("Reference File - " + refFile));
}
and earlier in the same file.
private JMenuBar menuBar;
private JPanel testListingPanel;
private JScrollPane testScroller;
private JPanel refListingPanel;
private JScrollPane refScroller;
private static Dimension listingDefault = new Dimension(350, 230);
private IDiffPresenter presenter;
private boolean allItems;
private boolean unChangedItems;
private boolean changedItems;
private JTable refTable;
private JTable testTable;
public MasterFrame (IDiffPresenter presenter) {
super("Magic Diff - Under Construction");
this.presenter = presenter;
menuBar = new JMenuBar();
setupFileMenu(presenter);
setupExportMenu(presenter);
setupDisplayChangedMenu();
setupAboutMenu();
setupReferencePanel();
setupTestPanel();
getContentPane().setLayout(new GridLayout(1,2));
setJMenuBar(menuBar);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize((int)listingDefault.getWidth() + 10, (int)listingDefault.getHeight() + 60);
Dimension DimMax = Toolkit.getDefaultToolkit().getScreenSize();
this.setMaximumSize(DimMax);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
...
}
private void setupReferencePanel() {
refListingPanel = new JPanel();
refListingPanel.setLayout(new BorderLayout());
refListingPanel.setBorder(BorderFactory.createTitledBorder("Reference File"));
refScroller = new JScrollPane(refListingPanel);
getContentPane().add(refScroller);
}
What am I missing or failing to do? I have even tried some sample data, what is currently in the code, and I get the same issue.
This is based on what cmickr and Andrew Thompson posted. I modified the following functions to work.
public void setReferencePanel(ArrayList<Item> items, String refFile) {
DefaultTableModel model = new DefaultTableModel(vectorize(items), makeHeaderVector());
refTable.setModel(model);
refListingPanel.setBorder(BorderFactory.createTitledBorder("Reference File - " + refFile));
}
private Vector vectorize(ArrayList<Item> items) {
Vector results = new Vector();
for (int i = 0; i < items.size(); i++) {
results.addElement(items.get(i).vectorize());
}
return results;
}
private Vector makeHeaderVector() {
String[] cols = { ... }; // hid application specific string array
Vector<String> results = new Vector<String>(Arrays.asList(cols));
return results;
}
This is my basic understanding of vectors, since I do not use them much. Also, this may not be the fastest way of approaching the problem, but my first goal is to get it working, then improve it. The important part was to use a TableModel, in my case DefaultTableModel, and then setModel() of the the JTable to the new model, like was referenced.
Related
I have a panel for adding an item to the cart. For example:
public class SomePanel extends JPanel {
private static final long serialVersionUID = 1L;
private JLabel firstLabel;
private JLabel secondNameLabel;
private JLabel thirdLabel;
// and more..
private JTextField firstTextField;
private JTextField firstTextField;
private JTextField thirdTextField;
// and more..
private void init() {
firstLabel = new JLabel("First label");
secondLabel = new JLabel("Second label");
thirdLabel = new JLabel("Third label");
// and more..
firstTextField = new JTextField("first field");
secondTextField = new JTextField("second field");
thirdTextField = new JTextField("third field");
// and more..
}
This panel is located in the dialog. When I select "Add" in the menu, a dialog and this panel appear. There I can enter information about the product and add the product.
The problem is that I have another three areas on the main form. These areas also display the same panel as above. How can I reuse an existing SomePanel and would this be a good practice? Maybe it's better to create singletons for each element (JLabel and JTextField) instead?
Maybe there is some special pattern for solving this problem?
It is an excellent suggestion to re-use the panel object, and it doesn't just work for a fixed number of fields, you can do it with a dynamic number of fields as well.
You have already created a wrapper around a JPanel, so we can simply add a method to it that will update the panel to display the new contents. In this case I have created a new method create(...) that will update the contents.
For example, if you have a fixed number of fields it might look something like this:
public class SomePanel extends JPanel {
private static final long serialVersionUID = 1L;
final int labelHeight = 10;
final int fieldHeight = 20;
private JLabel firstLabel = createLabel("label 1", 0, 0);
private JLabel secondLabel = createLabel("label 2", 0, 30);
private JLabel thirdLabel = createLabel("label 3", 0, 60);
// and more..
private JTextField firstTextField = createField(null, 0, 10);
private JTextField secondTextField = createField(null, 0, 40);
private JTextField thirdTextField = createField(null, 0, 70);
// and more..
//New method to udpate the contents
public boolean create(List<String> labels, List<String> textFields) {
if(labels.size() != textFields.size()){
System.out.println("Failed to update panel, there was a different number of labels and fields");
return false;
}
//Update the fixed label and field values
firstLabel.setText(labels.get(0));
secondLabel.setText(labels.get(1));
thirdLabel.setText(labels.get(2));
firstTextField.setText(textFields.get(0));
firstTextField.setText(textFields.get(1));
firstTextField.setText(textFields.get(2));
//Make sure that this panel is visiable after updating the values
this.setVisible(true);
//Success, return true
return true;
}
//Remove the x and y depending on the layout manager
private JLabel createLabel(String name, int x, int y){
//Create label
JLabel label = new JLabel(name);
//Set location and size or use a layour manager
label.setLocation(x, y);
label.setSize(50, labelHeight);
//Configure cutsom label settings
//label.setFont(...);
//label.setBorder(...);
//return the custom label
return label;
}
//Remove the x and y depending on the layout manager
private JTextField createField(String content, int x, int y) {
//Create label
JTextField field = new JTextField();
if(content != null){
field.setText(content);
}
//Set location and size or use a layour manager
field.setLocation(x, y);
field.setSize(80, fieldHeight);
//Configure cutsom text field settings
//field.setFont(...);
//field.setBorder(...);
//return the custom field
return field;
}
}
Or if you want to get fancy with dynamic content with a flexible number of labels and fields you could do something like this:
public class SomePanel extends JPanel {
private static final long serialVersionUID = 1L;
final int labelHeight = 10;
final int fieldHeight = 20;
final int padding = 5;
//Keep a list of contents only if you need to edit/retreive data from the panel
private List<JTextField> fieldList = new ArrayList<>();
//New method to udpate the contents
public boolean create(List<String> labels, List<String> textFields) {
if(labels.size() != textFields.size()){
System.out.println("Failed to update panel, there was a different number of labels and fields");
return false;
}
//remove previous components
this.removeAll();
//reset the dynamic lists (For if you need to edit/retreive data from the panel)
fieldList = new ArrayList<>();
//placement values (remove these if using a layout manager)
int xPos = 0;
int yPos = 0;
//Update the lists based on the new values
for (int count = 0; count < labels.size(); count++) {
//Create and add labels
JLabel dynamicLabel = createLabel(labels.get(count), xPos, yPos);
this.add(dynamicLabel);
//update placement location, remove if you use a layout manager
yPos += labelHeight + padding;
//Create and add fields
JTextField dynamicField = createField(textFields.get(count), xPos, yPos);
this.add(dynamicLabel);
//update placement location, remove if you use a layout manager
yPos += fieldHeight + padding;
//Store fields in a list so that we can retreive the contents later if needed, or if
fieldList.add(dynamicField);
}
//Make sure that this panel is visiable after updating the values
this.setVisible(true);
//Success, return true
return true;
}
//Remove the x and y depending on the layout manager
private JLabel createLabel(String name, int x, int y){
//Create label
JLabel label = new JLabel(name);
//Set location and size or use a layour manager
label.setLocation(x, y);
label.setSize(50, labelHeight);
//Configure cutsom label settings
//label.setFont(...);
//label.setBorder(...);
//return the custom label
return label;
}
//Remove the x and y depending on the layout manager
private JTextField createField(String content, int x, int y) {
//Create label
JTextField field = new JTextField();
if(content != null){
field.setText(content);
}
//Set location and size or use a layour manager
field.setLocation(x, y);
field.setSize(80, fieldHeight);
//Configure cutsom text field settings
//field.setFont(...);
//field.setBorder(...);
//return the custom field
return field;
}
//Method to get the current field contents if needed or if edited by the user
public List<JTextField> getCurrentFieldContent (){
return fieldList;
}
}
I am making a simple sudoku and when I want to start a new game, I reload the panel. I first remove it and then add it to the frame. The problem is that I can choose the difficulty for new game, but it always selects the first "Easy" dificulty, not selected. So if I change it in JComboBox to "medium", when page is reloaded it will load the game with "Easy", not "medium".
What should I do so my refreshed panel will accept changed difficulty?
Here are methods that are used for this in my program:
JComboBox difficulty = new JComboBox();
DefaultComboBoxModel difficultyModel = new DefaultComboBoxModel();
difficultyModel.addElement("Easy");
difficultyModel.addElement("Medium");
difficultyModel.addElement("Hard");
difficulty.setModel(tezavnostModel);
difficulty.setSelectedIndex(0);
difficulty.setPreferredSize(new Dimension(100, 25));
newGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mainFrame.reloadSudokuBoard();
sudokuBoard.pickDifficulty(getDifficulty()));
}
});
public String getDifficulty() {
return (String)difficulty.getSelectedItem();
}
public void board(int[][] numbers, int zeros) {
int numberZeros = setDifficulty(sudokuForm.getDifficulty());
int[][] boardNumbers = gameNumbers();
public void reloadSudokuBoard() {
String newDifficulty = (sudokuForm.getDifficulty());
remove(sudokuBoard);
sudokuBoard.board(sudokuBoard.gameNumbers(), sudokuBoard.setDifficulty(newDifficulty ));
add(sudokuBoard, BorderLayout.WEST);
SwingUtilities.updateComponentTreeUI(sudokuBoard);
}
Hope this helps.
public void reloadSudokuBoard() {
int index = difficulty.getSelectedIndex();
String newDifficulty = (sudokuForm.getDifficulty());
remove(sudokuBoard);
sudokuBoard.board(sudokuBoard.gameNumbers(), sudokuBoard.setDifficulty(newDifficulty ));
add(sudokuBoard, BorderLayout.WEST);
SwingUtilities.updateComponentTreeUI(sudokuBoard);
difficulty.setSelectedIndex(index);
}
Before removing components, you can use the getSelectedIndex to get the index that was selected. After the element have been added, the setSelectedIndex will fix it
I have a program that allows the user to do a search in the warehouse. The result is returned in a JTable.
So far everything is good. When I attempt to do a second search, the old table is still showing.
Image:
Code:
public void panelTable(){
panelTable= new JPanel();
panelTable.setSize(400, 80);
panelTable.setOpaque(true);
panelTab = new JTable();
modele = new DefaultTableModel();
}
public void creerJTable(List<Pneu> liste){
String[] head= {"A", "B", "C"};
Object[][] data = null;
data = new Object[liste.size()][3];
Iterator<Pneu> it = liste.iterator();
int index = 0;
while(it.hasNext()){
Pneu unPneu = it.next();
data[index][0] = unPneu.descrip();
data[index][1] = unPneu.width();
data[index][2] = unPneu.height();
index++;
}
modele.setDataVector(data, head);
panelTab.setModel(modele);
panelTab.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
panelTab.setFillsViewportHeight(true);
panelTab.setPreferredScrollableViewportSize(new Dimension(500, 80));
panelTab.setModel(modeleColonnesNoEdit(data, entete));
panelTab.setRowSelectionInterval(0, 0);
panelTab.getColumnModel().getColumn(0).setPreferredWidth(250);
panelTab.getColumnModel().getColumn(1).setResizable(false);
panelTab.getColumnModel().getColumn(1).setPreferredWidth(50);
panelTab.getColumnModel().getColumn(2).setResizable(false);
panelTab.getColumnModel().getColumn(2).setPreferredWidth(50);
JScrollPane scrollPane = new JScrollPane(panelTab);
scrollPane.setPreferredSize(new Dimension(500, 60));
panelTable.add(scrollPane);
}
When clicking on the search button, you are taken to the class Listener which verifies that the button search was clicked. Once that is done, you have this code:
frame.creerJTable(liste);
This line of code, takes the list created from that search and calls the method creerJTable(List liste) that is shown in the above code.
Here's the code for the modeleColonnesNoEdit()
private DefaultTableModel modeleColonnesNoEdit(Object[][] data, String[] head) {
return new DefaultTableModel(data, head)
{
boolean[] columnEditables = new boolean[] { false, false, false};
public boolean isCellEditable(int row, int column) {
return columnEditables[column];
}
};
}
You should not be re-adding a JScrollPane or adding any new components to the GUI in the search. Instead, take the original JTable, simply change its TableModel, and that's it, do nothing more.
I am new to Java and I want to make a simple game of chess perhaps later will add sockets. First I wanted to start designing the board to which use GridLayout JLabel as shown . My problem is that I want to add to each Label an image to simulate the " chip " of the game but do not know how, I tried many things but does not leave me, I want help please.
This code generated my table of 8x8
public class Ventana extends javax.swing.JFrame {
private static final int COLUMNAS = 8;
private static final int FILAS = 8;
public Ventana() {
initComponents();
ImageIcon fNegra = new ImageIcon("Images/FichaNegra.png");
ImageIcon fRoja = new ImageIcon("Images/FichaRoja.png");
jPanel1.setLayout(new GridLayout(FILAS, COLUMNAS));
JLabel [][] jLabel = new JLabel[FILAS][COLUMNAS];
for (int i=0;i<FILAS;i++)
for (int j=0;j<COLUMNAS;j++)
{
jLabel[i][j] = new JLabel();
jLabel[i][j].setOpaque(true);
if((i+j)%2 == 0)
{
jLabel[i][j].setBackground(Color.WHITE);
jPanel1.add(jLabel[i][j]);
}
else
{
jLabel[i][j].setBackground(Color.GRAY);
jPanel1.add(jLabel[i][j]);
}
}
this.add(jPanel1);
this.setVisible(true);
}
I have a JDialog dlg, created by a JFrame frm, that contains a JList list.
When I modify the list (through the ListModel), the list itself is repainted but not the JDialog.
This means that, if I delete a line, the list remains with an empty line while if I add a line, this new line won't be shown (because there is no space in the dialog) until I manually force repainting of dlg (doubleclicking in frm).
Following advices in this post :
How to make repaint for JDialog in Swing?
and in this post:
Force repaint after button click
I tried to call, from my controller class (which is where updates to list are made), the following line:
SwingUtilities.getWindowAncestor(dlg).repaint();
but it didn't work.
I also tried:
dlg.repaint();
No luck either...
Any clue?
Thank you very much.
EDIT:
The organization of my classes is as follows:
a controller class that contains a reference to the main JFrame, frm.
I also extended JDialog into MyDialog, which contains a JList.
When a doubleclick on frm is detected, I show the instance of MyDialog (or create, if it is the first time I show it) and the JList is filled with the data passed to the DefaultListModel. MyDialog is painted so that the list has only the space that it needs.
Now, when a specific event is detected by the controller, I get the specific MyDialog, get the ListModel from JList and update it. Here the JList is indeed updated, but Dialog remains the same.
I use a code like this:
MyDialog dlg = group.getDlg();
if(dlg != null){
DefaultListModel listModel = ((DefaultListModel) dlg.getMyJList().getModel());
listModel.addElement(idStock);
SwingUtilities.getWindowAncestor(dlg).repaint();
}
This doesn't repaint dlg.
I also tried:
SwingUtilities.getWindowAncestor(dlg.getMyJList()).repaint();
but it doesn't work.
I checked with the debugger that the lines are actually executed.
I don't have much more code to show, really.....
I think that you going wrong way, define DefaultListModel that accesible throught all Java methods and Classes, this Model would holds your Objects, then put JList to the JDialog or JOptionPane, for example
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
// based on #trashgod code
/** #see http://stackoverflow.com/questions/5759131 */
// http://stackoverflow.com/questions/8667719/jdialog-repaint-after-jlist-modification
public class ListDialog {
private static final int N = 12;
private JDialog dlg = new JDialog();
private DefaultListModel model = new DefaultListModel();
private JList list = new JList(model);
private JScrollPane sp = new JScrollPane(list);
private int count;
public ListDialog() {
list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
JPanel panel = new JPanel();
panel.add(new JButton(new AbstractAction("Add") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
append();
if (count <= N) {
list.setVisibleRowCount(count);
dlg.pack();
}
}
}));
panel.add(new JButton(new AbstractAction("Remove") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
int itemNo = list.getSelectedIndex();
if (itemNo > -1) {
removeActionPerformed(e, itemNo);
}
}
}));
for (int i = 0; i < N - 2; i++) {
this.append();
}
list.setVisibleRowCount(N - 2);
dlg.add(sp, BorderLayout.CENTER);
dlg.add(panel, BorderLayout.SOUTH);
dlg.pack();
dlg.setLocationRelativeTo(null);
dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dlg.setVisible(true);
}
private void removeActionPerformed(ActionEvent e, int itemNo) {
System.out.println("made_list's model: " + list.getModel());
System.out.println("Model from a fresh JList: " + new JList().getModel());
model = (DefaultListModel) list.getModel();
if (model.size() > 0) {
if (itemNo > -1) {
model.remove(itemNo);
}
}
}
private void append() {
model.addElement("String " + String.valueOf(++count));
list.ensureIndexIsVisible(count - 1);
}
public static void main(String[] a_args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ListDialog pd = new ListDialog();
}
});
}
}