How to add listener to table? - java

I am trying to add a listener to JTable that delete a selected rows.
I have a class ToolBar in which contains all the buttons,
but all my JTable setting is on another class: TablePanel.
I want to be able to delete row(s) when the user click a buttons in ToolBar Class.
ToolBar.java
public class ToolBar extends JPanel
{
TablePanel tablePane;
JButton openButton, saveButton, addButton, delButton;
ImageIcon openIcon, saveIcon, addIcon, delIcon;
Image openImage, saveImage, addImage, delImage;
Image openImage2, saveImage2, addImage2, delImage2;
ButtonListener listener;
public ToolBar(TablePanel tablePane)
{
this.tablePane = tablePane;
//Bunch of codes here to initialize all the buttons and icons
}
//Button Listener
private class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
if (event.getSource() == openButton)
JOptionPane.showMessageDialog(null, "hello");
if (event.getSource() == saveButton)
tablePane.saveData();
if (event.getSource() == addButton)
tablePane.addRow();
if (event.getSource() == delButton)
tablePane.delRow();
}
}
}
TablePanel
public class TablePanel extends JPanel
{
//Table's column name
private ArrayList<String> columnNames = new ArrayList<String>();
//List of data, later needs to be change
//so that it will be editable on the go
//It starts with 5 columns
//User can add more columns
private ArrayList<Object[]> data = new ArrayList<Object[]>();
//DefaultTableModel is needed for adding new rows
private JTable table;
private TModel tModel;
private JScrollPane scrollPane;
//For importing & exporting data
JFileChooser fileChooser;
public TablePanel()
{
//Column Names:
columnNames.add("Date");
columnNames.add("Category");
columnNames.add("Details");
columnNames.add("Add/Subtract");
columnNames.add("Total");
//Example data:
data.add(new Object[]{20140925, "Grocery", "Supermarket", -5.23,600.00});
data.add(new Object[]{20141013,"Car Maintenance", "Changing Tires", -200.00, 400.00});
//Some codes here
}
private class TModel extends AbstractTableModel implements TableModelListener
{
//Bunch of codes(methods) in here such as:
//public voide setValueAt, public Boolean isCellEditable, getColumnCount etc.
//Method for deleting row
public void delRow()
{
public void tableChanged(TableModelEvent event)
{
int row = event.getFirstRow();
fireTableRowsDeleted(row, row);
}
}
} //End of TModel class
} //End of TablePanel Class
How should I implement listener and fireTableDeleted(int row)?
What should I add in the public void delRow()?

Someone is going to need a reference to someone else, but you also want to maintain a level of separation so you don't end up tightly coupling your components together
You could use a controller of some kind, which has a reference to the table and is either listening directly to the buttons on the toolbar or which the tool bar can call and instruct it on what it wants to do.
For example, when clicked, the delete button would simply instruct the controller to "delete the selected rows". The controller would ask the TablePane to "Delete the selected rows" and the TablePane would comply.
This could be achieved through the Actions API where the Action would act as the controller.
Basically you would create a new DeleteRowAction (this is class you'd have to create), which had a reference to the TablePane and which you would pass to the ToolBar pane. You would then apply the Action to the delete button (JButton#setAction) and let it take care of everything else for you

Related

JTable and JButton click not working

I have a JPanel holding a JButton and JScrollPane (in turn holding a JTable) and am currently running into two issues which I believe are related:
The JButton listener's actionPerformed() method is not invoked upon click. The only way in which I can get it to be invoked is by calling doClick() on the JButton. The JButton color changes upon hover but no click animation is shown when the mouse is pressed.
Secondly, if a cell is clicked within the JTable, the cell located 2 rows down in the same column registers the click instead. This offset does not occur when clicking in the column headers (i.e. to adjust cell widths), only when within the cell area.
Left-hand panel. Click position circled
public class InventoryPanel extends JPanel {
// Parent Business object reference for communication and JFrame
private Business parent;
private AddItemPanel addItemPanel;
// Inventory table items
private DefaultTableModel inventoryModel;
private JTable inventoryTable;
private JScrollPane inventoryScrollPane;
private JLabel updateLbl;
private JButton addItemBtn;
// Columns for inventory table
private static final String[] INVENTORY_COLUMNS = {"Item","Stock","Restocking Level","Edit"};
public InventoryPanel(Business parent) {
this.parent = parent;
initGUI();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
//doStuff
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(new PrintStream(System.out));
}
}
}
}).start();
}
// INITIALISES GUI
public void initGUI() {
this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
JLabel titleLabel = new JLabel("<html><B>Inventory</B></html>");
this.add(titleLabel);
// Create empty inventory table
inventoryModel = new DefaultTableModel(new Object[3][4],INVENTORY_COLUMNS);
inventoryTable = new JTable(inventoryModel);
inventoryScrollPane = new JScrollPane(inventoryTable);
// Create button to allow items to be added
addItemBtn = new JButton("Add item");
addItemBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("ADD ITEM PRESSED");
}
});
updateLbl = new JLabel("Loading inventory...");
this.add(addItemBtn);
this.add(inventoryScrollPane);
this.add(updateLbl);
}
I've tried removing the table from the panel to see if that solves the JButton issue and visa-versa, but no luck. I've also tried changing the project JDK but no luck there either.
There are other JPanels adjacent to the troublesome one in a JFrame which work perfectly fine. Any ideas?
Edit: I can create a working instance of the InventoryPanel alone in a frame in another project, as mentioned in the comments. However the exact same code (no calls being made to other objects/methods) in the current project now produces ClassCastExceptions. After some googling this seems to be due to non-EDT threads updating the GUI.
However there is no use of the Business class, and all GUI operations are performed using the SwingUtilities.invokeLater() method like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("test");
frame.add(new InventoryPanel());
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
Note: the no-argument constructor InventoryPanel() just calls initGUI().
Thanks for the help so far...still very confused by this.

Categories don't show on JComboBox

I'm writing code in a JPanel, it's all working fine. However, the categories are not displayed when I view the panel.
Here's the code I wrote:
for(Category c : categories){
comboModel.addElement(c);
NoResultsLabel.setVisible(false);
}
CategoriesCombo.setModel(comboModel);
So that in the customized code inside the design I write the following:
CategoriesCombo.setModel(comboModel);
However, the categories still don't show in the combobox.
Do you try to change NoResultsLabel.setVisible(false); to NoResultsLabel.setVisible(true); and let us know if your problem is solved
NoResultsLabel.setVisible(false); to NoResultsLabel.setVisible(true);
make sure your loop is ok,i mean Categories and Category class and
make sure your CategoriesCombo is a JComboBox type and then add your ComboBox to Jpanel
then use DefaulComboBoxModel for give a model to ComboBox
like this :
class test extends JFrame{
private JComboBox combo;
private final DefaultComboBoxModel model;
private Jpanel panel;
test()
{
combo = new JComboBox();
model = new DefaultComboBoxModel();
panel = new Jpanel();
createModel();
combo.SetModel(model);
panel.add(Combo);
add(panel);
}
void createModel()
{
for(Category c : categories){
model.addElement(c);
NoResultsLabel.setVisible(false);
}
public static void main(String[] args)
{
test t = new test();
}
}

How to use ActionListener when the button function is in another class

I have three different classes: Main, WindowFrameDimetnions, and ValidationOfNumbers.
Main – Calls WindowFrameDimetnions. It is the main class
WindowFrameDimetnions – Calls (well I am trying to call ) ValidationOfNumbers. This is the class that creates the frame for the program, the pane, the label for the box, and the button.
ValidationOfNumbers – is the one that does all the calculations for number validations. Basically this class validates that the numbers typed by the use are within the range of 1..100,000.
Goal:
The goal is to connect WindowFrameDimetnions with ValidationOfNumbers by using an ActionListener.
package BlueBlueMainFiles;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class WindowFrameDimentions extends JFrame{
final static int WINDOW_WITH = 950;//Window with in pixel
final static int WINDOW_HEIGH = 650;//Window height in pixel
static JPanel panel;//use to reference the panel
static JLabel messageLabel;//use to reference the label
static JTextField textField;//use to reference the text field
static JButton calcButton;//use to reference the button
public WindowFrameDimentions() {
// TODO Auto-generated constructor stub
}
public static void windowFrameDimentions(){
//create a new window
JFrame window = new JFrame();
//add a name to the window
window.setTitle("BLUE BLUE");
//set the size of the window
window.setSize(WINDOW_WITH, WINDOW_HEIGH);
//specify what happens when the close button is pressed
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//BUILD THE PANEL AND ADD IT TO THE FRAME
buildPanel();
//ADD THE PANEL TO THE FRAMES CONTENT PANE
window.add(panel);
//Display the window
window.setVisible(true);
}
public static void buildPanel(){
//create a label to display instructions
messageLabel = new JLabel("Enter a Number from 1..100,000");
//create a text field of 10 characters wide
textField = new JTextField(10);
//create panel
calcButton = new JButton("Calculate");
//Add an action listening to the button. Currently, I can't make it work
//Create the a JPanel object and let the panel field reference it
panel = new JPanel();
panel.add(messageLabel);
panel.add(textField);
panel.add(calcButton);
}
}
Now this is the other code:
package TheValidationFiles;
public class ValidationOfNumbers {
static int MAX_NUMBER_TO_VAL = 10000000;
public static void GetValidationOfNumbers(boolean isTrue, String s) {
String[] numberArray = new String [MAX_NUMBER_TO_VAL];
boolean numberMatching = false;
for (int i = 0; i < MAX_NUMBER_TO_VAL; i++){
numberArray[i] = Integer.toString(i);
if (numberArray[i].equals(s)){
System.out.println("The number you typed " + s + " Matches with the array value of: " + numberArray[i]);
System.exit(0);
break;
}
else{
numberMatching = true;
}
}
if(numberMatching){
ValidationOfFiles.ValidationOfFiles(s);
}
}
}
You can try to make an anonymous AbstractAction:
panel.add(new JButton(new AbstractAction("name of button") {
public void actionPerformed(ActionEvent e) {
//do stuff here
}
}));
well hope this should work..try importing package TheValidationFiles into WindowFrameDimentions
then code for actionlistener
calcButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
ValidationOfNumbers von=new ValidationOfNumbers();
von.GetValidationOfNumbers(boolean value,string);
}});
It seems to me you are trying to achieve something like a MVC pattern. In this case,
Your Validation class will be treated as the Model (logic and data)
Your Frame class acts as the View (presentation / user interface)
Your Main class acts as the Cnotroller (middleman betweem Model and View)
Note that Model and View should not know the existence of one another. They communicate via the Controller.
Hence your Controller (Main class) should hold a reference of View (Frame class) and Model (Validation class):
//Your controller
public class MainClass{
private WindowFrameDimentions view;
private ValidationOfNumbers model;
}
Now the crucial part to link View to your Controller:
Because your view does not handle the logic and implementation, hence you don't code the implementation for button's action listener in this class directly, instead, just add a method to receive an ActionListener:
//The view
public class WindowFrameDimentions{
private JButton calcButton;
private JTextField textField; //please use a better name for this
public WindowFrameDimentions(){
//Initialize all other required attributes here..
calcButton = new JButton("Calculate");
}
//The controller will create a listener and add to calcButton
public void addCalcButtonListener(ActionListener listener){
calcButton.addActionListener(listener)
}
//You need a getter for all the input fields such as your JTextFields
public String getInput(){
textField.getText();
}
}
For your Validation class, it will be just a simple method to validate like this:
//The model
public class ValidationOfNumbers{
public ValidationOfNumbers(){
//Initialize all other required attributes here..
}
public boolean validationPassed(String input){
//your validation code goes here..
}
}
Now, linking all 3 classes together, you have:
//The controller
public class MainClass{
private WindowFrameDimentions view;
private ValidationOfNumbers model;
public static void main(String[] args){
view = new WindowFrameDimentions();
model = new ValidationOfNumbers();
view.addCalcButtonListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
//Now, we can use the Validation class here
if(model.validationPassed(view.getInput())){ //Linking Model to View
//If validation passes, do this
}
//Any other actions for calcButton will be coded here
}
});
}
}
This is the overall idea of linking all 3 classes. Normally, I would have 4 classes instead of 3 when implementing MVC, 1 more class to drive the codes. But in this example, I use Controller class to drive the codes.
Also note that, you should actually be extending to a JPanel instead of a JFrame, then add the instance of the extended class to the JFrame.

How to make a JList "refresh" method in a JPanel class

I'm a beginner at java and want to make a JFrame with tabs containing a seperate JPanel. One panel has a list where it displays things that you select in a different panel, so I want this panel to always display a list of stuff that you have selected in a different panel (I hope that makes sense). To do this, I need to make a method to refresh the JList. This is the Farthest that I've gotten on that:
public class PanelClass extends JPanel {
private JList list;
private DefaultListModel listModel = new DefaultListModel();
private ArrayList<SomeOtherClass> objectArray = new ArrayList<SomeOtherClass>();
public PanelClass() {
list.setModel(listModel);
}
public void refresh() {
updateListModel();
list.setModel(listModel);
}
public void updateListModel() {
if (objectArray.isEmpty()) {
System.out.println("No Objects In Array!");
} else {
listModel.clear();
for (SomeOtherClass SOC : objectArray) {
// SOC.getName() just returns a string
listModel.addElement(SOC.getName());
}
}
}
public void addObjectToArray(SomeOtherClass SOC) {
objectArray.add(SOC);
}
}
Could someone please tell me how to make a "refresh" method to constantly keep the JList up to date?
The AWT/Swing event model is based upon the widgets being event sources (in the MVC paradigm, they are both view and controller). Different widgets source different event types.
Look at the java.awt.event (primarily), and javax.swing.event packages for the listener interfaces you'll need to implement and register in order to produce your desired effect.
Basically, you write a Listener implementation, and register it with Widget1. When Widget1 detects an event, it will notify you, and you can then use the information it provides to update Widget2.
For instance, if a button being clicked would add an object to your list, you might have something like below (I usually put this code in the encompassing JFrame class, and make it implement the listener interfaces; but you can choose to use inner classes or separate listener classes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyFrame extends JFrame implements ActionListener {
private JButton button = new JButton("Click me!");
private DefaultListModel<String> listModel = new DefaultListModel<String>();
private JList<String> list = new JList<String>(listModel);
private int counter = 1;
public MyFrame() {
setTitle("Test Updates");
JTabbedPane tabs = new JTabbedPane();
add(tabs, BorderLayout.CENTER);
JPanel panel = new JPanel();
panel.add(list);
tabs.add("Selections", panel);
panel = new JPanel();
button.addActionListener(this);
panel.add(button);
tabs.add("Options", panel);
pack();
}
#Override
public void actionPerformed(final ActionEvent event) {
if (button.equals(event.getSource())) {
listModel.addElement("Item " + counter++);
}
}
/* Test it! */
public static void main(String[] args) {
final MyFrame frame = new MyFrame();
frame.addWindowListener(new WindowAdapter() {
#Override public void windowClosing(final WindowEvent e) {
frame.setVisible(false);
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
This code sample is minimal, but it should give you an idea of how to go about implementing what you want.
You can do it in two way. First : Write it in infinite thread loop so that it will constantly update JList. Second : You can call refresh() method whenever new SOC objects are added in your ArrayList. It means you can call refresh() method from addObjectToArray() method which ultimately call the refresh method only when you have some change in your ArrayList.
FYI : I did it in my project and I went for second option.

JComboBox, many visible Items in list, but the first item is always selected

First i have these declared as global variables:
private static ArrayList<Resource> resourceList;
private static JComboBox resourceBox;
Then i have a method that adds String items to a JComboBox. The JComboBox is put on a JPanel (not shown here).
private static JComboBox createComboBox(){
resourceBox = new JComboBox();
for(Resource r : resourceList){
resourceBox.addItem(r.getName());
}
return resourceBox;
}
The following method creates a JButton which is added to the same panel.
private static JButton createButton() {
JButton b = new JButton("Click");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
System.out.println(resourceBox.getSelectedItem());
}
});
return b;
}
It all displays nicely in my JFrame window. I can click the JComboBox and see all the different items in it. They're called "Res1", "Res2", "Res3" and so on. However, when i click the button it always prints "Res1" (first item in the list), no matter what I have selected in the combo box.
Any idea what might cause this?

Categories