Java JTextPane + JScrollPane: de/activate automatic scrolling - java

I'm currently writing a simple chat in Java and currently I'm stuck on this problem:
I want my output JTextPane to behave like you would expect it to from a good chat, ie by default the text scrolls automatically when new text arrives (using outputfield.setCaretPosition(outputdocument.getLength())), but when the user scrolls up this should be disabled and of course re-enabled when the user scrolls to the bottom again.
I tried toying around with the ScrollBars and all, but I can't seem to find a way to detect whether the ScrollBar is at the bottom or not.
I create the scrollable output area simply by creating a JTextPane, a JScrollPane and put one into the other.
JTextPane outputpane = new JTextPane
...
JScrollPane outputscroll = new JScrollPane(outputpane);
outputscroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Edit: Here's the code I use to create the components and display new messages:
// lots of imports
public class RoomFrame extends JFrame implements ListSelectionListener, ActionListener, Comparable, Runnable
{
public static final String DEFAULT_FONT = "Courier";
public static final int DEFAULT_FONT_SIZE = 12;
private JTextPane mOutputField;
private JScrollPane mOutputScroll;
private StyledDocument mOutputDocument;
public RoomFrame(...)
{
super(...);
createGUI();
setOutputStyles();
setVisible(true);
new Thread(this).start();
}
// ========================================================
private void createGUI()
{
Color borderhighlightouter = new Color(220, 220, 220);
Color borderhighlightinner = new Color(170, 170, 170);
Color bordershadowouter = new Color(120, 120, 120);
Color bordershadowinner = new Color(170, 170, 170);
setLayout(new GridBagLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(500, 400);
// -----------------------------
// Output
mOutputField = new JTextPane();
mOutputField.setEditable(false);
mOutputField.setBackground(new Color(245, 245, 245));
mOutputDocument = mOutputField.getStyledDocument();
mOutputScroll = new JScrollPane(mOutputField);
mOutputScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
mOutputScroll.setPreferredSize(new Dimension(250, 250));
mOutputScroll.setMinimumSize(new Dimension(50, 50));
mOutputScroll.setOpaque(false);
mOutputScroll.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 1, 0), BorderFactory.createBevelBorder(BevelBorder.LOWERED, borderhighlightouter, borderhighlightinner, bordershadowouter, bordershadowinner)));
getContentPane().add(mOutputScroll);
}
private void setOutputStyles()
{
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
Style regular = mOutputDocument.addStyle("regular", def);
StyleConstants.setFontFamily(def, DEFAULT_FONT);
StyleConstants.setFontSize(def, DEFAULT_FONT_SIZE);
StyleConstants.setFirstLineIndent(def, 100.0f);
Style nickname = mOutputDocument.addStyle("username", def);
StyleConstants.setBold(nickname, true);
StyleConstants.setForeground(nickname, new Color(50, 50, 220));
Style highlight = mOutputDocument.addStyle("highlight", def);
StyleConstants.setBold(highlight, true);
StyleConstants.setBackground(highlight, new Color(150, 0, 0));
Style join = mOutputDocument.addStyle("join", def);
StyleConstants.setBold(join, true);
StyleConstants.setForeground(join, new Color(20, 100, 20));
Style leave = mOutputDocument.addStyle("leave", def);
StyleConstants.setBold(leave, true);
StyleConstants.setForeground(leave, new Color(100, 100, 20));
Style topic = mOutputDocument.addStyle("topic", def);
StyleConstants.setBold(topic, true);
StyleConstants.setUnderline(topic, true);
Style error = mOutputDocument.addStyle("error", def);
StyleConstants.setBold(error, true);
StyleConstants.setForeground(error, new Color(255, 0, 0));
Style kick = mOutputDocument.addStyle("kick", def);
StyleConstants.setBold(kick, true);
StyleConstants.setForeground(kick, new Color(150, 0, 0));
}
private final boolean shouldScroll()
{
int min = mOutputScroll.getVerticalScrollBar().getValue() + mOutputScroll.getVerticalScrollBar().getVisibleAmount();
int max = mOutputScroll.getVerticalScrollBar().getMaximum();
return min == max;
}
// ========================================================
public void displayMessage(String message)
{
displayMessage(message, "");
}
public void displayMessage(String message, String style)
{
displayMessage(message, style, true);
}
public void displayMessage(String message, String style, boolean addnewline)
{
String newline = (addnewline ? "\n" : "");
style = (style.equals("") ? "regular" : style);
message = message.replace("\n", " ");
// check for highlight
try
{
mOutputDocument.insertString(mOutputDocument.getLength(),
String.format("%s%s", message, newline),
mOutputDocument.getStyle(style));
}
catch (Exception e) {}
// if (shouldScroll())
// mOutputField.setCaretPosition(mOutputDocument.getLength());
}
public void run()
{
while (true)
{
if (shouldScroll())
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
mOutputScroll.getVerticalScrollBar().setValue(mOutputScroll.getVerticalScrollBar().getMaximum());
}
});
}
try { Thread.sleep(500); }
catch (InterruptedException e) { break; }
}
}
public void valueChanged(ListSelectionEvent event)
{
}
public void actionPerformed(ActionEvent event)
{
}
public final int compareTo(Object o) { return this.toString().compareTo(o.toString()); }
}
Edit: Thanks to fireshadow52's link to another similar question I finally got it to work exactly how I want it to:
private boolean isViewAtBottom()
{
JScrollBar sb = mOutputScroll.getVerticalScrollBar();
int min = sb.getValue() + sb.getVisibleAmount();
int max = sb.getMaximum();
System.out.println(min + " " + max);
return min == max;
}
private void scrollToBottom()
{
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
mOutputScroll.getVerticalScrollBar().setValue(mOutputScroll.getVerticalScrollBar().getMaximum());
}
});
}
public void displayMessage(String message, String style, boolean prependnewline)
{
String newline = (prependnewline ? "\n" : "");
boolean scroll = isViewAtBottom() && prependnewline;
style = (style.equals("") ? "regular" : style);
message = message.replace("\n", " ");
try
{
mOutputDocument.insertString(mOutputDocument.getLength(),
String.format("%s%s", newline, message),
mOutputDocument.getStyle(style));
}
catch (Exception e) {}
if (scroll)
scrollToBottom();
}
Again, thanks for all your help!

If you're only wanting to scroll when you're at the bottom then this should help.
Use this method to check and see if the scrollbar is at the end (or bottom), and if so, scroll down automatically using setCaretPosition(Component.getDocument().getLength());:
public boolean shouldScroll() {
int minimumValue = scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount();
int maximumValue = scrollPane.getVerticalScrollBar().getMaximum();
return maximumValue == minimumValue;
}
I found similar results when using Google which led me to a method similar to this one which worked as requested.
Edit: Make sure that it is done within invokeLater() as it needs to be updated before scrolling is done.
A full example of what I use:
public class ScrollTest extends Thread {
private JFrame frame;
private JTextArea textArea;
private JScrollPane scrollPane;
public static void main(String[] arguments) {
new ScrollTest().run();
}
public ScrollTest() {
textArea = new JTextArea(20, 20);
scrollPane = new JScrollPane(textArea);
frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
public void run() {
while (true) {
textArea.append("" + Math.random() + "\n");
if (shouldScroll()) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
}
});
}
try {
Thread.sleep(500);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
public boolean shouldScroll() {
int minimumValue = scrollPane.getVerticalScrollBar().getValue() + scrollPane.getVerticalScrollBar().getVisibleAmount();
int maximumValue = scrollPane.getVerticalScrollBar().getMaximum();
return maximumValue == minimumValue;
}
}

JScrollBar has getValue() method. Just warp it in SwingUtilities.invokeLater() to be called after text appending.

You can use an AdjustmentListener to condtion scrolling, as shown in this example.

Related

Search same colors (RGB) in same position (i, j) from different arrays (3 array) and lock it

I made a simple learning program to create 3 Array, put JPanel into it, and then give random color for each (each Array have its own "randomizer" JtoggleButton)
For learning continuation, I am thinking of creating 1 more button to search the same colors in same position from that Arrays like array1 [0][0] (r, g, b) = array2 [0][0] (r, g, b), and then lock it (so the loop can't revalidate its color).
My questions are:
Is it possible to lock only a position of array like array [0][9]?
I think I should make the randomizing loops synchronize first, is
that methodically right?
If it is possible, from where should I start to build it?
It is not a question but, please give me instigation if I make unnecessary "// copy method" except for the JToggleButtons.
P.S. the only question like this is How to check two array list are same content in same position, which is maybe the next step for the method, others are in different language and I don't think it has a same issue.
The code:
Main:
public class Main {
private static void createMainFrame() {
new Window().initMainFrame();
}
#SuppressWarnings("Convert2Lambda")
public static void main (String [] args) {
SwingUtilities.invokeLater (new Runnable() {
#Override
public void run() {
createMainFrame();
}
});
}
}
Window:
public class Window {
public void initMainFrame() {
Container container = mainFrame.getContentPane();
container.setLayout(null);
}
private static void createBlocks1() {
new Blocks().initBlocks1();
}
// createBlocks2
// createBlocks3
public static JFrame mainFrame = new JFrame("learning 43");
public static JPanel viewerBoard1 = new JPanel();
// viewerBoard2
// viewerBoard3
public static JToggleButton randomize1 = new JToggleButton("RANDOMIZER");
// randomize2
// randomize3
#SuppressWarnings("Convert2Lambda")
public Window() {
initMainFrame();
mainFrame.setSize(676,357);
mainFrame.setLocationRelativeTo(null);
mainFrame.setResizable(false);
mainFrame.setAlwaysOnTop(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
mainFrame.add(viewerBoard1);
viewerBoard1.setBounds(15, 15, 200, 200);
viewerBoard1.setBackground(new Color(222, 222, 222));
viewerBoard1.setVisible(true);
// viewerBoard2
// viewerBoard3
JPanel viewerPanel1 = new JPanel();
mainFrame.add(viewerPanel1);
viewerPanel1.setBounds(10, 10, 210, 210);
viewerPanel1.setBackground(new Color(111, 111, 111));
viewerPanel1.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
viewerPanel1.setVisible(true);
// viewerpanel2
// viewerpanel3
mainFrame.add(randomize1);
randomize1.setFocusPainted(false);
randomize1.setRolloverEnabled(true);
randomize1.setForeground(Color.GRAY);
randomize1.setFont(new Font("Courier", Font.BOLD, 16));
randomize1.setMargin(new Insets(0, 0, 0, 0));
randomize1.setBounds(10, 230, 210, 90);
randomize1.setVisible(true);
randomize1.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent randomEvent) {
if (randomEvent.getStateChange() == ItemEvent.SELECTED){
System.out.println("Randomize Button 1 selected: " + randomize1.isSelected());
System.out.println("randomizing panel 1...");
while (randomize1.isSelected()) {
createBlocks1();
break;
}
}
if (randomEvent.getStateChange() == ItemEvent.DESELECTED){
System.out.println("Randomize Button 1 deselcted!");
System.out.println("eraseing panel 1...");
viewerBoard1.removeAll();
viewerBoard1.revalidate();
viewerBoard1.repaint();
}
}
});
// randomize2
// randomize3
}
}
Blocks:
public class Blocks {
public void initBlocks1() {
BlockThread1 thread1 = new BlockThread1();
thread1.start();
}
// initBlocks2
// initBlocks3
Container container = Window.viewerBoard1;
JPanel [][] blocksArray1 = new JPanel[4][4];
JPanel colsPanel;
JPanel rowsPanel;
Random random1 = new Random();
private Color RColor1() {
return new Color(random1.nextInt(255), random1.nextInt(255), random1.nextInt(255)/*, random.nextInt(255)*/);
}
class BlockThread1 extends Thread {
#Override
public void run(){
container.setLayout(new GridLayout(4, 4));
do {
try {
for (int cols1 = 0; cols1 < blocksArray1.length; cols1++) {
colsPanel = new JPanel();
colsPanel.setBackground(RColor1());
Window.viewerBoard1.revalidate();
Window.viewerBoard1.add(colsPanel);
for (int rows1 = 1; rows1 < blocksArray1[cols1].length; rows1++) {
rowsPanel = new JPanel();
rowsPanel.setBackground(RColor1());
Window.viewerBoard1.revalidate();
Window.viewerBoard1.add(rowsPanel);
}
}
Thread.sleep(1000);
Window.viewerBoard1.removeAll();
Window.viewerBoard1.revalidate();
Window.viewerBoard1.repaint();
}
catch (InterruptedException ex) {
java.util.logging.Logger.getLogger(Window.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
} while (Window.randomize1.isSelected());
}
}
// blocksArray2
// blocksArray3
}

How to implement an actionListener for space bar as action event

I have this set up to update pretty constantly on the timer, but I want to be able to pause the timer with the spacebar. I have attempted to implement an actionListener, but I am not sure what to apply it to. Most of the examples I can find relate to buttons or text boxes, not keyboard presses inside a jpanel. I have printed src to the console and it doesn't appear to be registering my spacebar as an event... I have tried adding the actionListener, but I am not getting something about the syntax. Any help would be appreciated.
public class Arena extends JFrame {
private PaintPanel paintPanel;
public Arena() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setMinimumSize(new Dimension(1000, 720));
paintPanel = new PaintPanel();
getContentPane().add(paintPanel, BorderLayout.CENTER);
paintPanel.setBackground(Color.black);
paintPanel.setFocusable(true);
//paintPanel.addActionListener(this);
pack();
paintPanel.initGame();
}
class PaintPanel extends JPanel implements ActionListener {
private List<Gladiator> gladiators;
private Timer timer;
private Ai AI;
private Load loadObject;
public void initGame() {
timer = new Timer(500, this);
timer.start();
AI = new Ai(gladiators);
loadObject = new Load();
}
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
System.out.println("************* "+src);
// if (src == spacebar) {
// } else if (src = timer) {
AI.runAI();
try {
Thread.sleep(100);
System.out.println("sleeping");
} catch (InterruptedException d) {
System.err.println("Caught : InterruptedException" + d.getMessage());
}
repaint();
// }
}
public PaintPanel(){
super();
gladiators = new ArrayList<Gladiator>();
String[][] gladiatorInfo = new String[100][25];
String[] gladiatorRaw = new String[100];
String[][] parsedInfo = new String[250][100];
Gladiator[] gladiator = new Gladiator[20];
int[] matchInfo = new int[3];
int numberofcontestants = 0;
gladiatorRaw = loadObject.getGladiators(gladiatorRaw);
parsedInfo = loadObject.parseStats(gladiatorRaw);
Venue venue = new Venue();
matchInfo = loadObject.getMatchSettings(matchInfo);
venue.populateVenue(matchInfo);
gladiator = createGladiators(venue);
for (int a = 0; a < venue.contestants; a++) {
System.out.println("Populating Gladiator "+a);
gladiator[a].populategladiators(parsedInfo,a);
gladiator[a].getEquipment();
gladiator[a].contestantNumber = a;
gladiators.add(gladiator[a]);
}
}
public Gladiator[] createGladiators(Venue venue) {
int[][] initialPlacement = new int[20][2];
Gladiator[] gladiator = new Gladiator[(venue.contestants)];
initialPlacement = loadObject.loadInitialPlacement(venue.contestants);
for (int a = 0; a < venue.contestants; a++) {
System.out.println("Add gladiator "+a);
gladiator[a] = new Gladiator(initialPlacement[a][0],initialPlacement[a][1]);
System.out.println(initialPlacement[a][0]+","+initialPlacement[a][1]);
}
return gladiator;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
try {
BufferedImage background = ImageIO.read(new File("background.png"));
g.drawImage(background,0,0,this);
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
}
for (Gladiator s : gladiators){
s.draw(g2);
}
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
Arena gamePanel = new Arena();
gamePanel.setVisible(true);
}
});
}
}
Also, is there a getEvent() key code for the spacebar? Can't seem to find one. Thanks
You should use the key bindings API
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space");
am.put("space", new AbstractAction() {
public void actionPerformed(ActionEvent evt) {
if (timer.isRunning()) {
timer.stop();
} else {
timer.start();
}
}
});
The InputMap/ActionMap can be applied to any component that extends from JComponent, but in your case, I'd suggest attaching it to your PaintPane

Keeping the correct style on text retrieval

I am making an application similar to a chat. For that purpose I have two JTextPanes, one where I'm writing and one that displays messages. This is the code that handles the transferring of text from input to display :
String input = textPane.getText();
if(!input.endsWith("\n")){
input+="\n";
}
StyledDocument doc = displayPane.getStyledDocument();
int offset = displayPane.getCaretPosition();
textPane.setText("");
try {
doc.insertString(offset, input, set);
} catch (BadLocationException ex) {
Logger.getLogger(ChatComponent.class.getName()).log(Level.SEVERE, null, ex);
}
The problem is that if i have colour on some words of the input text , the output is all coloured . So the colour is applied to all of the text when moved to display(while displayed correctly on input). Any suggestions on how i can move text properly?
Notice that same happens with other format as bold , italic etc
The text is already formatted on the input JTextPane . What i need to do
is transfer it as it is on a different JTextPane without having to check
the different style options
example
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class Fonts implements Runnable {
private String[] fnt;
private JFrame frm;
private JScrollPane jsp;
private JTextPane jta;
private int width = 450;
private int height = 300;
private GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
private StyledDocument doc;
private MutableAttributeSet mas;
private int cp = 0;
private Highlighter.HighlightPainter cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.cyan);
private Highlighter.HighlightPainter redPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.red);
private Highlighter.HighlightPainter whitePainter = new DefaultHighlighter.DefaultHighlightPainter(Color.white);
private int _count = 0;
private int _lenght = 0;
public Fonts() {
jta = new JTextPane();
doc = jta.getStyledDocument();
jsp = new JScrollPane(jta);
jsp.setPreferredSize(new Dimension(height, width));
frm = new JFrame("awesome");
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setLayout(new BorderLayout());
frm.add(jsp, BorderLayout.CENTER);
frm.setLocation(100, 100);
frm.pack();
frm.setVisible(true);
jta.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
fnt = ge.getAvailableFontFamilyNames();
mas = jta.getInputAttributes();
new Thread(this).start();
}
#Override
public void run() {
for (int i = 0; i < fnt.length; i++) {
StyleConstants.setBold(mas, false);
StyleConstants.setItalic(mas, false);
StyleConstants.setFontFamily(mas, fnt[i]);
StyleConstants.setFontSize(mas, 16);
dis(fnt[i]);
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
StyleConstants.setBold(mas, true);
dis(fnt[i] + " Bold");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
StyleConstants.setItalic(mas, true);
dis(fnt[i] + " Bold & Italic");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
StyleConstants.setBold(mas, false);
dis(fnt[i] + " Italic");
try {
Thread.sleep(75);
} catch (Exception e) {
e.printStackTrace();
}
}
jta.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public void dis(String s) {
_count++;
_lenght = jta.getText().length();
try {
doc.insertString(cp, s, mas);
doc.insertString(cp, "\n", mas);
} catch (Exception bla_bla_bla_bla) {
bla_bla_bla_bla.printStackTrace();
}
if (_count % 2 == 0) {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, cyanPainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
} else if (_count % 3 == 0) {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, redPainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
} else {
try {
jta.getHighlighter().addHighlight(1, _lenght - 1, whitePainter);
} catch (BadLocationException bla_bla_bla_bla) {
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Fonts fs = new Fonts();
}
});
}
}
In the absence of a good SSCCE, I really don't know how you adding colour to the text on your JTextPane, but hopefully this method might sort things out for you :
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
private void appendToTextPane(String name, Color c, String f)
{
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);
aset = sc.addAttribute(aset, StyleConstants.FontFamily, f);
int len = Client.nPane.getDocument().getLength();
textPane.setCaretPosition(len);
textPane.setCharacterAttributes(aset, true);
textPane.replaceSelection(name);
}
With this you can give a different Color and Font to each String literal that will be added to your JTextPane.
Hope this new Code might help you in some way :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
public class TextPaneTest extends JFrame
{
private JPanel topPanel;
private JPanel bottomPanel;
private JTextPane tPane1;
private JTextPane tPane2;
private JButton button;
public TextPaneTest()
{
topPanel = new JPanel();
topPanel.setLayout(new GridLayout(1, 2));
bottomPanel = new JPanel();
bottomPanel.setBackground(Color.BLACK);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.BLUE);
aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console");
tPane1 = new JTextPane();
tPane1.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
tPane1.setCharacterAttributes(aset, false); // Add these settings to the other JTextPane also
tPane2 = new JTextPane();
tPane2.setCharacterAttributes(aset, false); // Mimic what the other JTextPane has
button = new JButton("ADD TO THE TOP JTEXTPANE");
button.setBackground(Color.DARK_GRAY);
button.setForeground(Color.WHITE);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
tPane1.setText(tPane2.getText());
}
});
add(topPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
topPanel.add(tPane1);
topPanel.add(tPane2);
bottomPanel.add(button);
pack();
tPane2.requestFocusInWindow();
setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new TextPaneTest();
}
});
}
}
Regards
This has been solved by merging the document models of the two panes. The solution is in this question: Keeping the format on text retrieval

Update JLabel every X seconds from ArrayList<List> - Java

I have a simple Java program that reads in a text file, splits it by " " (spaces), displays the first word, waits 2 seconds, displays the next... etc... I would like to do this in Spring or some other GUI.
Any suggestions on how I can easily update the words with spring? Iterate through my list and somehow use setText();
I am not having any luck. I am using this method to print my words out in the consol and added the JFrame to it... Works great in the consol, but puts out endless jframe. I found most of it online.
private void printWords() {
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel(w.name,SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
I have a window that get's created with JFrame and JLable, however, I would like to have the static text be dynamic instead of loading a new spring window. I would like it to flash a word, disappear, flash a word disappear.
Any suggestions on how to update the JLabel? Something with repaint()? I am drawing a blank.
Thanks!
UPDATE:
With the help from the kind folks below, I have gotten it to print correctly to the console. Here is my Print Method:
private void printWords() {
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
However, it isn't updating the lable? My contructor looks like:
public TimeThis() {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
//_textField.setText("loading...");
}
Getting there... I'll post the fix once I, or whomever assists me, get's it working. Thanks again!
First, build and display your GUI. Once the GUI is displayed, use a javax.swing.Timer to update the GUI every 500 millis:
final Timer timer = new Timer(500, null);
ActionListener listener = new ActionListsner() {
private Iterator<Word> it = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (it.hasNext()) {
label.setText(it.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
Never use Thread.sleep(int) inside Swing Code, because it blocks the EDT; more here,
The result of using Thread.sleep(int) is this:
When Thread.sleep(int) ends
Example code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import javax.swing.*;
//http://stackoverflow.com/questions/7943584/update-jlabel-every-x-seconds-from-arraylistlist-java
public class ButtonsIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private Queue<Icon> iconQueue = new LinkedList<Icon>();
private JLabel label = new JLabel();
private Random random = new Random();
private JPanel buttonPanel = new JPanel();
private JPanel labelPanel = new JPanel();
private Timer backTtimer;
private Timer labelTimer;
private JLabel one = new JLabel("one");
private JLabel two = new JLabel("two");
private JLabel three = new JLabel("three");
private final String[] petStrings = {"Bird", "Cat", "Dog",
"Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"};
private boolean runProcess = true;
private int index = 1;
private int index1 = 1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ButtonsIcon t = new ButtonsIcon();
}
});
}
public ButtonsIcon() {
iconQueue.add(UIManager.getIcon("OptionPane.errorIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.informationIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.warningIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.questionIcon"));
one.setFont(new Font("Dialog", Font.BOLD, 24));
one.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
two.setFont(new Font("Dialog", Font.BOLD, 24));
two.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
three.setFont(new Font("Dialog", Font.BOLD, 10));
three.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
labelPanel.setLayout(new GridLayout(0, 3, 4, 4));
labelPanel.add(one);
labelPanel.add(two);
labelPanel.add(three);
//labelPanel.setBorder(new LineBorder(Color.black, 1));
labelPanel.setOpaque(false);
JButton button0 = createButton();
JButton button1 = createButton();
JButton button2 = createButton();
JButton button3 = createButton();
buttonPanel.setLayout(new GridLayout(0, 4, 4, 4));
buttonPanel.add(button0);
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
//buttonPanel.setBorder(new LineBorder(Color.black, 1));
buttonPanel.setOpaque(false);
label.setLayout(new BorderLayout());
label.add(labelPanel, BorderLayout.NORTH);
label.add(buttonPanel, BorderLayout.SOUTH);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
label.setPreferredSize(new Dimension(d.width / 3, d.height / 3));
add(label, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
startBackground();
startLabel2();
new Thread(this).start();
printWords(); // generating freeze Swing GUI durring EDT
}
private JButton createButton() {
JButton button = new JButton();
button.setBorderPainted(false);
button.setBorder(null);
button.setFocusable(false);
button.setMargin(new Insets(0, 0, 0, 0));
button.setContentAreaFilled(false);
button.setIcon(nextIcon());
button.setRolloverIcon(nextIcon());
button.setPressedIcon(nextIcon());
button.setDisabledIcon(nextIcon());
nextIcon();
return button;
}
private Icon nextIcon() {
Icon icon = iconQueue.peek();
iconQueue.add(iconQueue.remove());
return icon;
}
// Update background at 4/3 Hz
private void startBackground() {
backTtimer = new javax.swing.Timer(750, updateBackground());
backTtimer.start();
backTtimer.setRepeats(true);
}
private Action updateBackground() {
return new AbstractAction("Background action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(new ImageIcon(getImage()));
}
};
}
// Update Label two at 2 Hz
private void startLabel2() {
labelTimer = new javax.swing.Timer(500, updateLabel2());
labelTimer.start();
labelTimer.setRepeats(true);
}
private Action updateLabel2() {
return new AbstractAction("Label action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
two.setText(petStrings[index]);
index = (index + 1) % petStrings.length;
}
};
}
// Update lable one at 3 Hz
#Override
public void run() {
while (runProcess) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
one.setText(petStrings[index1]);
index1 = (index1 + 1) % petStrings.length;
}
});
try {
Thread.sleep(300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// Note: blocks EDT
private void printWords() {
for (int i = 0; i < petStrings.length; i++) {
String word = petStrings[i].toString();
System.out.println(word);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
three.setText(word);
}
three.setText("<html> Concurency Issues in Swing<br>"
+ " never to use Thread.sleep(int) <br>"
+ " durring EDT, simple to freeze GUI </html>");
}
public BufferedImage getImage() {
int w = label.getWidth();
int h = label.getHeight();
GradientPaint gp = new GradientPaint(0f, 0f, new Color(
127 + random.nextInt(128),
127 + random.nextInt(128),
127 + random.nextInt(128)),
w, w,
new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
g2d.setColor(Color.BLACK);
return bi;
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.*;
class TimeThis extends JFrame {
private static final long serialVersionUID = 1L;
private ArrayList<Word> words;
private JTextField _textField; // set by timer listener
public TimeThis() throws IOException {
_textField = new JTextField(5);
_textField.setEditable(false);
_textField.setFont(new Font("sansserif", Font.PLAIN, 30));
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(_textField);
this.setContentPane(content);
this.setTitle("Swing Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setResizable(false);
_textField.setText("loading...");
readFile(); // read file
printWords(); // print results
}
public void readFile(){
try {
BufferedReader in = new BufferedReader(new FileReader("adameve.txt"));
words = new ArrayList<Word>();
int lineNum = 1; // we read first line in start
// delimeters of line in this example only "space"
char [] parse = {' '};
String delims = new String(parse);
String line = in.readLine();
String [] lineWords = line.split(delims);
// split the words and create word object
//System.out.println(lineWords.length);
for (int i = 0; i < lineWords.length; i++) {
Word w = new Word(lineWords[i]);
words.add(w);
}
lineNum++; // pass the next line
line = in.readLine();
in.close();
} catch (IOException e) {
}
}
private void printWords() {
final Timer timer = new Timer(100, null);
ActionListener listener = new ActionListener() {
private Iterator<Word> w = words.iterator();
#Override
public void actionPerformed(ActionEvent e) {
if (w.hasNext()) {
_textField.setText(w.next().getName());
//Prints to Console just Fine...
//System.out.println(w.next().getName());
}
else {
timer.stop();
}
}
};
timer.addActionListener(listener);
timer.start();
}
class Word{
private String name;
public Word(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) throws IOException {
JFrame ani = new TimeThis();
ani.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ani.setVisible(true);
}
}
I got it working with this code... Hope it can help someone else expand on their Java knowledge. Also, if anyone has any recommendations on cleaning this up. Please do so!
You're on the right track, but you're creating the frame's inside the loop, not outside. Here's what it should be like:
private void printWords() {
JFrame frame = new JFrame("Run Text File");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel textLabel = new JLabel("", SwingConstants.CENTER);
textLabel.setPreferredSize(new Dimension(300, 100));
frame.getContentPane().add(textLabel, BorderLayout.CENTER);
//Display the window. frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
for (int i = 0; i < words.size(); i++) {
//How many words?
//System.out.print(words.size());
//print each word on a new line...
Word w = words.get(i);
System.out.println(w.name);
//pause between each word.
try{
Thread.sleep(500);
}
catch(InterruptedException e){
e.printStackTrace();
}
textLabel.setTest(w.name);
}
}

Swing rendering problem of busy cursors when using modal dialogs on Linux

When setting a busy cursor on the glass pane of the application frame after closing a modal dialog, the busy cursor is not always displayed. Sometimes it works (the first time it is mostly always working), sometimes not.
Even better, when setting the busy cursor before opening the dialog. The busy cursor get displayed but when moving the mouse inside and then outside the dialog the busy cursor is not displayed anymore.
Note that I observe the following bug on Linux only. On Mac OS X or Windows the behavior is deterministic and consistent.
Another hint, in the first case of the code sample, when the mouse is NOT entering the dialog and the YES_OPTION is selected using the keyboard, the busy mouse cursor is always shown. Also in this case, the "Please wait..." label on the glass pane get never painted.
Here a SSCCE demonstrating these bugs:
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame {
private JPanel panel;
private JPanel glassPane;
public TestFrame() {
final JButton button1 = new JButton(new AbstractAction("Start activity indicator after closing the dialog") {
#Override
public void actionPerformed(ActionEvent e) {
doAction1();
}
});
final JButton button2 = new JButton(new AbstractAction("Start activity indicator before opening the dialog") {
#Override
public void actionPerformed(ActionEvent e) {
doAction2();
}
});
panel = new JPanel();
panel.add(button1);
panel.add(button2);
getContentPane().add(panel, BorderLayout.NORTH);
glassPane = (JPanel) getGlassPane();
glassPane.setLayout(new BorderLayout());
glassPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
glassPane.add(new JLabel("Please Wait..."), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setVisible(true);
}
public void doAction1() {
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity();
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
stopActivity();
}
}
public void doAction2() {
startActivity();
System.out.println("IsStartingInEDT?: "+ SwingUtilities.isEventDispatchThread());
final int response = JOptionPane.showConfirmDialog(this, "Move the mouse inside the dialog (me) and then outside, the busy indicator is not shown anymore");
if (JOptionPane.YES_OPTION == response) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopActivity();
}
public void startActivity() {
System.out.println("TestFrame.startActivity()");
glassPane.setVisible(true);
}
public void stopActivity() {
System.out.println("TestFrame.stopActivity()");
glassPane.setVisible(false);
}
/**
* #param args
*/
public static void main(String[] args) {
new TestFrame();
}
}
At the moment I did not find any related issues in the JavaBug parade. I will search further before opening a new one.
I also already read the following article but it is not very convenient as making a good modal dialog from a non-modal one is not straightforward:
http://www.javaspecialists.eu/archive/Issue065.html
Can anyone provide some help?
Thanks in advance, Pierre
You have some threading issue here.
Is IsStartingInEDT true?
If yes, you are doing it wrong because:
You should not sleep in UI thread. This would stop the screen update.
If no, you are doing it wrong because:
OptionPane.showConfirmDialog() must be called from the UI thread.
you should do something like this:
public void doAction1() {
if (!SwingUtilities.isEventDispatchThread()) {
System.err.println("error, must be edt");
return;
}
final int response = JOptionPane.showConfirmDialog(this, "Click on the YES_OPTION, busy indicator must start (if it does, try again).");
if (JOptionPane.YES_OPTION == response) {
startActivity(); // change glass panel in edt
// new thread for long standing task
new Thread( new Runnable() { public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
SwingUtilities.invokeAndWait(new Runnable(){ public void run() {
// changing glass panel need edt
stopActivity();
});
}).start();
}
}
1st. by using Tread.sleep(int) pretty sure to block EDT, with all issues desribed about Concurrency in Swing
2.nd works because initializations for JOptionPane create a new EDT
here is simple demonstrations about ...., please that only example and be sure that is against all Swing rules, but demostrated lock and unlock EDT by usage Tread.sleep(int) during EDT
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class ShakeComponents1 {
private JFrame frame = new JFrame();
private final String items[] = {"One", "Two", "Three"};
private Timer timer;
private JPanel panel = new JPanel();
private JPanel buttonPanel = new JPanel();
private JButton button = new JButton(" Exit ");
private boolean repeats = true;
private boolean runs = false;
private Color clr[] = {Color.red, Color.blue, Color.magenta};
private Insets initMargin;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ShakeComponents1().makeUI();
}
});
}
public void makeUI() {
buttonPanel = new JPanel();
buttonPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
buttonPanel.setLayout(new BorderLayout());
button.setPreferredSize(new Dimension(100, 45));
button.setForeground(Color.darkGray);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
Runnable doRun = new Runnable() {
#Override
public void run() {
System.exit(0);
}
};
SwingUtilities.invokeLater(doRun);
}
});
button.addMouseListener(new java.awt.event.MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
if (runs) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runs = false;
timer.stop();
changePnlBorder(new EmptyBorder(5, 5, 5, 5));
changeBtnForegroung(Color.darkGray);
}
});
}
}
#Override
public void mouseExited(MouseEvent e) {
if (!runs) {
timer.start();
runs = true;
}
}
});
buttonPanel.add(button);
final Insets margin = button.getMargin();
panel.add(buttonPanel);
for (int i = 0; i < 2; i++) {
JComboBox combo = new JComboBox(items);
combo.setMinimumSize(new Dimension(50, 25));
combo.setMaximumSize(new Dimension(150, 25));
combo.setPreferredSize(new Dimension(100, 25));
combo.addActionListener(new ShakeAction());
panel.add(combo);
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocation(50, 50);
frame.setVisible(true);
timer = new Timer(500, new ShakeAction());
timer.setRepeats(repeats);
initMargin = button.getMargin();
}
private class ShakeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private int noColor = 0;
private Border border;
private int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
if (count > 5) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
changeBtnForegroung(Color.darkGray);
Thread.sleep(500);
count = 0;
Thread.sleep(750);
} catch (Exception e) {
System.out.println(e);
}
}
}).start();
} else {
new Thread(new Runnable() {
#Override
public void run() {
try {
runs = true;
if (noColor < 2) {
noColor++;
changeBtnForegroung(clr[noColor]);
} else {
noColor = 0;
changeBtnForegroung(clr[noColor]);
}
changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10));
border = new EmptyBorder(0, 5, 10, 5);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10));
border = new EmptyBorder(0, 0, 10, 10);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left + 10, initMargin.bottom, initMargin.right - 10));
border = new EmptyBorder(5, 10, 5, 0);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left - 10, initMargin.bottom, initMargin.right + 10));
border = new EmptyBorder(10, 10, 0, 0);
changePnlBorder(border);
Thread.sleep(100);
changeBtnMargin(new Insets(initMargin.top, initMargin.left, initMargin.bottom, initMargin.right));
border = new EmptyBorder(5, 5, 5, 5);
changePnlBorder(border);
Thread.sleep(100);
count++;
} catch (Exception e) {
System.out.println(e);
}
}
}).start();
}
}
}
private void changePnlBorder(final Border b) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
buttonPanel.setBorder(b);
buttonPanel.revalidate();
buttonPanel.repaint();
}
});
}
private void changeBtnForegroung(final Color c) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setForeground(c);
}
});
}
private void changeBtnMargin(final Insets margin) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
button.setMargin(margin);
}
});
}
}
conclusion -> you can create new Thread as BackGroung Task(s) wrapped into Runnable, if you wnat to simulate LongRunning Task and with Thread.sleep(int), maybe answer to your question is here
sure correct way would be by using SwingWorker for that, with Thread.sleep(int) too

Categories