JTextPane not updating on JButton press - java

I am currently having trouble with a JTextPane not updating when a JButton ActionListener is telling it to update. In the code, I have a button that assigns a selected value from a JList to a global variable.
This process works because when I print out the variable when I press the button it prints the selected value in a list. However, when I push the button I also want that variable to populate the text pane so I know what value I am working with when using the UI. Does anyone know what might help with this?
I will try to get the relevant code from my large JavaSwing script as I'm using Eclipse WindowBuilder and it throws everything in the source in whatever order I created it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class MainMappingGui extends JFrame {
private JPanel contentPane;
String attSelected = "Hello";
String attButSelect = "";
JTextPane textPaneEdits;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainMappingGui frame = new MainMappingGui();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public MainMappingGui() {
setTitle("Data Mapping");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1105, 892);
contentPane = new JPanel();
contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton btnConfigMap = new JButton("Configure Mapping");
btnConfigMap.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
attButSelect = attSelected;
System.out.println(attButSelect);
textPaneEdits.repaint();
textPaneEdits.revalidate();
}
});
btnConfigMap.setFont(new Font("Tahoma", Font.PLAIN, 9));
btnConfigMap.setBounds(206, 406, 122, 23);
contentPane.add(btnConfigMap);
textPaneEdits = new JTextPane();
textPaneEdits.setBounds(634, 38, 314, 357);
textPaneEdits.setEditable(false);
textPaneEdits.setText("Current Output Column: " + attButSelect);
contentPane.add(textPaneEdits);
}
}
For this example, please assume that attSelected is a value that changes dynamically with a ListSelectionListener and works properly for selected values in a list. I have set it to "Hello" for simplicity sake.

As the one of the comments says, you have to manually change the text in the text pane.
btnConfigMap.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
attButSelect = attSelected;
textPaneEdits.setText(attButSelect);
}
});
Repaint and revalidate are not necessary.

Related

Printing JTextField gives out a blank on console

I am new to Java and have just tried out Java's swing, I tried making a log in form that would print the content of a JTextField to the console, but the console doesn't show anything when I tried it.
Here's my code:
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
public class JavaTextField {
private JFrame frame;
private JTextField text1;
private JTextField text2;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JavaTextField window = new JavaTextField();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public JavaTextField() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
text1 = new JTextField();
text1.setBounds(114, 38, 122, 40);
frame.getContentPane().add(text1);
text1.setColumns(10);
String majorText = text1.getText();
text2 = new JTextField();
text2.setBounds(114, 117, 86, 20);
frame.getContentPane().add(text2);
text2.setColumns(10);
String minorText = text2.getText();
JButton btnButton = new JButton("Button");
btnButton.setBounds(132, 192, 159, 40);
frame.getContentPane().add(btnButton);
btnButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(majorText);
System.out.println(minorText);
}
}
);
}
}
I'm glad if anyone could point me in the right direction, because I haven't seen the solution to this problem on the internet yet.
The issue here is, that you retrieve the content from the JTextFields at the wrong time. Currently you call getText() right when the components are being initialized. Of course, the content returned from getText() will be an empty String.
So to fix the issue in your logic, you should actually retrieve the majorText and minorText from the JTextFields only once your JButton has been pressed. Because at that point in time, when your button is pressed, the content of your text fields should be correct. To do that, move the retrieval of the text to the ActionListener.
The updated ActionListener should look as follows:
btnButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String majorText = text1.getText();
String minorText = text2.getText();
System.out.println(majorText);
System.out.println(minorText);
}
}
or simply:
btnButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(text1.getText());
System.out.println(text2.getText());
}
}
Sidenote (as also mentioned by the other answer):
Using null layout is highly discouraged, as it is a frequent source for unnecessary errors. Have a look at the different LayoutManagers available and how and when to use them.
There are some improvements to do in your code:
Avoid the use of null-layout and setBounds(...), see why should you avoid it and a graphic example along with a suggestion to fix it by using layout managers
Your majorText is getting the text BEFORE you click on the button, and by that time it's empty and never update it, you need to get the text on button click, so move this line:
String majorText = text1.getText();
Inside your actionListener, same thing for minorText
And if you tagged your question with Java 8, then you could rewrite your listener using Java 8 lambdas
btnButton.addActionListener(e -> {
String majorText = text1.getText();
String minorText = text1.getText();
System.out.println(majorText);
System.out.println(minorText);
}

How to Add text to JTextArea

Im creating a programme using java. I want the user to enter some text, then push the button so the text entered shows in the label. However, I have 2 problems. First, the text are isn´t displaying when I execute the app. Second, I don´t know how to allow the user to type in the area. Im new in java so that´s why Im asking. Here is the code. Thank you.
import javax.swing.*;
import java.awt.event.*;
class Boton extends JFrame implements ActionListener {
JButton boton;
JTextArea textArea = new JTextArea();
JLabel etiqueta = new JLabel();
public Boton() {
setLayout(null);
boton = new JButton("Escribir");
boton.setBounds(100, 150, 100, 30);
boton.addActionListener(this);
add(boton);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boton) {
try {
String texto = textArea.getText();
etiqueta.setText(texto);
Thread.sleep(3000);
System.exit(0);
} catch (Exception excep) {
System.exit(0);
}
}
}
}
public class Main{
public static void main(String[] ar) {
Boton boton1 =new Boton();
boton1.setBounds(0,0,450,350);
boton1.setVisible(true);
boton1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Problems:
You never add the JTextArea into your GUI, and if it doesn't show, a user cannot directly interact with it.
You are calling Thread.sleep on the Swing event thread, and this will put the entire application to sleep, meaning the text that you added will not show.
Other issues include use of null layouts and setBounds -- avoid doing this.
Solutions:
Set the JTextArea's column and row properties so that it sizes well.
Since your JTextArea's text is going into a JLabel, a component that only allows a single line of text, I wonder if you should be using a JTextArea at all. Perhaps a JTextField would work better since it allows user input but only one line of text.
Add the JTextArea to a JScrollPane (its viewport actually) and add that to your GUI. Then the user can interact directly with it. This is most easily done by passing the JTextArea into a JScrollPane's constructor.
Get rid of the Thread.sleep and instead, if you want to use a delay, use a Swing Timer. check out the tutorial here
For example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Main2 {
public static void main(String[] args) {
// create GUI in a thread-safe manner
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
BotonExample mainPanel = new BotonExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class BotonExample extends JPanel {
private JLabel etiqueta = new JLabel(" ");
private JButton boton = new JButton("Escribir");
// jtext area rows and column properties
private int rows = 5;
private int columns = 30;
private JTextArea textArea = new JTextArea(rows, columns);
public BotonExample() {
// alt-e will activate button
boton.setMnemonic(KeyEvent.VK_E);
boton.addActionListener(e -> {
boton.setEnabled(false); // prevent button from re-activating
String text = textArea.getText();
etiqueta.setText(text);
// delay for timer
int delay = 3000;
Timer timer = new Timer(delay, e2 -> {
// get current window and dispose ofit
Window window = SwingUtilities.getWindowAncestor(boton);
window.dispose();
});
timer.setRepeats(false);
timer.start(); // start timer
});
// create JPanels to add to GUI
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
topPanel.add(new JLabel("Etiqueta:"));
topPanel.add(etiqueta);
JPanel bottomPanel = new JPanel();
bottomPanel.add(boton);
JScrollPane scrollPane = new JScrollPane(textArea);
// use layout manager and add components
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
}
textarea.setText("Text"); // this will insert text into the text area
textarea.setVisable(true); // this will display the text area so you can type in it
textarea.setSize(500,500); // set size of the textarea so it actually shows
The user should be able to type in the TA when it is displayed and just do a getText to pull the text

Currency Exchange API Java GUI

I am fairly new to programming of this level and I was wondering if someone could help me with this.
So I am trying to create a currency exchange app using Java, and I have a problem updating the values on the GUI to reflect the new value on the API. Essentially ever so often the values change and it shows on the console, however, the GUI value never updates and stays the same.
I thought ActionListener would help solve this problem but either I have not implemented it properly or I haven't googled and come up with a solution properly.
Thank you in advance for any help :)
Here is my code:
GUI.java
public class GUI extends JFrame {
static Arb arb = new Arb();
private JPanel contentPane;
public static void main(String[] args) throws IOException, InterruptedException {
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
arb.runUpdate_fx("anAPI");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Timer timer = new Timer(100 ,taskPerformer);
timer.setRepeats(true);
timer.start();
Thread.sleep(5000);
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI frame = new GUI();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public GUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1121, 765);
contentPane = new JPanel();
contentPane.setBackground(Color.BLACK);
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JTextPane FXRate = new JTextPane();
FXRate.setForeground(new Color(255, 255, 255));
FXRate.setBackground(new Color(0, 0, 0));
FXRate.setEditable(false);
FXRate.setFont(new Font("Tahoma", Font.BOLD, 11));
panel_1.setLayout(new FlowLayout(FlowLayout.LEADING, 5, 5));
FXRate.setText("FX Rates\r\n\r\nEUR-AUD FX Rate: " + arb.fxEURAUD + "\r\nEUR-USD FX Rate: " + arb.fxEURUSD);
panel_1.add(FXRate);
}
}
Result:
EUR-AUD: 1.646659
after sometime
EUR-AUD: 1.646659
Expected Result:
EUR-AUD: 1.646659
after sometime
EUR-AUD: 1.80102
References are passed by value in Java.
JTextField textField = new JTextField();
String text = "Initial text";
textField.setText(text); // no displays "Initial text";
text = "Updated text"; // doesn't change what the panel displays
// the panel still holds a reference to the old text
textField.setText(text); // updates the reference the panel holds to your new text
In your event listener, you need to call setText with the updated string to actually make the textfield display that.
Your timer and event handler look good, but the update method only fetches new values into the Arb object; nothing takes those values and puts them into the GUI. You can do that explicitly in your event handler.after the update method returns. To enable that, you may want to make FXRate a member variable, so you can access it from the action listener.

Multiple Buttons doing something

I am still learning how to code in java and I could use a bit of help right now.
This is the current code I wrote. As you can see, it's a simple panel with a bunch of buttons and a slider. I want to make a different console output whenever I hit a different button. So if I hit Back, it's supposed to write Back in the console. If I scroll a bit on the slider, it's supposed to write the new value in the console. Stuff like that. I know it has to be done with actionListener and actionPerformed but after some experimenting I couldn't get it to work.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Gui implements ActionListener {
// Adding all the goods
JFrame frame;
JPanel panel;
JButton endButton;
JButton backButton;
JButton calcButton;
JSlider maxIterations;
JLabel view;
Gui() {
// General
this.frame = new JFrame("Trying my best, I swear");
this.frame.setSize(500, 500);
this.frame.setVisible(true);
this.panel = new JPanel();
// Buttons
this.backButton = new JButton("Back");
this.calcButton = new JButton("Calc");
this.endButton = new JButton("End");
this.panel.add(this.endButton);
this.panel.add(this.calcButton);
this.panel.add(this.backButton);
this.frame.add(this.panel);
// Label
JLabel label1 = new JLabel();
label1.setText("Space Holer");
panel.add(label1);
// Slider
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 30, 15);
panel.add(slider);
slider.setMinorTickSpacing(2);
slider.setMajorTickSpacing(5);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
// Make the buttons do something
this.endButton.addActionListener(this);
}
public void actionPerformed(ActionEvent ae) {
System.out.println("End");
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Gui m = new Gui();
}
}
You could...
Take advantage of the actionCommand property of the button, which is set to the ActionEvent when it's created. If you don't supply an actionCommand to the button yourself, it will default to the text value, so you could do something like
public class ButtonActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "Back":
System.out.println("Back");
break;
case "Calc":
System.out.println("Calc");
break;
case "End":
System.out.println("End");
break;
}
}
}
This is good if the ActionListener is external to the class where the buttons are defined, because you won't have access to the button references. It's also good, because you could have a number of buttons (including toolbar buttons and menu items) which do the same thing
You could...
Make use of the ActionListener's source property
public class ButtonActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == backButton) {
System.out.println("Back");
} else if (e.getSource() == calcButton) {
System.out.println("Calc");
} else if (e.getSource() == endButton) {
System.out.println("End");
}
}
}
This is useful if the ActionListener in defined as a inner class to the parent class from where the buttons are defined
You could...
Use an anonymous class registered directly against the button...
endButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("End");
}
});
This is good where the button does a single, isolated task
You could...
Make use of the Action API which allows you to define a self contained unit of work, which can be used by buttons to configure themselves completely from it. This is useful where you have a repeated action which can be executed from different locations of the UI, like a "open file" action contained in the menu bar, tool bar and some wizard. You can even use it with the key bindings API for extended functionality
See How to use actions for more details
Need to add ActionListener to all buttons,
calcButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("calcButton");
// calculation for slider.
}
});
backButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("backButton");
}
});
then u get the different console output.
Call setVisible on jframe after you placed all components into it.
Add ActionListener to each button. Add ChangeListener to slider as it cannot have ActionListener.
See full code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
public class Gui implements ActionListener {
// Adding all the goods
JFrame frame;
JPanel panel;
JButton endButton;
JButton backButton;
JButton calcButton;
JSlider maxIterations;
JLabel view;
Gui() {
// General
this.frame = new JFrame("Trying my best, I swear");
this.frame.setSize(500, 500);
this.panel = new JPanel();
// Buttons
this.backButton = new JButton("Back");
this.calcButton = new JButton("Calc");
this.endButton = new JButton("End");
this.panel.add(this.endButton);
this.panel.add(this.calcButton);
this.panel.add(this.backButton);
this.frame.add(this.panel);
// Label
JLabel label1 = new JLabel();
label1.setText("Space Holer");
panel.add(label1);
// Slider
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 30, 15);
panel.add(slider);
slider.setMinorTickSpacing(2);
slider.setMajorTickSpacing(5);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
// Make the buttons do something
this.endButton.addActionListener(this);
this.backButton.addActionListener(this);
this.calcButton.addActionListener(this);
slider.addChangeListener(e -> {
Object source = e.getSource();
if (source instanceof JSlider) {
int value = ((JSlider) source).getValue();
System.out.println(value);
}
});
frame.pack();
this.frame.setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Object source = ae.getSource();
if (source instanceof JButton) {
String text = ((JButton) source).getText();
System.out.println(text);
}
}
public static void main(String[] args) {
#SuppressWarnings("unused")
Gui m = new Gui();
}
}

Java JSlider.getvalue returns good value to JTextField, wrong to toolTipText

I work with NetBeans 7.2.
I have a JSlider slider_random in my JPanel1, entered the value 100, minimum 0, maximum 1000. I set a toolTipText for slider_random via properties (custom code):
"<html>Range (0-" + String.valueOf(slider_random.getMaximum()) + ")<br>Current: " + String.valueOf(slider_random.getValue())
Also placed a JTextField text_current and set the text to 100, This displays the value of slider_random when I change it.
I set stateChanged event to slider_random:
private void slider_randomStateChanged(javax.swing.event.ChangeEvent evt) {
slider_random.setToolTipText("<html>Range (0-" + String.valueOf(slider_random.getMaximum()) + ")<br>Current: " + String.valueOf(slider_random.getValue()));
jTextField1.setText(String.valueOf(slider_random.getValue()));
}
My problem is when I start the program and point to the slider it shows:
Range (0-1000)
Current: 50
Then move the slider a little, and move back to the original position (meanwhile I can see changes in text_current) all data become correct, and the tooltip says:
Range (0-1000)
Current: 100
What can cause my problem?
Here's the screenshot, after I lauched it.
I was able to repro your issue.
The problem is that jSlider's default value is 50. You modified the value to 100, but this was not reflected in jSlider's setToolTip() method where you access jSlider's value (thru the custom code). It would show the old value of 50.
To correct this, one solution is to create a mouse hover event on the slider, so that when you run your application and hover the mouse pointer over the slider, jToolTip method picks the latest value and shows you the same. It worked for me, so i'm sure it'll work for you.
If i can think of a better solution, i'll post the same.
Maybe the listener is added after the value of the slider was already set. You may need to change the order. Or, just to fix the initialization issue you may need to set the tooltip explicitly once you initialize the slider.
As an alternative you can subclass JSlider and override getToolTipText, for example:
JSlider slider = new JSlider() {
public String getToolTipText(MouseEvent e) {
return "<html>Range (0-" + String.valueOf(getMaximum()) + ")<br>Current: " + String.valueOf(getValue());
}
};
Here is a short demo:
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JSlider;
public class TestSlider {
public static void main(String[] args) {
JFrame frame = new JFrame("TestSlider");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JSlider slider = new JSlider() {
public String getToolTipText(MouseEvent e) {
return "<html>Range (0-" + String.valueOf(getMaximum())
+ ")<br>Current: " + String.valueOf(getValue());
}
};
slider.setToolTipText("");
frame.add(slider);
((JComponent) frame.getContentPane()).setBorder(BorderFactory
.createEmptyBorder(10, 10, 10, 10));
frame.setLocationByPlatform(true);
frame.pack();
frame.setVisible(true);
}
}
i think the best way to do this action,is to make a label near to your slider then put an variable like an integer instead of "y" or put the get value instead of "y",& the event which you need for this is Item state change ,so when you move your slider the label will move with the slider & is going to show the value ;)
public class Slidebar extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Slidebar frame = new Slidebar();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Slidebar() {
setResizable(false);
setTitle("SlideBar With Text Move");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 317, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
final JSlider slider = new JSlider();
slider.setPaintLabels(true);
slider.setOrientation(SwingConstants.VERTICAL);
slider.setValue(0);
slider.setBounds(131, 60, 53, 136);
contentPane.add(slider);
final JLabel lblNewLabel = new JLabel("");
int y = 165;
lblNewLabel.setBounds(111, 173, 41, 30);
contentPane.add(lblNewLabel);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent arg0) {
int y=165;
lblNewLabel.setBounds(111, y-(slider.getValue())-5, 41, 30);
lblNewLabel.setText(slider.getValue()+"");
}
});
}
}

Categories