I am working with a JTable That schould display Some informations sorted By the last two columns. The problem is the last two columns are filled with strings, one of them are Days of the Weak(Monday-Friday) the others are Hours(HH:mm), i would like to sort them going from Monday-Friday and if there are more elements of the same Day they schould be sorted by the Erliest Hour. Until now google was not a realy big help since it schows only ways to sorte something Alphabetically ore in Ascendant/descendant order for numbers, but i dont need an Alphabetically ordered JTable. Does anyone have an idea?
public class ScheduleFrame extends JFrame {
private JPanel contentPane;
private static JTable table;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScheduleFrame frame = new ScheduleFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
* #throws Exception
*/
public ScheduleFrame(){
setTitle("Schedule");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 627, 405);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
table = new JTable();
scrollPane.setViewportView(table);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
table.setModel(new DefaultTableModel(
new Object[][] {
},
new String[] {
"Course Name", "Course Room","Course Day", "Course Hour"
}
));}
public static void loadTable()throws Exception{
DefaultTableModel tm = (DefaultTableModel) table.getModel();
BufferedReader bfw = new BufferedReader(new FileReader("Schedulecourses.txt"));
String line;
while( (line = bfw.readLine() ) != null ) {
tm.addRow( line.split("\t") );
}
bfw.close();
}
}
This is how it schould look like
one of them are Days of the Weak(Monday-Friday)
So the data in the TableModel could be stored as an Integer to represent the day of the week. Then you use a custom renderer to convert the Integer value to a descriptive value.
Read the section from the Swing tutorial on Using Custom Renderers for an example.
In your case the code in the setValue(...) method would be something like:
int dayOfWeek = (Integer)value;
switch (dayOfWeek)
{
case 1: setText("Monday"); break;
case 2: setText("Tuesday"); break;
case 3: ...
default: value.toString();
}
the others are Hours(HH:mm),
In this case you are storing two pieces of information. So this means you need to parse the data into two times and then create a custom Comparator to sort based on the first time.
Another option might be to create two columns: "Start Time", "End Time". Then you could store Date objects in the TableModel and then just use the default Comparator that will sort by Date.
Simply implement it yourself. Use some basic sorting algorithm, like quick sort, bubble sort or merge sort (as found on wikipedia), and create your own comparison function to put the entries in order, like, in pseudo code:
bool is_smaller(entry_1, entry_2){
if (entry_1.weekday < entry_2.weekday) return true;
if (entry_1.weekday > entry_2.weekday) return false;
if (entry_1.course hour < entry_2.course_hour) return true;
if (entry_1.course hour > entry_2.course_hour) return false;
return false;
}
(of course with another comparison function for weekday and course hour)
I suggest you try and map the data that you read from the file to some kind of a model object that you can later sort. For example:
public class Course implements Comparable<Course> {
private String name;
private String room;
private String day;
private String hour;
// constructor and getters are omitted. you can add setters as well, but it's best that you keep this class immutable
#Override
public int compareTo(Course course) {
// here you implement the logic of your comparison
}
}
The benefit here is that, by implementing the Comparable<T> interface provided by the Java API, you specify that the instances of your Course class have a natural ordering. Then you can use Collections.sort() and your list of courses will be automatically sorted in the way you want. Then you can use it to back your table model and render it in the table.
Edit 1:
A bit of a clarification on my suggestion:
Right now you read text data from a file, transform each row into an array of strings and pass it to a DefaultTableModel that supplies data to your JTable.
Instead of doing this, you can a bit more complexity to the code, but end up with a better solution from an architectural point of view. What are the steps:
Define a model class (like the example Course class) that will hold the data that is saved in your text file. Implement logic to transform each row of the file into an instance of the Course class. This instances will represent your data and you will use them to populate your table with data.
Implement your own TableModel that holds a sorted list of Course instances (those are the instances you read from the file). Use the implemented model to supply data to your JTable.
Related
I can't figure this out (have been trying to fix this for the past 2-3 hours).
I would like to display the contents of an arraylist, but they do not appear in the table and also there are NO errors, they simply do not appear. Here is my code:
private class examinations{
private int id;
private int candidate_id;
private String date;
private String exam;
private String examNumber;
public examinations(int id, int student_id, String date, String exam, String examNumber) {
this.id = id;
this.student_id = student_id;
this.date = date;
this.exam= exam;
this.examNumber= examNumber;
}
public ArrayList ListExams(){
ArrayList<exams> list = new ArrayList<exams>();
return list;
}
public void addRollToTable(){
DefaultTableModel model = (DefaultTableModel)tableExams.getModel();
ArrayList<exams> list = ListExams();
Object rowData[] = new Object[5];
for(int i = 0; i < list.size(); i++) {
rowData[0] = list.get(i).id;
rowData[1] = list.get(i).student_id;
rowData[2] = list.get(i).date;
rowData[3] = list.get(i).exam;
rowData[4] = list.get(i).examNumber;
model.addRow(rowData);
}
}
}
I tested this loop and the variables coming out of the other list are there, so a System.out.println(list.get(i).exam); will display the correct thing i typed. However the table will NOT display whatever I add in the rowData. It gives, again, no errors. Let me show you the DefaultTableModel code. This code is in the private void initComponents() of my class...
Object [][] data = {};
String[] columnNames = {"Id", "Student_Id", "Date", "Exam",
"Exam_number"};
tableExams= new javax.swing.JTable();
DefaultTableModel model = new DefaultTableModel(data, columnNames);
tableExams.setModel(model);
tableExams.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR));
jScrollPane4.setViewportView(tableExams);
I've been reading this: DefaultTableModel Class Overview But I still can't find where I am going wrong... Could anyone give a tip?
First of all learn and use Java naming conventions:
Classs names SHOULD start with an upper case character. Can you show me a class in the JDK that does not?
Method should should NOT start with an upper case character. Again, can you show me a method in the JDK the does?
Learn by example and don't make up your own conventions.
so a System.out.println(list.get(i).exam); will display the correct thing i typed
I don't know how this is possible. Your code is as follows:
a) First, you retrieve the ArrayList from the "listExams() method.
ArrayList<exams> list = ListExams();
b) But in the "listExams()" method all you do is create an empty ArrayList.
ArrayList<exams> list = new ArrayList<exams>();
So you are missing the logic that actually adds data to the ArrayList.
Based on the logic provided, you don't even need the ArrayList. Just take the data from the Examination class and add it to the TableModel:
Object rowData[] = new Object[5];
rowData[0] = id;
rowData[1] = student_id;
rowData[2] = date;
rowData[3] = exam;
rowData[4] = examNumber;
model.addRow(rowData);
For a different solution you could create a custom TableModel to hold your "Examination" objects. Check out Row Table Model for a step-by-step example of how this can be done.
OK, I solved it, even though this was just a work around, I'd accept it.
All I did was use this.setVisible(false) and then entered the information in the other JFrame. Clicking add, i make an object of the first JFrame, passed all the variables, used this.dispose() and then called .setVisible(true) to return to the table, which displayed the information. LOL that was a long testing and re-writing of code to actually realize it was something that small...
I am sorry, I did not know where the actual problem was, and yeah thanks a lot for that simple suggestion there camickr. I tried it in the same JFrame and it worked, then I tried it between 2 JFrames and I realized the JFrame with the table DID NOT update the table. repaint() also didn't work. You quite literally helped me out with that small tip, which is all i needed. THANKS!!!!!!
I have a JComboBox that I made this way, using an enum for its values:
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
The enum looks like this:
public enum StudyGrade {
ELEMENTARY ("Primaria"),
MIDDLE ("Secundaria"),
MIDDLE_HIGH ("Preparatoria"),
HIGH ("Universidad"),
MASTERS ("Maestría / Posgrado"),
DOCTORATE ("Doctorado"),
POST_DOCTORATE ("Post Doctorado");
private String studies;
private StudyGrade(String studies) {
this.studies = studies;
}
public String getStudies() {
return studies;
}
public void setStudies(String studies) {
this.studies = studies;
}
#Override
public String toString() {
return studies;
}
}
As you can see I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
However I want to show the studies values only in the JComboBox not everytime I use the StudyGrade enum.
How would I change the code, so whenever I use something like:
System.out.println(StudyGrade.HIGH);
I get printed HIGH instead of Universidad, but not for the JComboBox?
I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
I've never used a enum before but I assume you can use it like any custom object added to the combo box so you should be able to use a custom renderer so you can control which data is displayed by the combo box.
Check out Combo Box With Custom Renderer for more information and a helper class.
You're looking to extend an enum, but that's impossible. It means that something is wrong with your requirement.
Rendering is done in the UI component, and it's not enum's business to deal with presentation of data. You should make you UI component render enum the way you'd like instead of trying to make enum understand where it's being used. Since you're a Swing fanatic you should know how to do that, something like this:
maxLevelOfStudiesCombo.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> jList, Object o, int i, boolean b, boolean b1) {
Component rendererComponent = super.getListCellRendererComponent(jList, o, i, b, b1);
setText(o instanceof StudyGrade ? ((StudyGrade) o).getStudies() : o.toString());
return rendererComponent;
}
});
That's going to do that.
You could just remove the toString override as the default toString for an enum is to return the name of the enum element.
And you could just have a simple for loop that would iterate through the values in your enums and add it to a string array. Then, you would need to pass that array as the argument for your JComboBox and it should be gold.
The code for it should look a bit like that:
//get all study grades
StudyGrade[] temp = StudyGrade.values();
//create a string array of same length as the array
String[] str = new String[temp.length];
//append all the studies value to the string array
for(int i = 0; i< temp.length; i++){
str[i] = temp[i].getStudies();
System.out.println(temp[i]);//debug
}
System.out.println("---------------------");//debug
for(String s : str){//debug
System.out.println(s);//debug
}//debug
//pass it
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
Here is an example I made on repl.it
https://repl.it/GH28/1
I have a function called FetchInbox() which fetches the header information (Sender, subject, date sent) of an email and then adds it to a Vector of String Vectors.
What I want to be able to do is to refresh this table as new emails come in and update the table by first running FetchInbox() again, and then using this to repopulate the table.
I know this can be done using a TableModel, but I have yet to find a example which uses Vectors and not Object[][]. Any assistance with this would be appreciated.
DefaultTableModel has constructors and methods that take Vectors instead of Object[]s.
The old version of DefaultTableModel only used Vectors, the Object[] parameters are newer methods that were added around the time Generics came to Java.
http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
When you create a table without providing it a model, it will have DefaultTableModel as it's default model. This model has two function:
setDataVector(Vector dataVector, Vector columnIdentifiers): Where dataVector is a Vector(which represents the data rows of table) of Vector and comlumnIdentifiers is Vector containing identifiers. It will show your table as you are providing the Vector.
addRow(Vector dataRow): it will add a data row to your dataVector as defined above.
So it is really simple to get the model and invoke these function:
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setDataVector(dataVector, comlnIdentifiers);
In your context, dataVector has the type vector<vector<string> >. But depending on Vector is not really a good choice. It is much safer and effective if your directly work with Object[]. The DefaultTableModel has similar function with Object array too.
setDataVector(Object[][] dataVector, Object[] columnIdentifiers)
addRow(Object[] rowData)
Check out the Tutorial page: How to Use Table to know many more things you can do with table and it's model.
This should work, but #jzd's answer is probably what you want, with the caveat that, according to the documentation, the column Vectors might be truncated or padded if their length does not match the number of columns you want in your table.
import javax.swing.*;
import javax.swing.table.*;
import java.util.*;
class test{
public static void main(String[] _) {
// Test data.
final Vector<Vector<String>> rows = new Vector<Vector<String>>();
for (int i = 0; i < 4; i++) {
Vector<String> row = new Vector<String>();
for (int j = 0; j < 5; j++) {
row.add(String.format("%s, %s", i, j));
}
rows.add(row);
}
// With AbstractTableModel, you only need to implement three methods.
TableModel model = new AbstractTableModel() {
public int getRowCount() {
return rows.size();
}
public int getColumnCount() {
return rows.elementAt(0).size();
}
public Object getValueAt(int row, int column) {
return rows.elementAt(row).elementAt(column);
}
};
// Test the TableModel in a JTable.
JFrame jf = new JFrame("test");
jf.setSize(512, 384);
jf.setContentPane(new JScrollPane(new JTable(model)));
jf.show();
}
}
have a look at GlazedLists - it'll save you a ton of time.
with it you can dynamically bind a JTable to a List of objects such that any change in the objects is reflected in the table and vice-versa.
I would like to create visualization of database. It's a full-desktop application, and it looks similar to Excel. When i put into my JTable database visualization 100 rows, each one with 6 columns, the application is crushing down. Is there a better class for such a task? Or some other smarter way?
Thats the way i do it:
import PodklasyInterfejsu.Menu;
import javax.swing.*;
import java.awt.*;
public class OknoGlowne extends JFrame
{
public Okno()
{
// ustawienie rozmiaru okna na 100%
JFrame Okno = new JFrame();
Okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Okno.setTitle("Archiwum Stomatologiczne");
Toolkit zestaw = Toolkit.getDefaultToolkit();
Dimension rozmiarEkranu = zestaw.getScreenSize();
int wysEkranu = rozmiarEkranu.height;
int szerEkranu = rozmiarEkranu.width;
Okno.setSize(szerEkranu, wysEkranu - 60);
Container powZawartosci = getContentPane();
// Panel Górnego Menu:
Menu GorneMenu = new Menu();
Okno.setJMenuBar(GorneMenu);
// Wizualizacja bazy w tabeli:
JTable tabela = new JTable(komorki, nazwyKolumn);
tabela.setAutoCreateRowSorter(true);
Okno.add(new JScrollPane(tabela), BorderLayout.CENTER);
Okno.setVisible(true);
}
private Object[][] komorki = new Object [10][];
private String[] nazwyKolumn = {"Nazwisko", "Imię", "Pesel", "Płeć", "Data urodzenia", "Adres", "Kontakt"};
}
One problem in the code above is that your data 2-d Object[10][] array, komorki, doesn't match your column String[] array, nazwyKolumn. You have 7 columns and need 7 as the first array index for your Object array. Consider changing this:
private Object[][] komorki = new Object[10][];
private String[] nazwyKolumn = { "Nazwisko", "Imię", "Pesel", "Płeć",
"Data urodzenia", "Adres", "Kontakt" };
to this:
// !! private Object[][] komorki = new Object[10][];
private Object[][] komorki = new Object[10][7]; //!!
private String[] nazwyKolumn = { "Nazwisko", "Imię", "Pesel", "Płeć",
"Data urodzenia", "Adres", "Kontakt" };
for starters.
As mentioned by others: have you tried profiling ? I personally have good experiences with JProfiler.
Although we do not yet know whether the JTable is the actual problem, I had performance problems with JXTables (note: the SwingX version of JTable) in combination with large TableModels where the table would iterate over all elements to determine the column size before painting it.
This was solved by setting a prototype value for each column (using TableColumnExt#setPrototypeValue). I am not sure whether a regular JTable contains this logic as well, but it might be worth a try to replace your JTable by a JXTable and set the prototype.
1) In the following method (actionListener) a user select a grade (e.g. A-F) from a JComboBox.
2) There are multiple JComboBoxes, and each selection made gets stored into a single String[] array.
PROBLEM:
Here is the dilemma, if a user goes back and changes a selection made from a random JComboBox the previous grade selection does not get replaced in the array, however the new selection made gets stored at the next array index.
How can I make the program replace the previous grade selection and not just add the new selection?
relevant variables:
int counter;
private JComboBox[] gradeField;
//grade.userGrades[] is array of grades taken from selected combo boxes
Action Listener anonymous class:
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[grade.getNext()] = theGrade;
grade.updateNext();
}
});
Thanks in advance for any help.
I save the grade in an array and increment the index,
Well you should not be incrementing the index. This assumes that the user selects the grades from the combo box in a sequential order. As you have discovered users can often work randomly.
Instead you need to know which combo box has been changed and then update the appropriate entry in your array.
Or a different solution might be to update your array at the end. So maybe you have a "Process Results" button. Then you can sequentually loop through all the combo boxes to get the selected value.
Update the user grade being at the same index as the combo box:
final int index = counter;
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
});
Here's another variation of JB Nizet's answer:
class OuterClass
{
...
gradeField[counter].addActionListener( new GradeSettingActionListener( counter ) );
...
class GradeSettingActionListener implements ActionListener
{
// -- Doesn't have to be final here (it does in JB's answer), but I like to be restrictive.
private final int index;
public GradeSettingActionListener( int index )
{
this.index = index;
}
#Override
public void actionPerformed( ActionEvent e )
{
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox) holder;
String theGrade = (String) tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
}
}
This approach removes the anonymous class by adding an inner class. The inner class will still have access to grade. You don't gain much here unless there's a chance you'll be splitting out the inner class later.
Of course, camickr's suggestion to process all the grades at once may also be valid, depending on other requirements (i.e., whether additional processing is done after the grades are stored in the array, which seems likely).