JTable with 2 different data - java

Im using a JTable , loading on it a different data depending on the button pressed.
The problem is : when one of the data is loaded, if i try to load the other one, and pass ther mouse over the header or a cell, it updates the header/cell with the data from the first input, if there is data on the header/cell selected.
Any ideas on how to solve it? That's the code im using.
private static void setCompromissosTable(Object[][] data, Object[] header){
try{
compromissosTable.removeAll();
} catch(Exception e){
e.printStackTrace();
}
compromissosTable = new JTable(data, header);
compromissosTable.setRowSelectionAllowed(true);
// Make the entire row selectable, but not editable
int columnMax = compromissosTable.getColumnCount();
for(int column = 0; column < columnMax; column++){
Class<?> col_class = compromissosTable.getColumnClass(column);
compromissosTable.setDefaultEditor(col_class, null);
}
scrollPane = new JScrollPane(compromissosTable);
pane.add(scrollPane);
scrollPane.setBounds(btnAddCompromisso.getX(),
btnAddCompromisso.getHeight() + btnAddCompromisso.getY() + 5
, frame1.getWidth() - 20
, frame1.getHeight() - 20);
compromissosTable.revalidate();
compromissosTable.repaint();
compromissosTable.addMouseListener(new MouseAdapter() {}
//Change mouse behavior.
);
}

This is suspicious...
compromissosTable = new JTable(data, header);
//...
scrollPane = new JScrollPane(compromissosTable);
pane.add(scrollPane);
Basically, assuming that each time you want to switch data sets, you are calling this method, you are creating a new JTable and JScrollPane each time and then are adding it onto the UI...
What about the previous JTable?
Next is this...
scrollPane.setBounds(btnAddCompromisso.getX(),
btnAddCompromisso.getHeight() + btnAddCompromisso.getY() + 5
, frame1.getWidth() - 20
, frame1.getHeight() - 20);
This looks like you're using a null layout. Basically what it "looks" like is happening, is you're just stacking the JScrollPanes ontop of each other, which would explain, in part, the graphics glitches, as the components are actually been added at the same z-deepthness (essentially) and are competing with each other then they are updated.
Two simple answers...
Don't use null layouts. Sure they "seem" like a good idea, but they have a tendency to turn around and bite you in strange and wonderful ways which are hard to diagnose and fix. Use the layout management API which Swing was designed around
Update the JTables model instead of creating a new JTable/JScrollPane each time
See How to use tables and Laying Out Components Within a Container

Related

Advice on Implementing a simple Delete button in Swing

So my issue that I have is implementing a functioning delete button for my GUI.
While I have just about everything working, I have been stumped with trying to implement this function. What it does is as i click the 'Add' button, it creates a row with text fields and a check box. The 'Delete' works in the sense that it only deletes the most recent field create once I click on the checkbox to delete it. My intention is that the GUI works in a dynamic way to where I can click whatever check boxes and delete only those specific rows with the boxes checked.
I've researched methods of using an ItemListener but I'm still wrestling with that as I figure its the most proficient way to go. I've also done the storing the components in an array to iterate over. I feel I'm close with what I have now, any advice appreciated.
Below is the 'Add' button code to create new rows in my GUI. Then there is the 'Delete' button code which places the components in an array, but only deletes the most recent row created that has been checked.
add = new JButton("Add");
add.addActionListener(e ->{
rowPanel = new JPanel(new GridLayout(1,4,5,5));
for(int i = 0; i < 4; i++ ){
rowPanel.add(new JTextField(8));
}
for(int l=0; l < 1; l++){
rowPanel.add(new JCheckBox(), BorderLayout.EAST);
}
infoPanel.add(rowPanel);
infoPanel.revalidate();
infoPanel.repaint();
});
delete = new JButton("Delete");
delete.addActionListener(e -> {
Component[] components = rowPanel.getComponents();
for(Component c : components){
if(c instanceof JCheckBox){
if(((JCheckBox)c).isSelected()){
infoPanel.remove(rowPanel);
}
}
}
infoPanel.revalidate();
infoPanel.repaint();
});
You can use a JTable as a container and add a custom row that is a checkbox and a textfield. This way you just have to get the checkbox's event and see what index in the JTable it is located and delete it.
This might be useful:
https://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender

simplier way to add jbutton to jtable

well i am making this system that has a table, and i have to put buttons in the last column. i've been researching but all the codes i saw are really confusing. there is one tho, but there are still some parts that i didn't understand. here's the site where i got it http://www.javaquery.com/2013/05/how-to-implement-jbutton-in-jtable.html
String[] InvoiceArray = new String[20];
//Declare above variable globally. Used by two-three methods. Change variable name as per your need.
/*
* import the ButtonColumn class if you are not working in IDE
* I used formWindowOpened event to load content in Jtable but you can use other event.
* All you need is put the code with in that event.
*/
private void formWindowOpened(java.awt.event.WindowEvent evt) {
Object[][] rowData = new Object[4][2]; // 4: is number of row ; 2: is number of column
Object columnNames[] = {"Invoice No", "View Report"}; // Name of columns
for (int i = 0; i < 4; i++) {
InvoiceArray[i] = i + "-2345";
rowData[i][0] = i + "-2345";
rowData[i][1] = "View Order " + i; // Can change the text of button.
}
DefaultTableModel tm = new DefaultTableModel(rowData, columnNames);
jTable1.setModel(tm);
ButtonColumn buttonColumn = new ButtonColumn(jTable1, showOrder, 1); // 1: is column number. column count starts with 0,1,2...
}
what's the InvoiceArray for? and should i make the showOrder from the last line? and also, i didn't understand the code he posted on how to make a listener on it. here it is:
Action showOrder = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
//JTable table = (JTable) e.getSource(); // If you have multiple component following the ActionEvent
int modelRow = Integer.valueOf(e.getActionCommand());
if (InvoiceArray[modelRow] != null) {
/* We are placing invoice no in array
* And track the button click index
* And fetch index in invoice no
*/
System.out.println("Your Invoice No:" + InvoiceArray[modelRow]);
} else {
JOptionPane.showMessageDialog(rootPane, "No records found!");
}
}
};
i know there are some explanations already. i understand some of them but not all. just a simplier way to add jbutton on jtable and also listeners for the jbutton. thank you so much
just a simplier way to add jbutton on jtable and also listeners for the jbutton.
There is no simple way. You need to understand how renderers and editors work in a JTable. Read the section from the Swing tutorial on Concepts: Renderers and Editors for the basics.
Then you can check out Table Button Column which does the hard work for you. You only need to provide the Action to be invoked when you click on the button.
what's the InvoiceArray for?
It is used to load data into the JTable. This is basic usage of a JTable and has absolutely nothing to do with adding a button to a column of the table.
After the data is loaded you should forget about the invoiceArray. The Action you write should access the data via the TableModel or the JTable.

JComboBox is refering to old Frame while removeAllItems()

I tried to figure this out myself but I can't. I'm stuck at a strange problem.
I have a Java Program with multiple classes and forms (I use Intellij and the build in GUI-Creator). When I switch from one Screen to another I just call frame.setVisible(false); at the leafing window and frame.setVisible(true); at the window I want to show next.
On a Button Click I make this:
In Class 1:
if (e.getSource() == umschaltenButton) {
this.mainW.goToMainWindow();
logger.log(Level.INFO, "Switched Back to MainMenu");
frame.setVisible(false);
}
And here is the weird part.
In Class 2:
public void goToMainWindow() {
frame = tvElectronics.drawMainWindow(); // I get a new Frame with new Images and so on
frame.addMouseListener(al);
frame.add(BotomPanel); // in here is the JComboBox
frame.setSize(LENGTH, HEIGHT);
comboBox1.removeAllItems(); // Here it tryes to refere to the old frame before i made frame = tvElectronics.drawMainWindow();
Vector<String[]> content = tvElectronics.getContent();
for (int i = 0; i < tvElectronics.getAnz(); ++i) {
comboBox1.addItem((i + 1) + ". " + content.get(i)[3]);
}
comboBox1.setSelectedIndex(chanel);
frame.setVisible(true);
}
And so it tries to update the old frame from class2 which no longer exists because of the new one I just created. And so I have 2 frames open: one as I want it and one strange old frame form class2.
My problem is that I want bind my JComboBox to a new Frame and update it but it is still connected to the old one and that causes weird problems like jumping back in the function. I mean it is at the last line of goToMainWindow() and then it starts again at the first line.
First off you should avoid swapping JFrames as your program does since this is a very annoying GUI design. Please read The Use of Multiple JFrames, Good/Bad Practice? for more on this.
Next, it's impossible for us to tell what GUI view your JComboBox is associated with.
But having said that, it really shouldn't matter. Instead of doing what you're doing, I would give the display class that holds a JCombBox a public method that you call on the containing display class that clears the contained JComboBox's model or that places items in the model. This way, there will be no ambiguity as to which JComboBox you're referring to, and this way you avoid directly exposing a view's inner components.
As an aside, I try to gear my display or view classes towards creating JPanels, not JFrames as this will give my code much greater flexibility.
For example
// my display class
class Display1 {
private DefaultComboBoxModel<String> myModel = new DefaultComboBoxModel<>();
private JComboBox<String> myCombo = new JComboBox<>(myModel);
public void removeAllComboElements() {
myModel.removeAllElements();
}
public void addElement(String ele) {
myModel.addElement(ele);
}
}
Same for your Display2 class. Then you can call the correct method on the JComboBox that is held by the correct view/display.
This way, when you swap displays, perhaps by using a CardLayout, you can clear the JComboBox in the display that is being shown by calling its own method to clear its own combobox's model.

GridLayout columns

I recently decided to start using GridLayout because FlowLayout seems somewhat amateur. However, I need help. The parameters when creating the GridLayout are (rows,columns,row space,column space). I have a variable for the row amount and 4 for the column amount, but when I try to add a JButton after everything else, there are 5 columns.
Here is my code:
byte i = 0;
while(i < main.componentNum)
{
comp[i] = new JLabel("component #" + (i+1));
box[i] = new JComboBox();
field[i] = new JTextField(5);
edit[i] = new JButton("edit");
comp[i].setBackground(Color.WHITE);
box[i].setBackground(Color.WHITE);
field[i].setBackground(Color.WHITE);
edit[i].setBackground(Color.WHITE);
add(comp[i]);
add(box[i]);
add(field[i]);
add(edit[i]);
i++;
}
When I run the above code, I get four columns and it works fine. But when I add a button to the end, I get five. Can anyone tell me how to give one button an entire row?
From the Java Docs
One, but not both, of rows and cols can be zero, which means that any
number of objects can be placed in a row or in a column.
Now, without your actual code the sets up the GridLayout, it's difficult to say, but, if your after maintaining only 4 columns, I would create a GridLayout as follows, new GridLayout(0, 4)
If you want something more flexible, look into GridBagLayout

Dispatching event for specific component only in java

I would like to customize JTableHeader so it would offer serval actions (for example 2 buttons which one of them would sort column and second show properties of this column etc). Unfortunately it is not possible to set CellEditor for JTableHeader so i'm stuck with using mouse adapter. But maybe it is possible to dispatch event from this particular JTableHeader component so it will show up a popup menu which will contains all options i desire and it would dispatch event if option other than sorting would be chosen. This way standard JTable sorting operation will be available, along with my operations and it will maintain a decent visual apperance. So my question is - Is it possible and how it should be done.
In response to trashgod comment - i understand that you mean to treat defaultheader as an ordinary component and just use "add" function to add Components. It doesnt work well with JTableHeader. After reading trashgod example i wrote this:
private class mouseList extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
TableColumnModel thisColumnModel = thisTable.getColumnModel();
int xCor = e.getX();
//int Cols = thisColumnModel.getColumnCount();
int thisColNum = thisColumnModel.getColumnIndexAtX(xCor);
int prevWidth=0;
for(int i = 0 ;i<thisColNum;i++)
{
prevWidth+=thisColumnModel.getColumn(i).getWidth();
}
int width = xCor-prevWidth;
/////////////////////////////////////////////////////////////////////////////////////
customHeader thisHeader = (customHeader)((JTableHeader)e.getSource()).getDefaultRenderer();
System.out.println(thisHeader.mainB.getText() + " text of thisHeader");
//////////////////////////////////////////////////
test thisTest = new test(null,false,thisHeader);
thisTest.setVisible(true);
///////////////////////////////////////////////////////////////
//System.out.println(width + " width of the header");
Object thisComp = thisHeader.getComponentAt(width, e.getY());
System.out.println(thisComp + "\n" + width + " + " + e.getY() +"\n" + thisHeader.getMainButton().getText());
((JTableHeader)e.getSource()).repaint();
if(thisComp instanceof JButton)
{
//System.out.println("sdfdsf");
String name = ((JButton)thisComp).getName();
if(name.equals("mainB"))
{
System.out.println("its working on main");
((JButton)thisComp).doClick(1000);
}else{
System.out.println("its working on menu");
((JButton)thisComp).doClick(1000);
}
}
((JTableHeader)e.getSource()).repaint();
}
}
MouseListener is applied to JTableHeader. HeaderRender is an extension of JPanel that contains 2 JButtons. Strange thing happens in line
Object thisComp = thisHeader.getComponentAt(width, e.getY());
When i left lines
test thisTest = new test(null,false,thisHeader);
thisTest.setVisible(true);
(This dialog shows selected component)
uncommented, function "getComponentAt" seems to work allmost fine (allmost because it never goes for else condition even when mouse is targeting second button, and it does not repaint clicked buttons[Strangely its repainting buttons in test dialog window]),otherwise it allways returns null object.
I dont know if it is important but i set Header renderer globally by invoking "setDefaultRenderer" on JTableHeader.
Im pretty much running out of ideas so i would appreciate any help.
This example shows the basic infrastructure, while this answer offers several important caveats regarding usability. This example shows how to change the RowFilter dynamically, but changing the RowSorter is similar. Both examples use JToggleButton to manage two states, but a JComboBox could be used to select from among more alternatives.

Categories

Resources