I have a very simple Java JTable question.
I am creating this class to make things easier in the rest of my application. I receive an error when running it. I know what the errors mean, but have no idea what else to try.
You'll see in the code what I am trying to accomplish:
My Class:
import javax.swing.*;
public class CPTable extends JScrollPane
{
private JTable table;
CPTable(Object [] headers, Object [][] data)
{
table = new JTable(data, headers);
this = new JScrollPane(table);//The line I can't figure out.
}
}
My errors: (an obvious one)
cannot assign a value to final variable this
this = new JScrollPane(table);
and
incompatible types
found : javax.swing.JScrollPane
required: CPTable
Try this:
private CPTable(JTable table) {
super(table);
this.table = table;
}
public CPTable(Object[] headers, Object[][] data) {
this(new JTable(data, headers));
}
You cannot reassign this, but you can cause the correct superclass constructor to be called by using super (which must be the first statement in your constructor).
The this statement is called "constructor delegation"---it chains through to the other constructor so that you can pass the table to the superclass as well as assign it to your table field.
Related
I am having trouble extending JComboBox. Mainly, I want to add a method that returns the selected Item into String. But since I might want to add more methods later on, I decided it would be better to create a child class.
import javax.swing.JComboBox;
public class ComboBox extends JComboBox{
public ComboBox(Integer[] items) {
super();
}
public ComboBox(String[] items) {
super();
}
public String getSelectedItemInString() {
return super.getSelectedItem().toString();
}
}
Above is my attempt but it wouldn't work this way. It would only create ComboBoxes that look like this, and I am not able to see the items even if I click on the drop down button result
I want to be able to create ComboBox that could take in both String[] or Integer[] in different instances.. just like how JComboBox allows to do this:
String [] groups = {null, "Zombies","Instigators","Fantastic Beasts","Stranger Things"};
JComboBox<String> groupSelector = new JComboBox<String>(groups);
totalNum = new JComboBox<Integer>();
totalNum.addItem(null);
totalNum.addItem(0); totalNum.addItem(1);
totalNum.addItem(2); totalNum.addItem(3);
totalNum.addItem(4);
The array that you are passing into the constructor of your ComboBox-class needs to be passed on to the constructor of the JComboBox.
public ComboBox(E[] items) {
super(items);
}
The reason your code is not throwing an error is because JComboBox also has another constructor which does not require any parameters (you are currently calling the constructor https://docs.oracle.com/javase/7/docs/api/javax/swing/JComboBox.html#JComboBox() but want to call https://docs.oracle.com/javase/7/docs/api/javax/swing/JComboBox.html#JComboBox(E[])). However, you want to call the constructor which takes an Array as the parameter. That's why you have to pass the parameter on to the super()-methid you're calling.
Why is the setVisible method throwing an error saying symbol not found in my showPanel method?
It does not make sense as I am referencing a JPanel stored in an ArrayList so it should be able to use setVisible.
public class mainFrame extends javax.swing.JFrame {
/**
* Creates new form mainFrame
*/
private ArrayList list;
public mainFrame() {
initComponents();
this.setSize(500,500);
int h=this.getHeight();
int w=this.getWidth();
homePanel homePnl = new homePanel();
this.add(homePnl);
homePnl.setLocation(0,0);
homePnl.setSize(w,h);
homePnl.setVisible(true);
DeploymentInfoPanel infoPanel = new DeploymentInfoPanel();
this.add(infoPanel);
infoPanel.setLocation(0,0);
infoPanel.setSize(w,h);
atomServerPanel atomPnl = new atomServerPanel();
this.add(atomPnl);
atomPnl.setLocation(0,0);
atomPnl.setSize(w,h);
autoDeploymentPanel autoPnl = new autoDeploymentPanel();
this.add(autoPnl);
autoPnl.setLocation(0,0);
autoPnl.setSize(w,h);
list = new ArrayList<>();
list.add(homePnl);
list.add(infoPanel);
list.add(atomPnl);
list.add(autoPnl);
this.pack();
}
public void showPanel(int panelNum){
list.get(1).setVisible(true);
}
private ArrayList list;
You didn't specify the type of Object that will be added to the ArrayList. So by default get() method will return an instance of Object. There is no setVisible(…) method for an Object
When you define the ArrayList you should be using:
private ArrayList<Component> list;
Now the compiler knows you are adding Component instances to the ArrayList.
In fact, the compiler will check to make sure you only add Component.
It will also get rid of the warning messages when you compile.
Also class names should start with an upper case character. Sometimes you do and sometimes you don't:
DeploymentInfoPanel infoPanel = new DeploymentInfoPanel();
...
atomServerPanel atomPnl = new atomServerPanel();
...
autoDeploymentPanel autoPnl = new autoDeploymentPanel();
Notice how the forum highlights properly named classes making the code easier to read?
Follow Java conventions and be consistent.
Finally, to display multiple panels in the same area of the frame you should be using a Card Layout.
I'm writing a small program that creates a gui to display the contents of a csv file. I've tried following the outline from the Oracle website (http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#data), but my problem is that the 'getColumnCount' method that is used to build the table can't access the 'headers' variable. Or more likely, it can, but the changes I thought I made to it in the main method did not connect to it. If anyone can shed some light on what's wrong and how to fix it, it'd be much appreciated.
public class MyTableModel implements TableModel {
private String[] headers; //This line.
private Object[][] tableData;
public static void main(String[] args) {
String fileName = "products.csv";
String[] csvList = readCSV(fileName);
String[] headers = Arrays.copyOfRange(csvList, 0, 10); //Or maybe this line isn't changing the one above.
}
private static String[] readCSV(String file) {
//Some code to fill the list.
return fileString;
}
#Override
public int getColumnCount() {
return headers.length; //<<This line of code
}
}
#Hovercraft Full Of Eels
Oh, I should have mentioned. I'm implementing this class like this, which is to say, I'm calling it from elsewhere.
private static void createGUI() {
csvTabler table = new csvTabler();
table.setTitle("CSV Table");
table.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table.createJTable();
table.pack();
table.setVisible(true);
}
private void createJTable() {
jTable = new JTable(new MyTableModel());
}
I'm sure this affects your solution but I'm not sure how to adjust..
String[] headers = Arrays.copyOfRange(csvList, 0, 10); //Or maybe this line isn't changing the one above.
Yep, that's it in a nutshell .... you're trying to change an instance field from a static method and are also shadowing the variable to boot, and that just won't work. Understand that the headers variable declared within the main method is local to this method -- visible only within the method -- and so changes to it will have absolutely no effect on the headers instance field in the class. Instead create a constructor and pass the header data in when you need to pass it into the class.
A bad idea is to make headers static -- just don't do this as this throws out the OOPs baby with the bathwater, essentially fixing your problem with a kludge rather than making a much cleaner more fundamental improvement to your program.
For example:
public class MyTableModel implements TableModel {
private String[] headers; //This line.
private Object[][] tableData;
public MyTableModel(String[] headers, Object[][] tableData) {
this.headers = headers;
this.tableData = tableData;
}
#Override
public int getColumnCount() {
return headers.length; //<<This line of code
}
public static void main(String[] args) {
String fileName = "products.csv";
String[] csvList = readCSV(fileName);
String[] headers = Arrays.copyOfRange(csvList, 0, 10);
Object[][] tableData = ..MyTableModel.. // code to create this
// now create a table model with your data and use it.
MyTableModel myTableModel = new MyTableModel(headers, tableData);
}
private static String[] readCSV(String file) {
String fileString = "";
//Some code to fill the list.
return fileString;
}
}
Other issues: You should almost never implement TableModel but rather extend either DefaultTableModel or AbstractTableModel. Otherwise your model will miss most of the necessary machinery to make it work.
Regarding:
What if I made the instance field static as well? But assuming that no such easy option exists. Do I do away with my main() method? I suspected that a constructor would be better, but the main method was helpful for testing at first, and I was getting a lot of errors with the constructor I tried to build.
Again, avoid statics as this increases connectedness of your code, its "coupling" without benefit which greatly increases your risk of hard to find bugs as your program grows.
Regarding, "do I do away with my main method" -- but of course your program will need a main method somewhere, so you already know the answer to this. The main method should be small and should serve only to set the pieces of the application in motion, and nothing more.
regarding "I suspected that a constructor would be better, but the main method was helpful for testing at first, and I was getting a lot of errors with the constructor I tried to build." -- a constructor is necessary, the main method and the constructor are no mutually exclusive, and as for errors -- fix them, one at a time.
I am trying to refresh my Jtable shown in the UI whenever I query the mysql database. The idea was to show whatever new data updated in the UI JTable.
The UI class is below.
public class DBView {
private JFrame frame = new JFrame();
private JScrollPane tableScrollPane = new JScrollPane();
private DefaultTableModel dbTable = new DefaultTableModel();
public void setDbTable(DefaultTableModel dbTable) {
this.dbTable = dbTable;
//this.dbTable.repaint();
paintDBTable();
}
public DefaultTableModel getDbTable() {
return dbTable;
}
public DBView() {
initializeFrame();
paintDBTable();
}
private void paintDBTable() {
tableScrollPane.setBounds(20, 350, 400, 80);
frame.getContentPane().add(tableScrollPane);
JTable DBTable = new JTable(dbTable);
tableScrollPane.add(DBTable);
DBTable.setFillsViewportHeight(true);
tableScrollPane.setViewportView(DBTable);
}
/**
* Initialize the contents of the frame.
*/
private void initializeFrame() {
frame.setVisible(true);
frame.setBounds(100, 100, 451, 525);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.setTitle("MySQL Database");
}
From another Model class I am calling the setDbTable() method. I input a new Jtable object to the setDbTable() method with data read from the database input into the new Jtable object.
The issue is inside the setDbTable() method, I am using paintDBTable() method again.
I tried using dbTable.fireTableDataChanged() method to refresh the view, didnt work.
The way it is now, it is working. But using the setDbTable() method to refresh seems like a very inefficient way to do it.
Question is Do you see anyway I could use another method defined for use of refreshing Jtables?
P.S. I am very new to java and programming in general. Sorry if the code is messy and the question is unclear. I can give all the code if its helpful. I removed most of the methods and other classes in the original code to make the question clearer.
tableScrollPane.add(DBTable);
JScrollPane isn't designated as container, you have to add child to JViewport
there are two options
a) tableScrollPane = new JScrollPane(myTable);
b) tableScrollPane.setViewportView(myTable);
DefaultTableModel dbTable = new DefaultTableModel();
DefaultTableModel is model that hold value for presentations layer for the JTable
rename this local variable (that make the sence) to dbTableModel instead of dbTable
you have to create a JTables view, f.e. two basics options
a) JTable myTable = new JTable(dbTableModel)
b) myTable.setModel(dbTableModel)
dbTable.fireTableDataChanged() is implemented in DefaultTableModel and correctly, not reason to call this method, nor outside of models definition (class, void, interface that returns XxxTableModel)
more informations in linked Oracle tutorials, ... for working code examples in SSCCE / MCVE form too
refresh data for JTable by
removing all rows in dbTableModel.setRowsCount(0);, then add a new row(s) to dbTableModel.addXxx
re_creating dbTableModel, note then must be added back to JTable e.g. myTable.setModel(dbTableModel)
It is not so confusing to refresh the JTable data and refreshing the UI after that, because:
Swing components implemented MVC and Observer in a very fantastic way. That means whenever you change the data in TableModel, the UI will be notified and repainted as you wanted.
So you should change you code in a way that you keep the JTable variable not the TableModel variable in your class. After that in setDbTable call the setModel method of the JTable, it means:
public class DBView {
private JTable jtable = new JTable();
public void setDbTable(DefaultTableModel dbTable) {
this.jtable.setModel(dbTable);
//this.dbTable.repaint();
//paintDBTable();
}
.
.
.
}
Hope this would be helpful,
Good Luck.
I am building my own GUI that will display a list of Friend's objects in list form. The first problem I ran into is that when I run the code without a constructor, everything works fine. But when I create a constructor for my GUI class, the error message displayed:
load: GUIapp.class is not public or has no public constructor.
java.lang.IllegalAccessException: Class sun.applet.AppletPanel can not access a member of class GUIapp with modifiers ""
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.Class.newInstance0(Class.java:349)
at java.lang.Class.newInstance(Class.java:308)
at sun.applet.AppletPanel.createApplet(AppletPanel.java:807)
at sun.applet.AppletPanel.runLoader(AppletPanel.java:714)
at sun.applet.AppletPanel.run(AppletPanel.java:368)
at java.lang.Thread.run(Thread.java:680)
My Code:
public class GUIapp extends JApplet{
/*
* Attributes
*/
//** Friends Objects**//
private FriendsGroup a;
private ArrayList<friends> friendList;
//** PANEL **//
private JPanel outerPanel;
//** Button **//
private JButton button1;
/*
* Constructor for Getting all the friends set up
*/
private GUIapp(){
a = null; //initialize variable
try {
a = new FriendsGroup("friends.txt"); //import friend list
} catch (IOException e) {
System.out.println("Fail Import.");
}
friendList = a.getFriendsGroup(); //return an arrayList of Friends Object
}
/*
* Create Stuff
*/
public void createStuff() {
outerPanel = new JPanel(); //create outer panel
button1 = new JButton("Click Me");
outerPanel.add(button1,BorderLayout.SOUTH);
}
/*
* Initialize Stuff
*
*/
public void init(){
createStuff(); //initialize create stuff
this.add (outerPanel);
}
}
In the Above Code, if you take out the constructor, it seems to work perfectly. My Question is, what is wrong with the code? Why can't I seem to create a constructor to load in data first?
My Second Question is how would I go about create a panel whereby it displays a list of friends names? Theses names are imported and stored in the arraylist of friends Object called friendList stored in the constructor.
Thanks,
when you are defining a constructor by yourself
compiler will not create the default constructor
since your defined constructor is private
you will not have a public constructor
so simply create a public constructor
public GUIapp(){
// your code
}
because you define constructor private change it to;
public GUIapp(){
a = null; //initialize variable
try {
a = new FriendsGroup("friends.txt"); //import friend list
} catch (IOException e) {
System.out.println("Fail Import.");
}
friendList = a.getFriendsGroup(); //return an arrayList of Friends Object
}
The problem is this: private GUIapp(){. That means that your constructor is available only to that class. Usually constructors are public, although there do exist exceptions, example of which could be the Singleton Pattern.
Removing the constructor works because each class, by default has a parameterless constructor. Take a look at this tutorial for more information on access modifiers.
Alternatively, you could have a method like so in your GUIapp class:
public static GUIapp getInstance() { return new GUIapp(); }
and you call that from your main class, but I think that in this case, changing your constructor from private to public should be enough.
Regarding your second question, this tutorial should be of help.
You ened to change syour constructor to public and debug into:
a.getFriendsGroup();
Its not clear what this methode does, and i assume for some reason (maby the list from the file is empt) the methode tries to access a non assigned object which causes null reference exception, try to debug into the methode to see where this happends or post the code of the methode.