Updating jTable - passing jTable as a parameter - java

I have a method in class A and I want class B (Main GUI) to call that method, but class A needs to perform some action on a jTable within class B.
I do not want this method to be within class B as it needs a connection to the db and I don't want my GUI to hold any such methods.
Here is the code within class A:
public void populatejTable(TableModel x) {
try {
String stmt = "SELECT * FROM APP.DATAVAULT";
PreparedStatement ps = Main.getPreparedStatement(stmt);
ResultSet rs = ps.executeQuery();
x.setModel(DbUtils.resultSetToTableModel(rs));
ps.close();
rs.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
I need to pass a parameter of type jTable to set it's model. I've tried all different common data types such as String, int etc... and even tried jTable and TableModel.
I'm guessing you're not really supposed to do this, but I cannot see a better way around this?
Here is the code calling this method within class B (my GUI):
//table
Account acc = new Account();
acc.populatejTable(datavaultjTable);
How should I go about doing this?
I am using Netbeans 7.3 Beta 2 GUI builder to create the table and the GUI - writing in Java on OS X.

The code in class A doesn't compile. There is no setModel() method in TableModel. Your goal of not having database-related code in a GUI class is a good one, but if it leads to GUI code in database-related code, the result is even worse.
The GUI class should contain GUI code only. The data access code should contain database-related code only. The GUI should call methods on the database access code to get data. It should not pass JTable instances or even TableModel instances to the data access code:
public class GUI {
private JTable table;
private MyTableModel tableModel;
private DataAccess dataAccess;
...
public void fillTableWithDataFromDatabase() {
List<Product> products = dataAccess.getProductsFromDatabase();
tableModel.setProducts(products);
}
}
public class DataAccess {
public List<Product> getProductsFromDatabase() {
// TODO:
// create an empty list
// execute a query
// loop through each row
// for each row, create a Product instance and add it to a list
// return the list
}
}

Related

Extending JComboBox

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.

Making a program using a GUI and MySQL database

i have a question regarding a program i am working on. It`s a database manager for a MqSQL db , written in Java. So i have the following program structure.
So i have a main class that extends JFrame, whichh is the main frame of the interface, like this (removed the unecessary code not relevant to the discussion) :
public class MainInterface extends JFrame {
public MainInterface {
................
MainInterface.setLayout(new FlowLayout());
MainInterface.setVisible(true);
TopToolbar toolbar;
try {
toolbar = new TopToolbar();
MainInterface.add(toolbar);
ResultsPanel Results = new ResultsPanel();
MainInterface.add(Results);
} catch (IOException e) {
e.printStackTrace();
}
}
TopToolbar and ResultsPanel are 2 other classes that extend JPanel, the TopToolbar class having a JToolBar with buttonsadded to it (Move Forward, MoveBack, Add entry)
public class TopToolbar extends JPanel implements ActionListener {
TopToolBar()
{
//constructor in which i was adding button to the toolbar, not relevat
}
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (MoveFirst.equals(cmd)){
try {
DatabaseAccess disp = new DatabaseAccess();
disp.getResults();
int id = disp.return_id();
System.out.println(id);
} catch (//exceptions) {
e1.printStackTrace();
}
}
That is the ActionListener event for the next button, which should trigger reading the next entry in the db
DatabaseAccess is another class with initializes the DB connection , and has these 2 methods :
public void getResults() throws SQLException {
Connection con = (Connection) DriverManager.getConnection(URL, user, "")
sql = (Statement) con.createStatement();
result_set = sql.executeQuery("select * from persons");
while (result_set.next()) {
id = result_set.getInt(1);
name = result_set.getString(2);
}
}
public int return_id(){
return id;
}
The return_ID method returns (and it does work) the ID (first key in the database, will obviously add methods for the rest of the entries in the db).
Now i want to show the ID in the final JPanel, the one called ResultsSet (just 3 JLabels and 3 TextFields for the ID , Name etc., in a GridLayout).
Since the dababase class creation (and subsequently the methods forr reading the db and returning the result) is done inside the ActionPerformed method inside the TopToolBar Jpanel, i can`t access it from the MainInterface JFrame and then use something like
ResultsPanel DispResults = new ResultsPanel();
add(DispResults);
DispResults.setID(id_Value)
where setID would be a method in the ResultsPanel that uses the JTextBox setText to set the text .
Hoope i`ve managed to explain my issue as clear as i can.
I disagree with several of your choices.
You should not extend JFrame. Create a JPanel and give it to a JFrame to display.
I would dissociate the database interactions from the Swing UI. Create them as interface-based POJOs on their own, without a UI. Get them tested, written, and working perfectly.
Once the database interactions are perfect, give an instance of that object to the class that controls the application. Give it a text-only interface for driving the database actions.
Once the controller is obeying every text command perfectly, using your fully tested database component, then have it create an instance of your JPanel and give it to a JFrame. It will make the same calls to its controller owner that your text UI has already executed successfully.
Computer science is all about decomposition. You solve big problems by breaking them into smaller ones.
If you'd like to see a great example of what your app might look like, download SQL Squirrel.

Java Class Constructor Error

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.

relations between classes

I'm having a difficults to add rows to a table that located in different class.
Following are the classes structure:
The dashed arrow is the desired relation that I dont manage to have
in the AddPanel class I have a fileds and Addbutton.
when clicking the addButton I first creating an instance of Product (class located in Logic Package). Then I need to add row to the table (Using the TableModel.AddRow method).
Following are the GUI Looks (the focused tab is AddPannel):
I tried different approches but non of them were successed.
My last attempt was to create in the Table class the following method:
public void AddRow(Product p) {
tbmStock.addRow(new Object[] { p.getExternalId(), p.getName(),
p.getAmount(), p.getPriceForMe(), p.getPriceForCustomer() });
}
In addition, in the AddPanel class I tried to add the following method:
private void AddButtonAction() {
btnAddProduct.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
Product p = new Product(txtName.getText(), txtExternalID
.getText(), Integer.parseInt(txtAmount.getText()),
Double.parseDouble(txtPriceForMe.getText()),
Double.parseDouble(txtPriceForCustomer.getText()),
Integer.parseInt(txtFromYear.getText()), Integer
.parseInt(txtToYear.getText()), Integer
.parseInt(txtSupplier.getText()), Integer
.parseInt(txtCarType.getText()));
AddRow(p); //This call doesn't compiles
}
catch (Exception e1){
JOptionPane.showMessageDialog(null,"Error");
}
}
});
}
Any suggestions ? (actually I'm not sure even that my structure is good :S )
Provide a custom event and event listener. If you create a new product fire the event and notify all listeners. The MainPanel (assuming that's where you create the instance of AddPanel), should register a listener. In this listener you then can update the table as the MainPanel has access to the table.
This is also known as the Mediator pattern.
Some pointers:
Create an event class, e.g. ProductCreatedEvent extends EventObject. Pass the Product as an argument to the constructor and make it accessible with a getter.
Create an event listener class: interface ProductCreatedEventListener extends EventListener. Provide a method such as productCreated(ProductCreatedEvent productCreatedEvent).
In the AddPanel add something like:
private final List<ProductCreatedEventListener> productCreatedEventListeners = new ArrayList<>();
...
public void addProductCreatedEventListener(ProductCreatedEventListener productCreatedEventListener){
productCreatedEventListeners.add(productCreatedEventListener);
}
public void removeProductCreatedEventListener(ProductCreatedEventListener productCreatedEventListener){
productCreatedEventListeners.remove(productCreatedEventListener);
}
private void fireProductCreatedEvent(ProductCreatedEvent event){
for (ProductCreatedEventListener productCreatedEventListener : productCreatedEventListeners){
productCreatedEventListener.productCreated(event);
}
}
Replace:
AddRow(p); //This isn't working
with
fireProductCreatedEvent(new ProductCreatedEvent(AddPanel.this, p));

Possible thread issue?

I have 2 classes, one class is a datamodel class and the other is a gui class.
class datamodel .........
Takes user selected data and creates a arraylist
class gui .........
Has a tableviewer that is using the array from the datamodel class
My issue is I need to fresh the tableviewer when the user has added more data to the array.
I created a updateTableViewer method in the gui class.
public void updateTableViewer() {
if(getViewer() != null) {
viewer.refresh();
{
Then I made a reference to the gui class in the datamodel class.
AplotBaseDialog abd = new AplotBaseDialog(null, null);
Then I added the method call to the method adding more data to the array
public void add(TCComponentItemRevision tcRevision, TCComponentDataset selectedDataset) {
AplotDatasetData pp = new AplotDatasetData(tcRevision, selectedDataset);
if (!dataArrayList.contains(pp)) {
dataArrayList.add(pp);
}
abd.updateTableViewer();
}// end add()
This does not work. The getViewer() call always returns null, even if the gui class is created and open.
So I create a boolean value;
Boolean hasViewerBeenCreated = false;
I am setting the value to true after the tableviewer is created.
viewer = new AplotDataTableViewer(parent, SWT.BORDER|SWT.V_SCROLL|SWT.FULL_SELECTION);
viewer.setInput(AplotDataModel.getInstance().getArrayData());
hasViewerBeenCreated = true;
Then I created a method to return the boolean value.
I am calling the method from a button on the dailog.
I also replaced the updateTableViewer method call in the datamodel class
if (!dataArrayList.contains(pp)) {
dataArrayList.add(pp);
}
abd.getBooleanValue();
}
Here are the results.
I execute the add method in the datamodel class -
It returns false - That makes sense because the dailog has not been created at this time
I execute and create the gui class
I click the button and it returns true - This makes sense because the viewer has been created
Here is where I get confused.
With the gui still open, I can execute the add method again and it stills returns a false value. Then I can click the button and see it is true value.
I would think that when the gui is created and the boolean value is set to true. I would be able to get the current value of the boolean in other classes.
I am not sure if I am not referencing the gui class correctly or when the gui is created I am not accessing the current thread or tableviewer?
I don't know if this is a thread issue or I am just not getting the current value from the gui correctly.
This is a big issue with my application right now. I have to be able to refresh the tableviewer any time new data is added to the array. I can not have the user having to manually refresh the table every time that select new data

Categories