I have the following problem:
in my JTextArea I inserted a default string, which must be updated with the new wording once the file is uploaded.
I have the problem that a live refresh of JTextArea is not done, but if I log out and log in I will see the changed string.
public void createWindow()
{
// some code...
JTextArea textArea = new JTextArea(1,1);
String all = "Nothing Infractions";
try {
all = new Scanner (file).useDelimiter("\\A").next();
textArea =new JTextArea(100,1);
} catch (FileNotFoundException e1) {
textArea =new JTextArea(1,1);
}
JScrollPane scroll = new
JScrollPane(textArea,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
textArea.setText(all);
frmUser.getContentPane().add(textArea);
Update:
the text area was thought to have been written without infraction, then passed the program going on randomly and assigning it to each user, the problem and that when assigning them all the logged in user does not automatically update that part of text where no infraction was written.
I Use Java 8
Use revalidate() and repaint().
Here is an MCVE (Minimal, Complete and Verifiable example, see https://stackoverflow.com/help/mcve) from which you cut and paste as needed for your question. The example below is not fundamentally different from your question, but it allows other users on StackOverflow to replicate the problem and pass along suggestions or solutions.
In addition to modifying the question, please indicate which version of Java you are running.
Based on what you have said, you will probably need to implement some type of listener to determine when the contents of the file change -- or does it get created and never changed?
190418 1646Z: Added a refresh button per your last comment. Let me know if you would prefer the window to update without having to click a button.
package javaapplication7;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class FileWatcher extends JFrame {
static final File WATCH_FILE = new File("c:\\temp\\java7.txt");
static final String DELIMITER = "\n";
private JPanel panel = new JPanel();
private JTextArea textArea = new JTextArea(20, 20);
public FileWatcher() {
JFrame frame = new JFrame();
frame.setSize(600, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setTitle("File Watcher");
frame.add(createPanel());
frame.pack();
}
private JPanel createPanel() {
// some code...
JPanel tempPanel = getPanel();
GridBagConstraints gbc = new GridBagConstraints();
tempPanel.setLayout(new GridBagLayout());
JButton button = new JButton("Refresh");
button.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
getUpdatedText();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
gbc.anchor = GridBagConstraints.NORTH;
getPanel().add(button, gbc);
getTextArea().setFont(new Font("Verdana", Font.BOLD, 16));
getTextArea().setBorder(BorderFactory.createEtchedBorder());
getTextArea().setLineWrap(true);
getTextArea().setWrapStyleWord(true);
getTextArea().setOpaque(true);
getTextArea().setVisible(true);
getUpdatedText();
JScrollPane scroll = new JScrollPane(getTextArea(), JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setBorder(BorderFactory.createLineBorder(Color.blue));
scroll.setVisible(true);
// frmUser.getContentPane().add(textArea);
gbc.gridy = 1;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
tempPanel.add(scroll, gbc);
return tempPanel;
}
public void getUpdatedText() {
String all = new String();
try (Scanner scanner = new Scanner(WATCH_FILE).useDelimiter(DELIMITER)) {
while (scanner.hasNext()) {
all = all.concat(scanner.next()).concat(DELIMITER);
}
} catch (FileNotFoundException ex) {
// swallow, next line covers it
}
if (all.isEmpty()) {
all = "No Infractions";
}
getTextArea().setText(all);
}
public JPanel getPanel() {
return panel;
}
public void setPanel(JPanel panel) {
this.panel = panel;
}
public JTextArea getTextArea() {
return textArea;
}
public void setTextArea(JTextArea textArea) {
this.textArea = textArea;
}
public static void main(String[] args) {
FileWatcher javaApplication7 = new FileWatcher();
}
}
Related
unfortunately I can't handle the change of txt when the button is clicked, I try to write a txt and overtime that I click the button, this txt value should change and allotting seems right, the only problem is that the printed number is not obvious and it seems some part of previous txt remains with it.
package berGenerator;
import java.awt.EventQueue;
public class sscce {
private JFrame frame;
private final Action action = new SwingAction();
private static int i = 555;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
sscce window = new sscce();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public sscce() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 550, 401);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton Next = new JButton("Next");
Next.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
Next.setAction(action);
Next.setBounds(167, 290, 198, 64);
frame.getContentPane().add(Next);
}
private class SwingAction extends AbstractAction {
public SwingAction() {
putValue(NAME, "Next Timeslot/scheduler");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
i = i+1;
frame.getContentPane().validate();
frame.getContentPane().repaint();
String from = String.valueOf(i);
System.out.println("sw is: "+from);
JTextArea TextArea11 = new JTextArea("");
TextArea11.setText(from);
TextArea11.setForeground(Color.GREEN);
TextArea11.setBounds(6, 66, 87, 16);
frame.getContentPane().add(TextArea11);
}
}
}
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify.
Layout managers are fundamental to the Swing API, you should make the time to learn how to use them, they will solve more problems than you think they create.
See Laying Out Components Within a Container for more details.
You're creating multiple instances of JTextArea and adding to the frame, but you're not removing any, you're running into a potential z-ordering problem at best and a major resource management issue at worst.
Instead, simply create a single instance of JTextArea, add it to the frame (just like you did your button) and simply update it when the Action is triggered, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import static javax.swing.Action.NAME;
import static javax.swing.Action.SHORT_DESCRIPTION;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Test {
private JFrame frame;
private final Action action = new SwingAction();
private static int i = 555;
private JTextArea textArea;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Test() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textArea = new JTextArea(10, 20);
textArea.setText(String.valueOf(i));
frame.add(new JScrollPane(textArea));
JButton next = new JButton("Next");
next.setAction(action);
frame.getContentPane().add(next, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
}
private class SwingAction extends AbstractAction {
public SwingAction() {
putValue(NAME, "Next Timeslot/scheduler");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
i = i + 1;
String from = String.valueOf(i);
System.out.println("sw is: " + from);
textArea.setText(from);
textArea.setForeground(Color.GREEN);
}
}
}
I have a method like so, which is given an array of JButton and returns their text whenever they are pressed:
public static String foo(JButton[] buttons) {
for (JButton i : buttons) {
i.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
return i.getText();
}
});
}
}
But, of course, this code will not compile because I am returning a variable to a null method. So, how would I have i.getText() return its output too the foo() method?
Edit, all of the code:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class JCustomFrame {
public static void showMessageFrame(String title, String message,
String[] textOnButtons, ImageIcon icon) {
final JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.WHITE);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.RELATIVE;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 5, 5, 5);
JLabel messageLabel = new JLabel(message);
messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));
panel.add(messageLabel, c);
c.gridy = 1;
c.gridx = 0;
for (int i = 0; i < textOnButtons.length; i++) {
JButton button = new JButton(textOnButtons[i]);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
return ((JButton) arg0.getSource()).getText();
frame.dispose();
}
});
button.setFont(button.getFont().deriveFont(16.0f));
panel.add(button, c);
c.gridx++;
}
if (icon == null) {
frame.setIconImage(new BufferedImage(1, 1,
BufferedImage.TYPE_INT_ARGB_PRE));
} else {
frame.setIconImage(icon.getImage());
}
frame.add(panel);
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
public static void main(String[] args) {
JCustomFrame.showMessageFrame("Test Frame",
"Do you really want to do this?", new String[] { "Hell No",
"Sure, Why Not" }, null);
}
}
This statement doesn't make sense:
So, how would I have i.getText() return its output too the foo() method?
The method foo() is no longer running after the ActionListeners have been added to the buttons, and certainly will have ended by the time a user pushes a button, as per the rules of event-driven programming. Instead, though you could have the ActionListeners change the state of a class, any class, and that should suffice. For instance:
class FooClass {
private String text;
public void foo(JButton[] buttons) {
for (JButton i : buttons) {
i.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
text = e.getActionCommand();
}
});
}
}
}
If you need greater detail on a viable solution, please tell us more details about your actual program and your specific problem.
Now if you actually needed a method to return the value of the button pressed, you would need to do this via notification mechanisms and a call-back method, but again the details of a solution will depend on the details of the actual problem and code.
Edit
You're trying to emulate a JOptionPane. Your solution is to either use a JOptionPane, adding a JPanel to it, or create your own using a modal JDialog:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JCustomFrame2 {
public static String showMessageFrame(Window owner, String title,
String message, String[] textOnButtons, ImageIcon icon) {
final JDialog dialog = new JDialog(owner);
StringBuilder sb = new StringBuilder();
// make it application modal!
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.WHITE);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.RELATIVE;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 5, 5, 5);
JLabel messageLabel = new JLabel(message);
messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));
panel.add(messageLabel, c);
c.gridy = 1;
c.gridx = 0;
for (int i = 0; i < textOnButtons.length; i++) {
JButton button = new JButton(textOnButtons[i]);
button.addActionListener(new ButtonListener(sb));
button.setFont(button.getFont().deriveFont(16.0f));
panel.add(button, c);
c.gridx++;
}
if (icon == null) {
dialog.setIconImage(new BufferedImage(1, 1,
BufferedImage.TYPE_INT_ARGB_PRE));
} else {
dialog.setIconImage(icon.getImage());
}
dialog.add(panel);
dialog.setTitle(title);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.pack();
dialog.setVisible(true);
return sb.toString();
}
private static class ButtonListener implements ActionListener {
private StringBuilder sb;
public ButtonListener(StringBuilder sb) {
this.sb = sb;
}
#Override
public void actionPerformed(ActionEvent e) {
sb.append(e.getActionCommand());
Component component = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(component);
if (win != null) {
win.dispose();
}
}
}
public static String showMessageFrame(String title,
String message, String[] textOnButtons, ImageIcon icon) {
return showMessageFrame(null, title, message, textOnButtons, icon);
}
public static void main(String[] args) {
String result = JCustomFrame2.showMessageFrame("Test Frame",
"Do you really want to do this?", new String[] { "Hell No",
"Sure, Why Not" }, null);
System.out.println(result);
}
}
Why so complicated? whatever foo is supposed to do, it would be a lot easier to simply call another method from inside the ActionListener with the name of the button as argument. Or, if you really want to achieve something like this, make the thread wait for the user to press a button.
public void doSomething(){
JButton[] someButtons = ...;//whereever you create the buttons
System.out.println(foo(someButtons));
}
public static String foo(JButton[] buttons){
final String someString = "";
final Object lock = new Object();
for(JButton b : buttons){
b.addActionListener(e -> {
someString.concat(b.getName());
synchronized(lock){
lock.notifyAll();
}
});
}
synchronized(lock){
try{
lock.wait();
}catch(InterruptedException e){}
}
return someString;
}
I have a JScrollPane and a JTextArea (editable) with 10 rows. I want the first user input to appear at the bottom of the JTextArea and the most recent input should push the previous input upward. To achieve this I use textArea.setMargin(new Insets(x,0,0,0)); and everything works as it should - except that my second input will toggle the JScrollPane.
How can I start at the bottom of the JTextArea and only enable scrolling when the entire original viewport is filled?
Basically, you could add the JTextText onto a JPanel with another JPanel which acts a filler, causing the JTextArea to occupy the smallest space it actually needs.
I did this by using GridBagLayout to force the fill to occupy the most of space it could...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestTextArea {
public static void main(String[] args) {
new TestTextArea();
}
public TestTextArea() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
JPanel filler = new JPanel();
filler.setBackground(Color.WHITE);
add(filler, gbc);
gbc.gridy = 1;
gbc.weighty = 0;
ta = new JTextArea(1, 20);
add(ta, gbc);
}
}
}
To achieve this I use textArea.setMargin(new Insets(x,0,0,0)); and everything works as it should - except that my second input will toggle the JScrollPane.
Well I would guess that you would need to reset the margin every time you add text to the text area to take into account the new preferred size of the text area in relation to the size of the scroll pane.
You should be able to add a DocumentListener to the text area and make your adjustment whenever text is added to the Document.
I don't think that using margins and insets is the way to go because you are using layout adjustments to achieve text (content) functionality. This should be controlled by the Document object, which is what JTextArea makes its calls to regarding its content.
If you are calling append internally, then override it in a new class extending JTextArea:
public class Test {
static MyTextArea ta = new MyTextArea();
static int x = 0;
public static void main(String[] args) {
ta.setRows(10);
ta.setText("\n\n\n\n\n\n\n\n\n");
ta.setCaretPosition(ta.getDocument().getLength());
JButton append = new JButton("Append");
append.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ta.append("\n" + x);
x++;
}
});
JFrame frame= new JFrame();
frame.setContentPane(new JPanel(new BorderLayout()));
frame.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
frame.getContentPane().add(append, BorderLayout.LINE_START);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class MyTextArea extends JTextArea {
#Override
public void append(String str) {
super.append(str);
try {
if (getDocument().getText(0, 1).equals("\n"))
getDocument().remove(0, 1);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
}
If you are editing it manually, add a DocumentListener:
public class Test {
public static void main(String[] args) {
JTextArea ta = new JTextArea();
ta.setRows(10);
ta.setText("\n\n\n\n\n\n\n\n\n");
ta.setCaretPosition(ta.getDocument().getLength());
ta.getDocument().addDocumentListener(new MyDocListener());
JFrame frame= new JFrame();
frame.setContentPane(new JPanel(new BorderLayout()));
frame.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static class MyDocListener implements DocumentListener {
#Override
public void insertUpdate(DocumentEvent e) {
final DocumentEvent de = e;
Runnable pushUp = new Runnable() {
#Override
public void run() {
String t = null;
try {
t = de.getDocument().getText(de.getOffset(), de.getLength());
if (t.equals("\n") && de.getDocument().getText(0, 1).equals("\n"))
ta.getDocument().remove(0, 1);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
};
SwingUtilities.invokeLater(pushUp);
}
#Override
public void removeUpdate(DocumentEvent e) {}
#Override
public void changedUpdate(DocumentEvent e) {}
}
}
Note that all you need from the code are the inner classes, the rest is just so you can see it working. I also don't have information regarding the initial state of the text area. Here I just set the number of rows to 10 and the text to 10 empty lines. I'm also not sure what you're allowed to do in the text area. This solution assumes that you can't jump lines and each time you insert a line it's not blank and it follows the previous line.
I have a problem with my JLayeredPane, I am probably doing something incredibly simple but I cannot wrap my head around it. The problem i have is that all the components are merged together and have not order. Could you please rectify this as I have no idea. The order I am trying to do is have a layout like this
output
label1 (behind)
input (in Front)
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class window extends JFrame implements KeyListener {
/**
*
*/
private static final long serialVersionUID = 7092006413113558324L;
private static int NewSize;
public static String MainInput;
public static JLabel label1 = new JLabel();
public static JTextField input = new JTextField(10);
public static JTextArea output = new JTextArea(main.Winx, NewSize);
public window() {
super("Satine. /InDev-01/");
JLabel label1;
NewSize = main.Winy - 20;
setLayout(new BorderLayout());
output.setToolTipText("");
add(input, BorderLayout.PAGE_END);
add(output, BorderLayout.CENTER);
input.addKeyListener(this);
input.requestFocus();
ImageIcon icon = new ImageIcon("C:\\Users\\" + System.getProperty("user.name") + "\\AppData\\Roaming\\.Satine\\img\\textbox.png", "This is the desc");
label1 = new JLabel(icon);
add(label1, BorderLayout.PAGE_END);
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_ENTER) {
try {
MainMenu.start();
} catch (IOException e1) {
System.out.print(e1.getCause());
}
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
And the main class.
import java.awt.Container;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
public class main {
public static int Winx, Winy;
private static JLayeredPane lpane = new JLayeredPane();
public static void main(String[] args) throws IOException{
Winx = window.WIDTH;
Winy = window.HEIGHT;
window Mth= new window();
Mth.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Mth.setSize(1280,720);
Mth.setVisible(true);
lpane.add(window.label1);
lpane.add(window.input);
lpane.add(window.output);
lpane.setLayer(window.label1, 2, -1);
lpane.setLayer(window.input, 1, 0);
lpane.setLayer(window.output, 3, 0);
Mth.pack();
}
}
Thank you for your time and I don't expect the code to be written for me, all I want is tips on where I am going wrong.
I recommend that you not use JLayeredPane as the overall layout of your GUI. Use BoxLayout or BorderLayout, and then use the JLayeredPane only where you need layering. Also, when adding components to the JLayeredPane, use the add method that takes a Component and an Integer. Don't call add(...) and then setLayer(...).
Edit: it's ok to use setLayer(...) as you're doing. I've never used this before, but per the API, it's one way to set the layer.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class LayeredPaneFun extends JPanel {
public static final String IMAGE_PATH = "http://duke.kenai.com/" +
"misc/Bullfight.jpg";
public LayeredPaneFun() {
try {
BufferedImage img = ImageIO.read(new URL(IMAGE_PATH));
ImageIcon icon = new ImageIcon(img);
JLabel backgrndLabel = new JLabel(icon);
backgrndLabel.setSize(backgrndLabel.getPreferredSize());
JPanel forgroundPanel = new JPanel(new GridBagLayout());
forgroundPanel.setOpaque(false);
JLabel fooLabel = new JLabel("Foo");
fooLabel.setFont(fooLabel.getFont().deriveFont(Font.BOLD, 32));
fooLabel.setForeground(Color.cyan);
forgroundPanel.add(fooLabel);
forgroundPanel.add(Box.createRigidArea(new Dimension(50, 50)));
forgroundPanel.add(new JButton("bar"));
forgroundPanel.add(Box.createRigidArea(new Dimension(50, 50)));
forgroundPanel.add(new JTextField(10));
forgroundPanel.setSize(backgrndLabel.getPreferredSize());
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(backgrndLabel.getPreferredSize());
layeredPane.add(backgrndLabel, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(forgroundPanel, JLayeredPane.PALETTE_LAYER);
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(new JScrollPane(new JTextArea("Output", 10, 40)));
add(layeredPane);
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("LayeredPaneFun");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LayeredPaneFun());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I start off by creating a JTextArea of a specific size. The user can add text within it but it will get cut off if it becomes too long (vertically or horizontally). I want the JTextArea to automatically expand or contract (for deletion of text).
I may allow users to change font and font size in the future, so it would be good if I could avoid making things increase/decrease by a certain size.
I am currently using bounds to size my JTextArea. Perhaps I should size by rows and columns and use a listener and act appropriately?
thanks in advance!
I can't imagine why you'd want to do this, why not put a JTextArea in a JScrollPane, but ok, i'll play along... Maybe something like this:
import java.awt.Container;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
public class Expander extends JFrame {
private final JTextArea area;
private int hSize = 1;
private int vSize = 1;
public Expander() {
Container cp = getContentPane();
cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
cp.add(Box.createHorizontalGlue());
area = new JTextArea(vSize, hSize);
cp.add(area);
cp.add(Box.createHorizontalGlue());
area.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
adjust();
}
#Override
public void removeUpdate(DocumentEvent e) {
adjust();
}
#Override
public void changedUpdate(DocumentEvent e) {
adjust();
}
});
pack();
}
private void adjust() {
int maxColumns = getMaxColumns();
if ((area.getLineCount() != vSize) || (maxColumns != hSize)) {
hSize = maxColumns;
vSize = area.getLineCount();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
area.setColumns(hSize);
area.setRows(vSize);
Expander.this.doLayout();
Expander.this.pack();
}
});
}
}
private int getMaxColumns() {
int startOffset = 0;
int maxColumns = 0;
for (int i = 0; i < area.getLineCount(); i++) {
try {
int endOffset = area.getLineEndOffset(i);
int lineSize = endOffset - startOffset;
if (lineSize > maxColumns) {
maxColumns = lineSize;
}
startOffset = endOffset;
} catch (BadLocationException ble) {
}
}
return maxColumns;
}
public static void main(String[] args) {
Expander e = new Expander();
e.setLocationRelativeTo(null);
e.setVisible(true);
}
}
I second the advice to simply put the JTextArea in a JScrollPane and let this take care of extra text. Also and perhaps most importantly, don't set the bounds of the JTextArea because if you do this, you constrain it to be a certain size and that's not what you want to have happen. Instead initialize your JTextArea with two int constants to represent the number of rows and columns that should be visualized and then place it in a JScrollPane. Also be sure to read up on using the layout managers so you can avoid setting the size of your JScrollPane too!
Edit: on testing, it seems that setPreferredSize is more dangerous to a JTextArea than setSize.
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class ConstrainedTextArea extends JPanel {
private JTextArea textArea1, textArea2, textArea3;
public ConstrainedTextArea() {
textArea1 = new JTextArea(20, 30);
textArea2 = new JTextArea();
textArea3 = new JTextArea();
textArea2.setPreferredSize(new Dimension(300, 300));
textArea3.setSize(textArea3.getPreferredSize());
setLayout(new GridLayout(1, 0));
add(new JScrollPane(textArea1));
add(new JScrollPane(textArea2));
add(new JScrollPane(textArea3));
}
private static void createAndShowUI() {
JFrame frame = new JFrame("ConstrainedTextArea");
frame.getContentPane().add(new ConstrainedTextArea());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
also, see GrowingTextAreaExample