I would like to develop a Swing application that may contain text field which will act like Terminal (the console from Unix/Linux systems).
Whenever a user entered a command, it will save into a container, then will be accessed thru up or down arrow (↑/ ↓).
I know it is possible but I still don't have the idea in implementing it right. My first implementation is to store the commands into a single text file, then accessed it in reverse order so that last input will be retrieve first.
My problem is that how will I know if I'm in the specified index (e.g. 2 ↑ arrows will go into length-2 index of file).
A very basic example but working fine.you can take user inputs when pressing enter and add them to a collection like arraylist ,vectors .i used vector in this example.when user hit enter store them in a collection and when user press (↑/ ↓) ,take from it back and show in textarea.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
public class terminal extends JFrame {
Vector v = new Vector();
JTextArea area;
int pos = 0;
public terminal() {
setTitle("my terminal");
JPanel j = new JPanel();
setLayout(new GridLayout(1, 1));
setSize(400,250);
j.setLayout(new GridLayout(1, 1));
area = new JTextArea("terminal");
area.setBackground(Color.black);
area.setForeground(Color.white);
area.setCaretColor(Color.white);
area.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
area(evt);
}
private void area(KeyEvent evt) {
int keyCode = evt.getKeyCode();
if (keyCode == 38) {
try {
String store = (String) v.get(v.size() - 1 - pos);
replacer(store);
} catch (Exception ex) {
//ex.printStackTrace();
}
pos++;
evt.consume();
} else if (keyCode == 40) {
try {
String store = (String) v.get(v.size() - 1 - pos);
replacer(store);
} catch (Exception ex) {
//ex.printStackTrace();
}
pos--;
evt.consume();
} else if (keyCode == 10) {
v.add(linetext());
}
}
});
j.add(area);
add(j);
setVisible(true);
}
void replacer(String rep) {
try {
int caretOffset = area.getCaretPosition();
int lineNumber = area.getLineOfOffset(caretOffset);
int startOffset = area.getLineStartOffset(lineNumber);
int endOffset = area.getLineEndOffset(lineNumber);
area.replaceRange(rep, startOffset, endOffset);
} catch (BadLocationException ex) {
//ex.printStackTrace();
}
}
String linetext() {
String text = null;
try {
JTextArea ta = area;
int offset = ta.getLineOfOffset(ta.getCaretPosition());
int start = ta.getLineStartOffset(offset);
int end = ta.getLineEndOffset(offset);
text = ta.getText(start, (end - start));
} catch (BadLocationException ex) {
//ex.printStackTrace();
}
return text;
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
terminal terminal = new terminal();
}
});
}
}
output>>
Related
I am making a Source code Editor using JtextArea.In that I want to do the following task." While user typing on Editor window(JtextArea),each and every time the updated text(last word) should compare with the set of words in the database, if it matches any one of the word then the definition will be open in new popup frame."
My coding is like following
String str = textarea.getText();
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url+dbName,userName,password);
String stm="select url from pingatabl where functn=?";
PreparedStatement st = conn.prepareStatement(stm);
st.setString(1, str);
//Excuting Query
ResultSet rs = st.executeQuery();
if (rs.next()) {
String s = rs.getString(1);
//Sets Records in frame
JFrame fm = new JFrame();
fm.setVisible(true);
fm.setSize(500,750);
JEditorPane jm = new JEditorPane();
fm.add(jm);
jm.setPage(ClassLoader.getSystemResource(s));
In the above coding String str = textarea.getText(); reads all the text in the textarea.. but i need to get last word only. How can i get latest word from JTextArea..
Use a DocumentListener to monitor for changes to the text component and use javax.swing.text.Utilities to calculate the start/end index of the word in the Document, from which you can the extract the result
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Utilities;
public class TheLastWord {
public static void main(String[] args) {
new TheLastWord();
}
public TheLastWord() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTextArea ta = new JTextArea(10, 20);
add(new JScrollPane(ta));
JLabel lastWord = new JLabel("...");
add(lastWord, BorderLayout.SOUTH);
ta.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
checkLastWord();
}
#Override
public void removeUpdate(DocumentEvent e) {
checkLastWord();
}
#Override
public void changedUpdate(DocumentEvent e) {
checkLastWord();
}
protected void checkLastWord() {
try {
int start = Utilities.getWordStart(ta, ta.getCaretPosition());
int end = Utilities.getWordEnd(ta, ta.getCaretPosition());
String text = ta.getDocument().getText(start, end - start);
lastWord.setText(text);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
You can use following code block if you want to get the last word in the testarea
String[] wordsArray = textarea.getText().split("\\s+");
String lastWord = wordsArray[wordsArray.length - 1];
But if you want to get the last updated word then you have to use a Listener for that.
Check on DocumentListener and DocumentEvent
http://docs.oracle.com/javase/7/docs/api/javax/swing/event/DocumentListener.html
http://docs.oracle.com/javase/7/docs/api/javax/swing/event/DocumentEvent.html
To get the last line in your JEditorPane, split the text in the editor on \n as shown below:
String text = editor.getText();
String[] lines = text.split("\n");
String lastLine = lines[lines.length-1];
System.out.println("Last line: " + lastLine);
Similarly, to get the last word, split the last line on space.
Here a code of method that returns the last word of a text
public static String getLastWord(String s) {
int endOfLine = s.length() - 1;
boolean start = false;
while (!start && endOfLine >= 0) {
if (!Character.isLetter(s.charAt(endOfLine))) {
endOfLine--;
} else {
start = true;
}
}
final StringBuilder lastWord = new StringBuilder("");
while (start && endOfLine >= 0) {
if (!Character.isLetter(s.charAt(endOfLine))) {
start = false;
} else {
lastWord.insert(0, s.charAt(endOfLine));
endOfLine--;
}
}
return lastWord.toString();
}
In a Swing application, I sometimes need to support read-only access to large, line-oriented text files that are slow to load: logs, dumps, traces, etc. For small amounts of data, a suitable Document and JTextComponent are fine, as shown here. I understand the human limitations of browsing large amounts of data, but the problematic stuff seems like it's always in the biggest file. Is there any practical alternative for larger amounts of text in the 10-100 megabyte, million-line range?
Because of the size, you'll surely want to load the file in the background to avoid blocking the event dispatch thread; SwingWorker is a common choice. Instead of using a Document, consider updating a TableModel and displaying the lines of text in the rows of a JTable. This offers several advantages:
Results will begin appearing immediately, and there will be reduced perceived latency.
JTable uses the flyweight pattern for rendering, which scales well into the multi-megabyte, million-line range.
You can parse the input as it is being read to create an arbitrary column structure.
You can leverage the sorting and filtering features of JTable, for example.
You can use TablePopupEditor to focus on a single line.
Addendum: The example below uses DefaultTableModel for convenience. To reduce overhead, extend AbstractTableModel and manage a List<String> or List<RowData>, as shown here. The example displays indeterminate progress; changes to display intermediate progress are shown here.
Code:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
/**
* #see https://stackoverflow.com/a/25526869/230513
*/
public class DisplayLog {
private static final String NAME = "/var/log/install.log";
private static class LogWorker extends SwingWorker<TableModel, String> {
private final File file;
private final DefaultTableModel model;
private LogWorker(File file, DefaultTableModel model) {
this.file = file;
this.model = model;
model.setColumnIdentifiers(new Object[]{file.getAbsolutePath()});
}
#Override
protected TableModel doInBackground() throws Exception {
BufferedReader br = new BufferedReader(new FileReader(file));
String s;
while ((s = br.readLine()) != null) {
publish(s);
}
return model;
}
#Override
protected void process(List<String> chunks) {
for (String s : chunks) {
model.addRow(new Object[]{s});
}
}
}
private void display() {
JFrame f = new JFrame("DisplayLog");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
JProgressBar jpb = new JProgressBar();
f.add(jpb, BorderLayout.NORTH);
f.add(new JScrollPane(table));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
LogWorker lw = new LogWorker(new File(NAME), model);
lw.addPropertyChangeListener((PropertyChangeEvent e) -> {
SwingWorker.StateValue s = (SwingWorker.StateValue) e.getNewValue();
jpb.setIndeterminate(s.equals(SwingWorker.StateValue.STARTED));
});
lw.execute();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new DisplayLog().display();
});
}
}
I would separate the problem.
The first one is model - Document building speed
The second is the Document rendering - building tree of views to represent the Document.
A question is whether you need font effects like keywords colorizing?
I would start from Document building part. IMHO reading the file via EditorKit.read() should be fast even for big files. I would use the PainDocument for the purpose and check whether the pure model is built fast enough for your application. If yes it's fine just use the Document as model. If not implement your own Document interface because AbstractDocument has plenty of methods for update processing (e.g. writeLock).
When we have the Document loading fast enough we have to solve the Document rendering. BY default the views used in javax.swing.text are really flexible. They are designed as base classes to be extended - thus has a lot of code we don't need. E.g. measuring.
For the feature I would use Monospaced font, we don't need wrap so measurements of the view widht is fast = longest row char count * char widht.
The height is also char height * amount of lines.
So our PLainTextViewReplacement is really fast. Also we don't have to render the whole view but just a fragment visible in our scroll pane. Thus rendering could be mmuch much faster.
Of course there should be a lot of work to provide correct caret navigation, selection etc.
As I was struggeling with a similar use case I implemented a simple paging solution. It is far from perfect but works maybe someone finds it helpful.
In combination with a jtextarea it works ok but with a JEditorPane the performance is miserable.
If someone comes up with a better solution I would like to know about.
package net.ifao.tools.arcticrequester.gui.panel;
import java.awt.Adjustable;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.StringReader;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import javax.swing.JEditorPane;
import javax.swing.JScrollPane;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.JTextComponent;
/**
* A class that manages the visibility of file content visualized with a textarea within a scrollbar.
* Approx. 2050 lines from the file are visible at a time. Data is loaded from a file and
* displayed while the user is scrolling. The chunks are loaded dynamically.
*
* #author dostricki
*
*/
public class VisibilityManager
implements AdjustmentListener
{
private int lastLoadedLineFrom;
private int lastLoadedLineTo;
private int numberOfLines = 0;
private File file;
private boolean enabled = false;
private boolean showLines = false;
// load 1000 lines before the first visible line
// and 1000 lines after the last vissible line
private static final int LOAD_LINES_BEFORE_AND_AFTER_VIEWPORT = 1000;
// margin until when no load is triggered.
// moving the viewport more then 900 lines up or down should trigger a reload
private static final int VIEWPORT_LINES_MOVE_THRASHOLD = 900;
private JScrollPane scrollPane;
private JTextComponent textComponent;
private final BlockingQueue<Adjustable> queue;
public VisibilityManager(JScrollPane scrollPane, JTextComponent textArea)
{
this.scrollPane = scrollPane;
this.textComponent = textArea;
queue = new LinkedBlockingDeque<>();
startConsumer();
scrollPane.getVerticalScrollBar().addAdjustmentListener(this);
}
private void startConsumer()
{
Thread scrollEventConsumer = new Thread()
{
#Override
public void run()
{
while (true) {
try {
// if multiple events occured just process one
queue.take();
if (!queue.isEmpty()) {
List<Adjustable> events = new ArrayList<>();
queue.drainTo(events);
//System.out.println("Handling scroll event. " + events.size() + " queued events dropped");
}
doHandleScrollEvent();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
scrollEventConsumer.start();
}
public void setFile(File file)
{
this.file = file;
try {
this.numberOfLines = countNumberOfLines(file);
}
catch (IOException e1) {
e1.printStackTrace();
}
int showLineMax = Math.min(getNumberOfLines(), 100);
// show the first chunk immediately
showLinesBuffererdReader(1, showLineMax, 0);
this.enabled = true;
}
/**
* precalculates the number of lines in the document - necessary
* to replace the correct amount of preceeding and following
* lines with EOL's so that the height of the scrollpane does never change.
*
* #param file
* #return
* #throws IOException
*/
private int countNumberOfLines(File file)
throws IOException
{
int numberOfLines = 0;
//#formatter:off
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),StandardCharsets.UTF_8));) {
while (reader.ready()) {
reader.readLine();
++numberOfLines;
}
}
//#formatter:on
return numberOfLines;
}
/****************************************
* Getter
****************************************/
public int getNumberOfLines()
{
return numberOfLines;
}
public int getNumberOfLinesBuffer()
{
return LOAD_LINES_BEFORE_AND_AFTER_VIEWPORT;
}
public boolean isEnabled()
{
return enabled;
}
/****************************************
* Setter
****************************************/
public void setLastLoadedLines(int lineFrom, int lineTo)
{
this.lastLoadedLineFrom = lineFrom;
this.lastLoadedLineTo = lineTo;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public void setShowLines(boolean showLines)
{
this.showLines = showLines;
}
/****************************************
* Calculation
****************************************/
private boolean needsUpdate(int fromLine, int toLine)
{
boolean isBefore = fromLine < (this.lastLoadedLineFrom - VIEWPORT_LINES_MOVE_THRASHOLD);
boolean isAfter = toLine > (this.lastLoadedLineTo + VIEWPORT_LINES_MOVE_THRASHOLD);
if (isBefore || isAfter) {
return true;
} else {
return false;
}
}
private void showLinesBuffererdReader(int from, int to, int firstLineVisible)
{
//load also the buffer lines before
from = from - getNumberOfLinesBuffer();
//make sure it's valid
from = Math.max(1, from);
// load also the buffer lines after
to = to + getNumberOfLinesBuffer();
//make sure it's valid
to = Math.min(getNumberOfLines(), to);
FileChannel fileChannel = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
StringBuffer content = new StringBuffer();
int newCaretPosition = 0;
// fill leading empty lines
for (long i = 1; i < from; ++i) {
if (i == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(i).append(": ");
}
content.append('\n');
}
// read/write lines with content
int j = 0;
while (reader.ready() && j <= to) {
++j;
String line = reader.readLine();
if (j >= from && j <= to) {
if (j == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(j).append(": ");
}
content.append(line).append('\n');
}
}
// fill trailing empty lines
for (int i = to + 1; i <= getNumberOfLines(); ++i) {
if (i == firstLineVisible) {
newCaretPosition = content.length() + 1;
}
if (showLines) {
content.append(i).append(": ");
}
content.append('\n');
}
updateTextInUI(content);
// workaround for page up/down - it changes the caret position
// so we are re-setting it to the first visible line
// scrolling by scrollbars does not change the caret
//textComponent.setCaretPosition(newCaretPosition);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (fileChannel != null) {
fileChannel.close();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* #param content
* #throws IOException
*/
private void updateTextInUI(StringBuffer content)
throws IOException
{
if (textComponent instanceof JEditorPane) {
JEditorPane edit = ((JEditorPane) textComponent);
EditorKit editorKit = edit.getEditorKit();
Document createDefaultDocument = editorKit.createDefaultDocument();
createDefaultDocument.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
try {
editorKit.read(new StringReader(content.toString()), createDefaultDocument, 0);
}
catch (Exception e) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out));
edit.setText(new String(out.toByteArray()));
}
edit.setDocument(createDefaultDocument);
} else {
textComponent.setText(content.toString());
}
}
/****************************************
* Eventing
****************************************/
/**
* fired when scrolling happens in any of the cases and ways.
* Events are cached through a queue so that simultanious events
* don't trigger unnecessary update actions
* #see java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event.AdjustmentEvent)
*/
#Override
public void adjustmentValueChanged(AdjustmentEvent evt)
{
Adjustable source = evt.getAdjustable();
if (evt.getValueIsAdjusting()) {
return;
}
if (source != null) {
try {
queue.put(source);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void doHandleScrollEvent()
{
// determine which lines to request to be loaded into the
int height = this.scrollPane.getVerticalScrollBar().getMaximum();
int lines = getNumberOfLines();
if (lines == 0) {
return;
}
float heightPerLine = height / lines;
int visibleLines = Math.round(this.scrollPane.getVerticalScrollBar().getVisibleAmount() / heightPerLine);
int firstLineVisible = (int) Math.ceil(this.scrollPane.getVerticalScrollBar().getValue() / heightPerLine);
int fromLine = Math.max(firstLineVisible, 1);
if (fromLine > lines) {
fromLine = lines;
}
int toLine = Math.min(firstLineVisible + visibleLines, lines);
if (needsUpdate(fromLine, toLine)) {
if (enabled) {
setLastLoadedLines(fromLine, toLine);
showLinesBuffererdReader(fromLine, toLine, firstLineVisible);
}
}
}
}
usage:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.text.DefaultCaret;
import net.ifao.tools.arcticrequester.gui.panel.VisibilityManager;
public class TestFrame
extends JFrame
implements MouseListener
{
private VisibilityManager visibilityManager;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestFrame()
{
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 650, 500);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(new BorderLayout(0, 0));
JTextArea textArea = new JTextArea();
textArea.setEditable(false);
textArea.addMouseListener(this);
textArea.setAutoscrolls(false);
textArea.setCaretPosition(0);
DefaultCaret caret = (DefaultCaret) textArea.getCaret();
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
JScrollPane scrollPane = new JScrollPane(textArea);
contentPane.add(scrollPane);
visibilityManager = new VisibilityManager(scrollPane, textArea);
visibilityManager.setShowLines(true);
File file = new File("C:/iFAO/workspaces/polaris2/git/requester/ArcticRequester/src/test/java/responseview_20200603.tmp");
visibilityManager.setFile(file);
this.dispose();
}
/**
* #see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
*/
#Override
public void mouseClicked(MouseEvent e)
{
boolean doScroll = !visibilityManager.isEnabled();
this.visibilityManager.setEnabled(doScroll);
System.out.println("scrolling set to " + doScroll);
}
/**
* #see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
#Override
public void mousePressed(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
*/
#Override
public void mouseReleased(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
*/
#Override
public void mouseEntered(MouseEvent e)
{
// TODO Auto-generated method stub
}
/**
* #see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
*/
#Override
public void mouseExited(MouseEvent e)
{
// TODO Auto-generated method stub
}
}
The last days I have been trying to implement a highlighting feature in a small text editor. For some reason I get a strange result:
The given example should highlight each "dolor" - the first occurences are correctly found and highlighted but the next ones aren't.
Here is the code I wrote so far:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;
import javax.swing.text.DefaultStyledDocument;
/**
* Highlighting created on 04.11.2013<br>
* <br>
* Specification:<br>
*/
public class Highlighting extends JFrame implements MouseListener {
private JScrollPane scrollPane;
private JTextPane textPane;
private DefaultHighlighter highlighter;
private DefaultHighlightPainter painter;
public static void main(String[] args) {
new Highlighting().setVisible(true);
}
/**
*
*/
public Highlighting() {
this.initialize();
this.build();
this.configure();
}
/**
*
*/
public void initialize() {
this.scrollPane = new JScrollPane();
this.textPane = new JTextPane();
this.highlighter = new DefaultHighlighter();
this.painter = new DefaultHighlightPainter(Color.RED);
}
/**
*
*/
public void build() {
this.add(this.scrollPane);
}
/**
*
*/
public void configure() {
this.scrollPane.setViewportView(this.textPane);
this.textPane.setHighlighter(this.highlighter);
this.textPane.addMouseListener(this);
this.textPane.setDocument(new DefaultStyledDocument());
this.setPreferredSize(new Dimension(400, 500));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
*
*/
private void highlight() {
this.highlighter.removeAllHighlights();
String selectedText = this.textPane.getSelectedText();
String text = this.textPane.getText();
int wordlength = selectedText.length();
int index = 0;
while ((index = text.indexOf(selectedText, index)) != -1) {
try {
this.highlighter.addHighlight(index, index + wordlength, this.painter);
} catch (BadLocationException e) {
e.printStackTrace();
}
index += wordlength;
}
}
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
this.highlight();
}
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
Does this has something to do with the line separators (\r\n) ?
A JTextComponent's getText() and A JTextPane/JEditorPane's getText() has different implementation. JTextPane/JEditorPane uses EditorKit to write the document content(text) to a StringWriter and then return the text with formatting and inserting a line/paragraph break into the document. But the JTextCompoent returns document content directly by:
document.getText(0, document.getLength());
You will better understand if you try to compare the length : jTextPane1.getText().length() and jTextPane1().getDocument().getLength().
Reproducing the difference in length by inserting string with:
DefaultStyleDocument.insertString(0, str, primaryStyle)
when str = "I\n not" ; document length = 6, getText().length = 7
when str = "I\r\n not" ; document length = 7, getText().length = 8
when str = "I\n\n not" ; document length = 7, getText().length = 9!
So, in your high-lighting text program try reading the content text using:
DefaultStyledDocument document = (DefaultStyledDocument) jTextPane1.getDocument();
try {
contText = document.getText(0, document.getLength());
} catch (BadLocationException ex) {
Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
}
Then search for your selected text position in the contText as you were doing and you should be good to go. Because, highlighter.addHighlight(int p0, int p1, Highlighter.HighlightPainter p) uses the document for position offset.
Use CaretListener:
To Highlight upon text selection, It is better to use CaretListener, no need to add mouse and key board selection handling code at all:
jTextPane1.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent evt) {
if(evt.getDot() == evt.getMark())return;
JTextPane txtPane = (JTextPane) evt.getSource();
DefaultHighlighter highlighter = (DefaultHighlighter) txtPane.getHighlighter();
highlighter.removeAllHighlights();
DefaultHighlightPainter hPainter = new DefaultHighlightPainter(new Color(0xFFAA00));
String selText = txtPane.getSelectedText();
String contText = "";// = jTextPane1.getText();
DefaultStyledDocument document = (DefaultStyledDocument) txtPane.getDocument();
try {
contText = document.getText(0, document.getLength());
} catch (BadLocationException ex) {
Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
}
int index = 0;
while((index = contText.indexOf(selText, index)) > -1){
try {
highlighter.addHighlight(index, selText.length()+index, hPainter);
index = index + selText.length();
} catch (BadLocationException ex) {
Logger.getLogger(JTextPaneTest.class.getName()).log(Level.SEVERE, null, ex);
//System.out.println(index);
}
}
}
});
for example, see
how to remove Highlighter highlighter.removeHighlight(h);
View.modelToView for a new Highlighter
note I don't know how to determine a new line \n inside selection, not possible from this code
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.LayeredHighlighter;
import javax.swing.text.Position;
import javax.swing.text.View;
public class HighlightExample {
private JFrame f = new JFrame("Highlight example");
private JPanel panel = new JPanel();
private JTextPane textPane = new JTextPane();
private JTextField tf = new JTextField("wrapping!");
private String word;
private Highlighter highlighter = new UnderlineHighlighter(null);
public HighlightExample() {
textPane.setHighlighter(highlighter);
textPane.setText("This text pane contains no html. It supports letter wrapping, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping?, "
+ "\nThis text pane contains no html. It supports letter wrapping-, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping_, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping?, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping-, "
+ "\nThis text pane contains no html. It supports letter wrapping!, "
+ "\nThis text pane contains no html. It supports letter wrapping?");
panel.setLayout(new BorderLayout());
panel.add(new JLabel("Enter word, then press ENTER key: "), "West");
panel.add(tf, "Center");
/*try {
textPane.read(new FileReader("links1.html"), null);
} catch (Exception e) {
System.out.println("Failed to load file " + args[0]);
System.out.println(e);
}*/
final WordSearcher searcher = new WordSearcher(textPane);
tf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
word = tf.getText().trim();
int offset = searcher.search(word);
if (offset != -1) {
try {
textPane.scrollRectToVisible(textPane
.modelToView(offset));
} catch (BadLocationException e) {
}
}
}
});
textPane.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent evt) {
searcher.search(word);
}
#Override
public void removeUpdate(DocumentEvent evt) {
searcher.search(word);
}
#Override
public void changedUpdate(DocumentEvent evt) {
}
});
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel, "South");
f.add(new JScrollPane(textPane), "Center");
f.setSize(400, 400);
f.setVisible(true);
}
public static void main(String[] args) {
UIManager.put("TextPane.caretForeground", Color.yellow);
UIManager.put("TextPane.selectionBackground", Color.green);
UIManager.put("TextPane.selectionForeground", Color.blue);
/*try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception evt) {
}*/
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new HighlightExample();
}
});
}
}
// A simple class that searches for a word in
// a document and highlights occurrences of that word
class WordSearcher {
protected JTextComponent comp;
protected Highlighter.HighlightPainter painter;
public WordSearcher(JTextComponent comp) {
this.comp = comp;
this.painter = new UnderlineHighlighter.UnderlineHighlightPainter(Color.red);
}
// Search for a word and return the offset of the first occurrence.
// Highlights are added for all occurrences found.
public int search(String word) {
int firstOffset = -1;
Highlighter highlighter = comp.getHighlighter();
// Remove any existing highlights for last word
Highlighter.Highlight[] highlights = highlighter.getHighlights();
for (int i = 0; i < highlights.length; i++) {
Highlighter.Highlight h = highlights[i];
if (h.getPainter() instanceof UnderlineHighlighter.UnderlineHighlightPainter) {
highlighter.removeHighlight(h);
}
}
if (word == null || word.equals("")) {
return -1;
}
String content = null; // Look for the word we are given - insensitive search
try {
Document d = comp.getDocument();
content = d.getText(0, d.getLength()).toLowerCase();
} catch (BadLocationException e) {
return -1; // Cannot happen
}
word = word.toLowerCase();
int lastIndex = 0;
int wordSize = word.length();
while ((lastIndex = content.indexOf(word, lastIndex)) != -1) {
int endIndex = lastIndex + wordSize;
try {
highlighter.addHighlight(lastIndex, endIndex, painter);
} catch (BadLocationException e) {
// Nothing to do
}
if (firstOffset == -1) {
firstOffset = lastIndex;
}
lastIndex = endIndex;
}
return firstOffset;
}
}
class UnderlineHighlighter extends DefaultHighlighter {
protected static final Highlighter.HighlightPainter sharedPainter = new UnderlineHighlightPainter(null);// Shared painter used for default highlighting
protected Highlighter.HighlightPainter painter; // Painter used for this highlighter
public UnderlineHighlighter(Color c) {
painter = (c == null ? sharedPainter : new UnderlineHighlightPainter(c));
}
// Convenience method to add a highlight with the default painter.
public Object addHighlight(int p0, int p1) throws BadLocationException {
return addHighlight(p0, p1, painter);
}
#Override
public void setDrawsLayeredHighlights(boolean newValue) {
if (newValue == false) {// Illegal if false - we only support layered highlights
throw new IllegalArgumentException(
"UnderlineHighlighter only draws layered highlights");
}
super.setDrawsLayeredHighlights(true);
}
// Painter for underlined highlights
public static class UnderlineHighlightPainter extends LayeredHighlighter.LayerPainter {
protected Color color; // The color for the underline
public UnderlineHighlightPainter(Color c) {
color = c;
}
#Override
public void paint(Graphics g, int offs0, int offs1, Shape bounds,
JTextComponent c) {// Do nothing: this method will never be called
}
#Override
public Shape paintLayer(Graphics g, int offs0, int offs1, Shape bounds,
JTextComponent c, View view) {
g.setColor(color == null ? c.getSelectionColor() : color);
Rectangle alloc = null;
if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) {
if (bounds instanceof Rectangle) {
alloc = (Rectangle) bounds;
} else {
alloc = bounds.getBounds();
}
} else {
try {
Shape shape = view.modelToView(offs0, Position.Bias.Forward, offs1,
Position.Bias.Backward, bounds);
alloc = (shape instanceof Rectangle) ? (Rectangle) shape : shape.getBounds();
} catch (BadLocationException e) {
return null;
}
}
FontMetrics fm = c.getFontMetrics(c.getFont());
int baseline = alloc.y + alloc.height - fm.getDescent() + 1;
g.drawLine(alloc.x, baseline, alloc.x + alloc.width, baseline);
g.drawLine(alloc.x, baseline + 1, alloc.x + alloc.width, baseline + 1);
return alloc;
}
}
}
I have a string which is say "AAAABB". I have a JFormattedField of MaskFormatter. so I have ? ? ? ? ? ? in my Frame. I have two buttons A and B. when the user presses A button, the JFormattedField of the MaskFormatter should replace ? with Letter A for all occurrences of A. i.e, index 0,1,2,3 in this example.
I have my code that gets the list of indices to be replaced with A. But I am having difficulty in implementing setLetter(String Letter, int Position) method, that takes letter and indices to be replaced in the JformattedField. example if I pass setLetter("A",2), I should get ? ? A ? ? ? in the above example. Please try this code to see the frame.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.MaskFormatter;
public class TestMain extends JPanel{
JFormattedTextField input;
private MaskFormatter formatter;
public final String WORD = "ABBAABBA";
public TestMain() {
try {
JLabel label = new JLabel("Guesss");
String s="";
for (int i =0;i<WORD.length();i++){
s+="? ";
}
formatter = new MaskFormatter(s);
formatter.setPlaceholderCharacter('?');
input = new JFormattedTextField(formatter);
input.setColumns(20);
add(label);
add(input);
} catch (java.text.ParseException exc) {
System.err.println("formatter is bad: " + exc.getMessage());
System.exit(-1);
}
JButton buttonA = new JButton("A");
JButton buttonB = new JButton("B");
buttonA.addActionListener(clickedbutton());
buttonB.addActionListener(clickedbutton());
add(buttonA);
add(buttonB);
}
private ActionListener clickedbutton() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton pressedButton = (JButton) e.getSource();
String letter = e.getActionCommand();
try {
//System.out.println("actionCommand is: ---" + letter);
//Get the list of indices
int index = WORD.indexOf(letter);
ArrayList<Integer> indices = new ArrayList<Integer>();
if (index>=0){
for(int j=0;j<WORD.length();j++){
if (WORD.charAt(j)==letter.charAt(0)){
indices.add(j);
}
}
//System.out.println(indices);
}
for (int k =0 ; k < indices.size(); k++){
setLetter(letter, k);
}
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
};
}
public void setLetter(String letter, int position) throws ParseException {
String word="Hello";
input.setValue(letter);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
TestMain tm = new TestMain();
frame.add(tm);
frame.pack();
frame.setTitle("formatter");
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I don't think a mask formatter is what you want for this because you aren't really formatting a string here. If you just want to take a string and set characters at certain positions you should formulate the string yourself.
String text = "";
for (int i = 0; i < WORD.length(); i++) {
if (String.valueOf(word.charAt(i)).equals(letter)) {
text += letter + " ";
} else {
text += "? ";
}
}
input.setText(text);
Also a style note: all caps is for identifiers of static variables.
I have made a small program where the user gives the address of an image which is loaded on the ImageIcon and is displayed with a grid on it.
I now wish to get the position or the x,y cordinates of the grid in case of a mouse click on the picture.
Here's my code
import java.awt.*;
import java.awt.image.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;
import javax.swing.*;
class GridLines {
public static void main(String[] args) throws IOException {
System.out.println("Enter image name\n");
BufferedReader bf=new BufferedReader(new
InputStreamReader(System.in));
String imageName= null;
try {
imageName = bf.readLine();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
File input = new File(imageName);
Dimension imgDim = new Dimension(200,200);
BufferedImage mazeImage = new BufferedImage(imgDim.width, imgDim.height, BufferedImage.TYPE_INT_RGB);
mazeImage = ImageIO.read(input);
Integer k = mazeImage.getHeight();
Integer l = mazeImage.getWidth();
Graphics2D g2d = mazeImage.createGraphics();
g2d.setBackground(Color.WHITE);
//g2d.fillRect(0, 0, imgDim.width, imgDim.height);
g2d.setColor(Color.RED);
BasicStroke bs = new BasicStroke(1);
g2d.setStroke(bs);
// draw the black vertical and horizontal lines
for(int i=0;i<21;i++){
// unless divided by some factor, these lines were being
// drawn outside the bound of the image..
g2d.drawLine((l+2)/4*i, 0, (l+2)/4*i,k-1);
g2d.drawLine(0, (k+2)/5*i, l-1, (k+2)/5*i);
}
ImageIcon ii = new ImageIcon(mazeImage);
JOptionPane.showMessageDialog(null, ii);
}
}
Hope i get some help. Thanks in advance :)
The basic idea is to add a MouseListener to a component. In your case, you used a JOptionPane which does not provide access to the displayed components. Anyway, JOptionPane are not made for that purpose.
So I took the liberty to tackle this with a whole different angle. The code is far from perfect (for example, everything is in a single class), but it gives you a hint on how you could start. I think this will provide a better base to start from.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileFilter;
class GridLines {
private JFrame frame;
class MyGridPanel extends JPanel {
private static final int ROWS = 4;
private static final int COLS = 5;
class CellPanel extends JPanel {
int x;
int y;
public CellPanel(final int x, final int y) {
setOpaque(false);
this.x = x;
this.y = y;
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JOptionPane.showMessageDialog(CellPanel.this, "You pressed the cell with coordinates: x=" + x + " y=" + y);
}
};
setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.RED));
addMouseListener(mouseListener);
}
}
private final ImageIcon image;
public MyGridPanel(ImageIcon imageIcon) {
super(new GridLayout(ROWS, COLS));
this.image = imageIcon;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
add(new CellPanel(i, j));
}
}
// Call to setPreferredSize must be made carefully. This case is a good reason.
setPreferredSize(new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight()));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image.getImage(), 0, 0, this);
}
}
protected void initUI() {
frame = new JFrame(GridLines.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
File file = selectImageFile();
if (file != null) {
ImageIcon selectedImage = new ImageIcon(file.getAbsolutePath());
frame.add(new MyGridPanel(selectedImage));
frame.pack();
frame.setVisible(true);
} else {
System.exit(0);
}
}
public File selectImageFile() {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setFileFilter(new FileFilter() {
#Override
public String getDescription() {
return "Images files (GIF, PNG, JPEG)";
}
#Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String fileName = f.getName().toLowerCase();
return fileName.endsWith("gif") || fileName.endsWith("png") || fileName.endsWith("jpg") || fileName.endsWith("jpeg");
}
});
int retval = fileChooser.showOpenDialog(frame);
if (retval == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile();
}
return null; // Cancelled or closed
}
public static void main(String[] args) throws IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new GridLines().initUI();
}
});
}
}