I've just come over to JAVA from BASIC, so please forgive me for any convention issues with my coding.
I have a mildly infuritating GUI-related issue. I have constructed a matrix-multiplication calculator which does calculations on inputted letters (using MOD 26). I run the program exclusively on Eclipse and have included a picture of the actual program in operation below...
The issue is with the Jtextfield boxes which take the inputted letters:
Actual program running on Eclipse
Basically, I wanted to be able to input a letter in a box, then to have the cursor move to the next box (cycling back to the first box after all the letters are inputted). I used a 'KeyListener' as shown in the code for the first JTextField 'letter box':
A_RUCE = new JTextField(2);
A_RUCE.setFont(new Font("Serif", Font.PLAIN, 18));
A_RUCE.setEditable(true);
cp.add(A_RUCE);
A_RUCE.setText("");
A_RUCE.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
String value=A_RUCE.getText();
if(value.length()==0){
B_RUCE.requestFocus();
}
}
});
The problem is that when I run the program, most of the time, the thing becomes "over sensitive". I try to input a letter and the cursor skips a box. I consider key repeating rate on my computer and such, and have adjusted settings, but this did not help.
All I am seeking is for when a letter is inputted, that the cursor moves to the next box without it 'skipping' over a box. I don't know why that happens, and I cannot figure out an alternative way to fix the issue. I would be very grateful if someone could help with this. Thank you kindly.
I'd be more inclined to use a DocumentListener. You can check the length of the text and then move onto the next field. This is the sort of thing you could do:
import java.awt.Component;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.EventQueue;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
public class FB extends JFrame implements DocumentListener {
private JTextField[] fields = new JTextField[3];
public void insertUpdate(DocumentEvent e) {
int textLen = e.getDocument().getLength();
if (textLen == 1) {
// focus next
int nextToFocus = 0;
Component c = getFocusOwner();
for (int i = 0; i < fields.length; i++) {
if (fields[i] == c) {
nextToFocus = i + 1;
break;
}
}
nextToFocus %= fields.length;
System.out.printf("Next to focus is field %d%n", nextToFocus);
fields[nextToFocus].requestFocus();
}
}
public void removeUpdate(DocumentEvent e) {
} // No-op
public void changedUpdate(DocumentEvent e) {
// No-op
}
private void setGui() {
try {
setLocation(0, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
JPanel fieldsPanel = new JPanel();
for (int i = 0; i < fields.length; i++) {
JTextField tf = new JTextField(1);
tf.getDocument().addDocumentListener(this);
fieldsPanel.add(tf);
fields[i] = tf;
}
setContentPane(fieldsPanel);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
EventQueue.invokeAndWait(() -> {
FB f = new FB();
f.setGui();
f.setSize(200, 200);
f.setVisible(true);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
I have a table. If I right-click I got a JPopUpMenu but before the pop-up I want to select the row where the right-click event is done. Here is what I've tried.
path_tbl.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println(e.getPoint());
Point point = e.getPoint();
int selectedRow = path_tbl.rowAtPoint(point);
path_tbl.setRowSelectionInterval(selectedRow, selectedRow);
}
});
In that event, I cannot get any output from the console when I right-click. However, when I left-click, points are printed to the console.
java.awt.Point[x=105,y=76]
So, this event only works when I left-click. How can I make this event work with right-click?
Since you want custom mouse behavior, you should not use setComponentPopupMenu.
Instead, display the JPopupMenu yourself, using JPopupMenu’s show method:
JPopupMenu menu = /* ... */;
path_tbl.addMouseListener(new MouseAdapter() {
private void showPopupMenuFor(MouseEvent e) {
if (menu.isPopupTrigger(e)) {
Point point = e.getPoint();
int row = path_tbl.rowAtPoint(point);
if (!path_tbl.isRowSelected(row)) {
path_tbl.setRowSelectionInterval(row, row);
}
menu.show(path_tbl, e.getX(), e.getY());
}
}
#Override
public void mousePressed(MouseEvent e) {
showPopupMenuFor(e);
}
#Override
public void mouseReleased(MouseEvent e) {
showPopupMenuFor(e);
}
#Override
public void mouseClicked(MouseEvent e) {
showPopupMenuFor(e);
}
});
You must check the MouseEvent in both mousePressed and mouseReleased, because exactly when a context menu is triggered depends on the platform and the look-and-feel. (Checking in mouseClicked may or may not be necessary, but it doesn’t hurt.)
In most cases, I'm lazy, so if I don't need to do something, then I'd prefer not to. In this case, I'd prefer to make use of the existing API works as much as possible, meaning, make use of JComponent#setComponentPopupMenu, as it will take care of the "how" and "when" the popup should be shown, based on the current platform.
However, as you have discovered, by default, JTable will NOT select the row when the user presses the "right" mouse button, for that, you could just continue with your current workflow, but, checking to see if the MouseEvent is actually a "right" click.
Lucky for us, some of the original Swing developers were also "lazy" and they provided us with SwingUtilities.isRightMouseButton, yea 🎉
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
DefaultTableModel model = new DefaultTableModel(0, 10);
for (int row = 0; row < 10; row++) {
Vector data = new Vector(10);
for (int col = 0; col < 10; col++) {
String value = row + "x" + ((char) (col + 'A'));
data.add(value);
}
model.addRow(data);
}
JPopupMenu menu = new JPopupMenu();
menu.add("Hello");
menu.add("This looks interesting");
menu.add("I like bi-planes");
JTable table = new JTable(model);
table.setComponentPopupMenu(menu);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
Point point = e.getPoint();
int row = table.rowAtPoint(point);
if (!table.isRowSelected(row)) {
table.setRowSelectionInterval(row, row);
}
}
}
});
add(new JScrollPane(table));
}
}
}
I am trying to change the background colour of a number field based on the numbers that are typed in. Just like a number field turns red when you type a letter in it. I want it to also change red when you type numbers below 1 and above 7.
I understand that you can do this with a button, but I want it to change when you're typing.
This is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class applet03 extends JApplet {
private JButton bHoeveelheid = new JButton();
private JNumberField nfAantal = new JNumberField();
private JTextArea taLijst = new JTextArea("");
private JScrollPane taLijstScrollPane = new JScrollPane(taLijst);
public void init() {
Container cp = getContentPane();
cp.setLayout(null);
cp.setBounds(0, 0, 442, 478);
bHoeveelheid.setBounds(224, 56, 59, 33);
bHoeveelheid.setMargin(new Insets(2, 2, 2, 2));
bHoeveelheid.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
bHoeveelheid_ActionPerformed(evt);
}
});
cp.add(bHoeveelheid);
nfAantal.setBounds(304, 56, 99, 36);
nfAantal.setText("Vul getal in");
nfAantal.setHorizontalAlignment(SwingConstants.CENTER);
nfAantal.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
nfAantal_FocusGained(evt);
}
});
nfAantal.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
nfAantal_KeyPressed(evt);
}
});
cp.add(nfAantal);
taLijstScrollPane.setBounds(224, 136, 168, 180);
cp.add(taLijstScrollPane);
}
public void bHoeveelheid_ActionPerformed(ActionEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
public void nfAantal_FocusGained(FocusEvent evt) {
if (nfAantal.getText().equals("Vul getal in")) {
nfAantal.clear();
}
}
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
}
The button part works, but the KeyEvent not.
And when I run this I keep getting these errors:
Exception in thread "AWT-EventQueue-1" java.lang.NumberFormatException: empty String
But when I do this, it kinda works. I still get the same errors but it works. (By the way not optimal, because it only appends it to the text field every second key pressing.):
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
taLijst.append(nfAantal.getText());
} else {
//some other code (not impotant for now)
}
}
So if someone knows why this doesn't work or knows a better way to accomplish this. Then that would be very appreciated!
(By the way I use Java 1.8)
Edit:
I now have (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) in the if statement and that got rid of the errors. (Thanks to #Joe)
But that still doesn't solve my question on how to turn the background red on certain values.
Aditional information about JNumberField:
I think this link has the code that makes up JNumberField and this link contains a download to the .jar file with in there the JNumberField Java file.
Another edit:
I think I found out for myself why it doesn't work with a JNumberfield; in the code it changes the background to white if its value is numeric so only if there is a way to get around this part of the code or change it (which I don't know how to do) my question can be answered for a JNumberField, if this isn't the case then I will use the JFormattedTextField instead.
This is the code that needs to be altered or circumvented:
protected void processKeyEvent(KeyEvent e) {
super.processKeyEvent(e);
if (isNumeric() || getText().equals("-") ||
getText().equals("") || getText().equals("."))
setBackground(Color.white);
else
setBackground(Color.red);
}
I don't know what a JNumberField is. It's not part of the JDK and when I searched with Google, it turned up several different ones.
I also don't understand why you are writing an applet.
Therefore, the below code may not be appropriate since it is a stand-alone Swing application that uses JFormattedTextField and DocumentListener.
Explanations after the code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.NumberFormatter;
public class RedNumbr implements DocumentListener, Runnable {
private JFormattedTextField aantal;
private JFrame frame;
#Override
public void insertUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void removeUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void changedUpdate(DocumentEvent event) {
// Never called for 'JFormattedTextField'
}
#Override
public void run() {
showGui();
}
private JPanel createNumberPanel() {
JPanel numberPanel = new JPanel();
NumberFormat format = NumberFormat.getIntegerInstance();
NumberFormatter formatter = new NumberFormatter(format);
aantal = new JFormattedTextField(formatter);
aantal.setColumns(10);
Document doc = aantal.getDocument();
doc.addDocumentListener(this);
numberPanel.add(aantal);
return numberPanel;
}
private void handleDocumentEvent(DocumentEvent event) {
Document doc = event.getDocument();
int len = doc.getLength();
if (len > 0) {
try {
String text = doc.getText(0, len);
int number = Integer.parseInt(text);
Color fg;
if (number < 1 || number > 7) {
fg = Color.red;
}
else {
fg = UIManager.getColor("TextField.foreground");
}
aantal.setForeground(fg);
}
catch (BadLocationException | NumberFormatException x) {
// Ignore.
}
}
}
private void showGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createNumberPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new RedNumbr());
}
}
Whenever the contents of the JFormattedTextField are changed, the relevant DocumentListener method is invoked. In those methods I check whether the JFormattedTextField contains a number and if it does then I change the foreground color of the JFormattedTextField according to your conditions, i.e. if the number is less than one (1) or greater than 7 (seven).
Note that the NumberFormatter does not prevent entering non-digits because JFormattedTextField handles that when it loses focus. Nonetheless it handles entering positive and negative numbers, which saves you some work. And the point of my answer is simply to demonstrate how to change the foreground color based on the entered text, which I believe answers your question.
EDIT
In order to change the background of the JFormattedTextField, rather than the foreground, you just need to change two lines in my code, above.
Replace
fg = UIManager.getColor("TextField.foreground");
with
fg = UIManager.getColor("TextField.background");
and also replace
aantal.setForeground(fg);
with
aantal.setBackground(fg);
I suppose that the JNumberField is an extension of JTextField and if it is the case it could be the synchronization problem between the main thread and the thread that is triggered by the KeyEvent action. To make sure that the event thread will be carried out you code it with invokeLater.
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
nfAantal.setBackground(Color.RED);
}
});
} else {
//some other code (not impotant for now)
}
}
I am trying to create a program in java that makes the letters of a string appear one at a time into a JLabel, but the text just appears all at once every time. The more the delay on the Thread.Sleep();, the longer it takes to appear. I think what is happening is that it is writing it all out and then printing it into the Label, but i still don't know what to do to fix it. The code is here:
package uiTesting;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public class ScrollingText extends JFrame {
private JPanel contentPane;
//Variables and values
public static String ThingToBePrinted = "You look down the gigantic hallway, the cold breath of spirits breathing down your neck. "
+ "Its nothing you haven't felt before. The spirits of those long past were always closer here, where many of them met"
+ " their end. Maybe you would be one of them, someday. But not today. Today, there was still too much to be done to rest.";
public static String ThingPrinted = "";
public static int Mili = 100;
public String html1 = "<html><body style='width: ";
public String html2 = "px'>";
/**
* Launch the application.
*/
public static void main(String[] args) {
System.out.println(ThingToBePrinted.length());
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ScrollingText frame = new ScrollingText();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ScrollingText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 719, 504);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
//The only Label
JLabel Scrolling_L1 = new JLabel("");
Scrolling_L1.setFont(new Font("Tahoma", Font.PLAIN, 15));
Scrolling_L1.setVerticalAlignment(SwingConstants.TOP);
Scrolling_L1.setBounds(10, 11, 693, 354);
contentPane.add(Scrolling_L1);
//The only Button
JButton Master_B1 = new JButton("Print Text");
Master_B1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
//scrolling function
for (int i = 0; i < ThingToBePrinted.length(); i++) {
String x = String.valueOf(ThingToBePrinted.charAt(i));
ThingPrinted = ThingPrinted + x;
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); //Html for wrapping text
Thread.sleep(Mili); //Delay between letters
}
}catch (Exception e){
JOptionPane.showMessageDialog(null, "Error");
}
}
});
Master_B1.setFont(new Font("Tahoma", Font.PLAIN, 25));
Master_B1.setBounds(164, 385, 375, 70);
contentPane.add(Master_B1);
}
}
I would really appreciate any solution at this point, I've been troubleshooting for hours
Your problem is related to how concurrency works in Swing. One (imperfect) solution is to use a SwingWorker. You could change your action listener to this:
Master_B1.addActionListener(event -> {
SwingWorker<Object, Void> worker = new SwingWorker<Object, Void>() {
#Override
protected String doInBackground() throws InterruptedException {
for (int i = 0; i < ThingToBePrinted.length(); i++) {
ThingPrinted += ThingToBePrinted.charAt(i);
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); // Html for wrapping text
Thread.sleep(Mili); //Delay between letters
}
return null;
}
};
worker.execute();
});
Read this tutorial: Lesson: Concurrency in Swing to get a better understanding of the topic. (You might want to read up on concurrency in Java in general also, see this tutorial for example).
It is because you are updating the JLabel in the UI thread itself from the event handler. Better way is to start a new thread in the event handler and then update the JLabel from this new thread. Following is the section you need to use in your code. I have tested it, it works.
Master_B1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try { // Start new thread here for updating JLabel.
new Thread() {
public void run() {
//scrolling function
for (int i = 0; i < ThingToBePrinted.length(); i++) {
String x = String.valueOf(ThingToBePrinted.charAt(i));
ThingPrinted = ThingPrinted + x;
Scrolling_L1.setText(html1 + "500" + html2 + ThingPrinted); //Html for wrapping text
try {
Thread.sleep(Mili); // Delay between letters
} catch (Exception e) {
}
}
}
}.start();
}catch (Exception e){
JOptionPane.showMessageDialog(null, "Error");
}
}
});
I'm working on a text editor, the main panel is composed of 3 JTextPanes, 2 on the side which show the number of line and common syntax errors, and 1 in the middle for the main edition. The whole stuff is packed in a JScrollPane.
The autoscroll issue appears when the users jump a line (press ENTER), the KeyListeners attached add a new entry in the 2 sides JTextPanes (num and syntax error for the line),
in reaction, the JScrollPane autoscroll in the bottom of the docs, probably to show the new text inserted in the 2 sides JTextPanes.
I partially fix the problem by setting the JScrollBar's position for each new line (added by the user) in my KeyListeners. Using scrollRectToVisible for example, or better by selecting a proper part of text in one of the 2 sides JTextPanes.
However, the final effect is not so great, for each new line the vertical scrollbar oscillates, and we can easily crash the app by pressing ENTER for a few seconds. I've been looking for solutions with a lot of methods of the JScrollPane class and trying AdjustmentListener but unsuccessfully. Would you help me?
PS: Sorry for my English. I am French, our forums suck.
SSCCE great source of inspiration, as this one worked well (couldn't see my problem when running it) it seems that my method actually works, but was not running in the right listener in my real code.
Thanks anyway!
There is the SSCCE, its a simple JScrollPane composed of one central JTextPane for edition and one lateral for the lines number. The placeScroll() method place the scrollbar so the caret in the main JTextPane is in the middle (vertically) when the paneLigne try to push it down.
Bye
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.BorderLayout;
import javax.swing.JScrollPane;
public class SSCCE extends JFrame {
private JTextPane paneLigne, main;
private String tempchain;
public SSCCE() {
this.setSize(500,500);
this.setTitle("S");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
paneLigne = new JTextPane();
paneLigne.setEditable(false);
tempchain = "";
for(int j=1; j<40; j++)
tempchain+=" " + j + " \n";
paneLigne.setText(tempchain);
main = new JTextPane();
main.addKeyListener(new KeyListener() {
private int lastnline=0;
public void keyPressed(KeyEvent arg0) {
if(arg0.getKeyCode()==10) {
String tecste=main.getText();
int n=nbLignes(tecste);
if(n>38) {
if(lastnline<n) {
paneLigne.setText(paneLigne.getText()+" " + (n+1) + " \n");
} else {
this.retablirLignes(tecste);
}
} else {
paneLigne.setText(tempchain);
}
lastnline=n;
this.placeScroll();
}
}
#Override
public void keyReleased(KeyEvent arg0) { }
#Override
public void keyTyped(KeyEvent arg0) { }
private int nbLignes(String str) {
int ret=1;
for(int n=0, cpt=0; (n=str.indexOf('\n', cpt))!=-1; cpt=n+1)
ret++;
return ret;
}
public void retablirLignes(String stret) {
int n=this.nbLignes(stret);
String retoure="";
if(n>=40) {
for(int j=1; j<n+2; j++)
retoure+=" " + j + " \n";
paneLigne.setText(retoure);
}
lastnline=n;
}
public void placeScroll() {
// TODO Auto-generated method stub
if(paneLigne!=null) {
int n=this.nbLignesBuen(main.getText().substring(0, main.getCaretPosition()));
if(n!=-1) {
paneLigne.select(paneLigne.getText().indexOf(""+n), n+1);
} else {
paneLigne.select(0,1);
}
}
}
private int nbLignesBuen(String str) { //return the index of the last 20th line
int ret=0;
for(int n, cpt=0; (n=str.indexOf('\n', cpt))!=-1; cpt=n+1)
ret++;
if(ret>20)
ret-=20;
else
ret=-1;
return ret;
}
});
JPanel contentpane=new JPanel(new BorderLayout());
contentpane.add(paneLigne, BorderLayout.WEST);
contentpane.add(main, BorderLayout.CENTER);
this.setContentPane(new JScrollPane(contentpane));
this.setVisible(true);
}
public static void main(String[] args) {
SSCCE fen = new SSCCE();
}
}
I am a bit new to swings, And i was trying to cough up some code involving Jtable.
I find that even though i have added the scrollbar policy the vertical scrollbar does not seem to appear. THe code is pretty shabby.(warning u before hand). But could you please indicate where I need to put in the scrollbar policy. I have tried adding it at a lot of places and it just does not seem to appear.
the other question is how do i make an empty table. As in every time the process button is clicked, i would like to refresh the table. Could u point me in this direction as well.
The directions for usage: just enter a number in the regular nodes textfield like 5 or 10
and click on the process button.
My code :
package ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import utils.ThroughputUtility;
/**
* #author Nathan
*
*/
public class EntryPoint extends JPanel{
public boolean isProcesed =false;
static JFrame frame;
JTabbedPane jTabbedPane = new JTabbedPane();
private static final long serialVersionUID = -6490905886388876629L;
public String messageTobeSent = null;
public int regularNodeCount =0;
public static final String MESSAGE_TO_BE_SENT =" Please Enter the message to be sent. ";
protected static final String ONE = "1";
Map<String,Double> regNodeThroughputMap ;
static JTable tableOfValues;
Object columnNames[] = { "<html><b>Regular Node Name</b></htm>", "<html><b>Throughput Value Obtained</b></html>"};
Object rowData[][] = null;
public EntryPoint() {
jTabbedPane.setTabPlacement(JTabbedPane.NORTH);
Font font = new Font("Verdana", Font.BOLD, 12);
jTabbedPane.setFont(font);
//Server Side Panel.
JPanel serverPanel = getServerPanel();
jTabbedPane.addTab("Server", serverPanel);
//Client side Panel.
JPanel clientPanel = getClientPanel();
jTabbedPane.addTab("Client", clientPanel);
}
private JPanel getClientPanel() {
//Heading Label
JPanel clientPanel = new JPanel();
JLabel RegularNodeLabel = new JLabel("<html><u>Throughput Optimization For Mobile BackBone Networks</u></html>");
RegularNodeLabel.setFont(new Font("Algerian",Font.BOLD,20));
RegularNodeLabel.setForeground(new Color(176,23,31));
clientPanel.add(RegularNodeLabel);
return clientPanel;
}
/**Server Side Code
* #return
*/
private JPanel getServerPanel() {
//Heading Label
JPanel serverPanel = new JPanel(new FlowLayout());
final Box verticalBox1 = Box.createVerticalBox();
Box horozontalBox1 = Box.createHorizontalBox();
Box verticalBox2forsep = Box.createVerticalBox();
Box horozontalBox2 = Box.createHorizontalBox();
JPanel heading = new JPanel(new FlowLayout(FlowLayout.CENTER));
JLabel backBoneNodeLabel = new JLabel("<html><u>Throughput Optimization For Mobile BackBone Networks</u></html>");
backBoneNodeLabel.setFont(new Font("Algerian",Font.BOLD,20));
backBoneNodeLabel.setForeground(new Color(176,23,31));
backBoneNodeLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
//Indication of BackBone Node
JPanel body = new JPanel(new FlowLayout(FlowLayout.LEFT));
JLabel backBoneNodeID = new JLabel("Fixed BackBone Node");
backBoneNodeID.setFont(new Font("Algerian",Font.BOLD,16));
backBoneNodeID.setForeground(new Color(176,23,31));
backBoneNodeID.setAlignmentX(Component.CENTER_ALIGNMENT);
//Seperator
JLabel seperator = new JLabel(" ");
seperator.setFont(new Font("Algerian",Font.BOLD,20));
seperator.setForeground(new Color(176,23,31));
verticalBox2forsep.add(seperator);
//Message label
JLabel messageLabel = new JLabel("Please enter the Message to be sent: ");
messageLabel.setFont(new Font("Algerian",Font.BOLD,16));
messageLabel.setForeground(new Color(176,23,31));
messageLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
//Message Text
final JTextField messageText = new JTextField(MESSAGE_TO_BE_SENT,25);
messageText.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void focusGained(FocusEvent arg0) {
if(messageText.getText().trim().equalsIgnoreCase(MESSAGE_TO_BE_SENT.trim())){
messageText.setText("");
}
}
});
horozontalBox1.add(messageLabel);
horozontalBox1.add(messageText);
//Regular node attached to backbone nodes.
JLabel regularNodelabel = new JLabel("Number of Regular nodes to be attached to the backbone node. ");
regularNodelabel.setFont(new Font("Algerian",Font.BOLD,16));
regularNodelabel.setForeground(new Color(176,23,31));
regularNodelabel.setAlignmentX(Component.LEFT_ALIGNMENT);
//Regular Node text
final JTextField regularNodeText = new JTextField(ONE,5);
regularNodeText.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
// TODO Auto-generated method stub
}
#Override
public void focusGained(FocusEvent e) {
if(regularNodeText.getText().trim().equalsIgnoreCase(ONE.trim())){
regularNodeText.setText("");
tableOfValues = new JTable(0,0);
}
}
});
horozontalBox2.add(regularNodelabel);
horozontalBox2.add(regularNodeText);
//Button for Processing.
JButton processbutton = new JButton("Process");
processbutton.setFont(new Font("Algerian",Font.BOLD,16));
processbutton.setForeground(new Color(176,23,31));
processbutton.setAlignmentX(Component.CENTER_ALIGNMENT);
//Processing on clciking process button
processbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
isProcesed=false;
Runnable runThread = new Runnable() {
#Override
public void run() {
while(!isProcesed){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
verticalBox1.add(tableOfValues);
isProcesed =false;
}
};
Thread processThread= new Thread(runThread);
processThread.start();
regularNodeCount = Integer.parseInt(regularNodeText.getText().trim());
regNodeThroughputMap = getThroughPutValues(regularNodeText.getText().trim());
System.out.println("Map obtained = "+regNodeThroughputMap);
tableOfValues = populateTable(regNodeThroughputMap);
isProcesed=true;
JScrollPane scrollPane = new JScrollPane(tableOfValues);
scrollPane.add(tableOfValues);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
verticalBox1.add(scrollPane,BorderLayout.CENTER);
// verticalBox1.add(scrollPane);
}
});
verticalBox1.add(backBoneNodeID);
verticalBox1.add(verticalBox2forsep);
verticalBox1.add(horozontalBox1);
verticalBox1.add(verticalBox2forsep);
verticalBox1.add(horozontalBox2);
verticalBox1.add(verticalBox2forsep);
verticalBox1.add(processbutton);
heading.add(backBoneNodeLabel);
//body.add(backBoneNodeID);
body.add(verticalBox1);
serverPanel.add(heading);
serverPanel.add(body);
return serverPanel;
}
protected JTable populateTable(Map<String,Double> regNodeThroughputMap) {
/*{ { "Row1-Column1", "Row1-Column2", "Row1-Column3" },
{ "Row2-Column1", "Row2-Column2", "Row2-Column3" } }*/
rowData = new Object[regularNodeCount+1][2];
Set<Map.Entry<String, Double>> set = regNodeThroughputMap.entrySet();
for (Map.Entry<String, Double> me : set) {
System.out.println("key ="+me.getKey());
System.out.println("Value ="+me.getValue());
}
String[] keys = new String[regularNodeCount+2];
String[] values = new String[regularNodeCount+2];
List<String> keyList = new LinkedList<String>();
List<String> valueList = new LinkedList<String>();
keyList.add("");
valueList.add("");
for(String key:regNodeThroughputMap.keySet()){
keyList.add(key);
}
for(double value:regNodeThroughputMap.values()){
System.out.println(value);
valueList.add(Double.toString(value));
}
keyList.toArray(keys);
valueList.toArray(values);
System.out.println(Arrays.asList(keys));
System.out.println(Arrays.asList(values));
rowData[0][0] =columnNames[0];
rowData[0][1] =columnNames[1];
for(int i=1;i<=regularNodeCount;i++){
for(int j=0;j<2;j++){
if(j==0)
rowData[i][j]=keys[i];
if(j==1)
rowData[i][j]=values[i];
}
}
return new JTable(rowData, columnNames);
//Printing the array
/* for (int i =0; i < regularNodeCount; i++) {
for (int j = 0; j < 2; j++) {
System.out.print(" " + rowData[i][j]);
}
System.out.println("");
}
*/
}
protected Map<String, Double> getThroughPutValues(String regularNodeInput) {
return ThroughputUtility.generateMapofNodeAndThroughput(regularNodeInput);
}
protected static void createAndShowGUI() {
//Create and set up the window.
frame = new JFrame("Throughput Optimization for Mobile BackBone Networks");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EntryPoint splitPaneDemo = new EntryPoint();
frame.getContentPane().add(splitPaneDemo.jTabbedPane);
JScrollPane sp = new JScrollPane(tableOfValues);
sp.setBorder(BorderFactory.createEmptyBorder());
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sp.setHorizontalScrollBarPolicy(JScrollPane .HORIZONTAL_SCROLLBAR_AS_NEEDED);
frame.setResizable(false);
//Display the window.
frame.pack();
frame.setVisible(true);
frame.setSize(800,600);
}
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Adding ThroughputUtility.java
package utils;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* #author Nathan
*
*/
public class ThroughputUtility {
public static double MIN =5000;
public static double MAX =10000;
public static final double e =Math.E;
public static final double epsilon = 8.854187 *Math.pow(10,-12);
static int regularNodeCount;
static int counter ;
/**Generates the map of Node and ThroughPut values
* #param regularNodeInput
*/
public static Map<String,Double> generateMapofNodeAndThroughput(String regularNodeInput){
regularNodeCount = Integer.parseInt(regularNodeInput);
List<Double> randNodeDistances =getRandDistanceOfNodes(regularNodeCount);
Map<String,Double> nodeAndThroughputmap = getThroughputValuesForNodes(randNodeDistances);
System.out.println(nodeAndThroughputmap);
return nodeAndThroughputmap;
}
/** Obtains the throughput value based on the distances between
* the regular nodes and the backend Nodes.
* #param randNodeDistances
* #return
*/
private static Map<String, Double> getThroughputValuesForNodes(
List<Double> randNodeDistances) {
Map<String,Double> nodeAndThroughputmap = new LinkedHashMap<String, Double>();
for(double i : randNodeDistances){
double throughputValue = calculateThroughPut(i);
nodeAndThroughputmap.put("RegularNode :"+counter, throughputValue);
counter++;
}
return nodeAndThroughputmap;
}
private static double calculateThroughPut(double distanceij) {
double throughput = 1 /(e*regularNodeCount*distanceij*epsilon);
return throughput;
}
/**Generates the distance dij .
* #param regularNodeCount
* #return
*/
private static List<Double> getRandDistanceOfNodes(int regularNodeCount) {
List<Double> distnodeNumbers = new LinkedList<Double>();
for(int i=0;i<regularNodeCount;i++){
double randnodeNumber = MIN + (double)(Math.random() * ((MAX - MIN) + 1));
distnodeNumbers.add(randnodeNumber);
}
return distnodeNumbers;
}
public static void main(String[] args) {
ThroughputUtility.generateMapofNodeAndThroughput("5");
/*System.out.println(e);
System.out.println(epsilon);*/
}
}
The main problem why you can't see the scroll bar is that you add the table to multiple containers.
when clicking the button, you recreate a lot of swing objects (why?), then you start a thread to add the table to the box (why?? be careful with swing and multithreading if you don't know what you are doing). after that (or before, depending on how long the thread is running) you add the table to the scrollpane.
the scrollpane does not contain your table, because you can only use it once.
A quick fix would be something like this:
create all you GUI stuff once, leave it out of any action listeners and stuff. if you start the application, it should just show an empty table. don't add the same object into multiple containers! you can control the size of your table and scrollpane by using
table.setPreferredSize(new Dimension(width, height));
if you click the button (that is in your action listener), get all the new data and add it it to the table. e.g. by using something like this.
tableOfValues.getModel().setValueAt(value, row, column);
or create a new table model if you have to:
tableOfValues.setModel(new DefaultTableModel(rowData, columnNames));
That's all I can tell you for now by looking at the code...
edit:
in the method populateTable(...) don't create a new table! use the above code to set a new model instead if you have to, or use an existing one and modify its values.
You never at the scroll pane to the JFrame as far as I could tell on
a quick look
You change the data in the TableModel (or replace the TableModel of
the JTable)
See http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
I had the same problem, just set JTable preferredsize to null and the scrollbar will show up.
Hope it helps