JTextArea - Highlight Text While Scrolling Up or Down - java

I'm trying to work with a non-editable JTextArea added to a JScrollPane. I want a line to be highlighted when the user clicks on that specific line. I could implement this part using the following code:
public static void initHighlightOption(final JTextArea textArea){
textArea.setFont(new Font("Courier New", Font.PLAIN, 12));
textArea.setEditable(false);
final Action selectLine = getAction(textArea, DefaultEditorKit.selectLineAction);
textArea.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 1) {
selectLine.actionPerformed(null);
}
});
textArea.setSelectionStart(0);
textArea.setSelectionEnd(0);
}
public static Action getAction(JTextArea textArea, String name) {
Action action = null;
Action[] actions = textArea.getActions();
for (int i = 0; i < actions.length; i++) {
if (name.equals(actions[i].getValue(Action.NAME).toString())) {
action = actions[i];
break;
}
}
return action;
}
What I want to add is that once a line is highlighted and user scrolls up/down using keyboard up/down key, i want the current line to be highlighted. Is this possible by adding a keyListener? I'm stuck on how highlight data while scrolling up.
The text area contains data like this:
Line1
Line2
Line3
Line4
Line5
(i.e. there might be new lines between two particular lines of data)

What your asking for is not so easy to do. First off use a JTextPane instead of a JTextArea, it'll be much easier to handle. You will be need to get the Highlighter object from it
Highlighter hl = textPane.getHighlighter();
and you would probably have to keep track of your caret position each time the user scrolls with the arrow keys. When doing that you need to programatically change the highlights; something like:
Highlighter.Highlight myHighlight = null;
Highlighter.Highlight[] highlights = textPane.getHighlighter().getHighlights();
myHighlight = highlights[0]; //assuming there is one only
try {
hl.changeHighlight(myHighlight, myHighlight.getStartOffset()+1, myHighlight.getEndOffset());
}
catch(BadLocationException e) {
e.printStackTrace();
}
You can probably put this in your onKeyReleased() method. You kind of get the idea of what you're going to have to do. Read up on using JTextPane and Highlighter classes in the Java API docs, it will really help you alot.

Related

Disable the mouse cursor within a program

I'm creating a text adventure and I need to completely disable the mouse cursor. Not just hide it, although I already know how to do that, but disable it completely so that you must use Alt-Tab or a built-in quit button to stop. The main reason for this is because people can scroll with the mouse cursor and I need to disable that, I thought about canceling MouseEvents when they're fired but I couldn't get it to work (the listener that is.)
If someone knows how then please speak up and tell me! :)
EDIT: Whoops, I forgot my code. Here is my Console class.
This is started by another class with new Console();
EDIT 2: Here are some snippets of me trying to create an invisible cursor and a mouse listener. The first one works, but the latter does not.
// Invisible cursor
Toolkit toolkit = Toolkit.getDefaultToolkit();
Point hotSpot = new Point(0,0);
BufferedImage cursorImage = new BufferedImage(1, 1, BufferedImage.TRANSLUCENT);
Cursor invisibleCursor = toolkit.createCustomCursor(cursorImage, hotSpot, "InvisibleCursor");
frame.setCursor(invisibleCursor);
// Adding mouse listener
frame.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
EDIT 3: To elaborate on the mouse listener it simply does not work. It doesn't print anything.
If you just want to prevent users from seeing old text, remove the old text from the JTextArea.
The easiest way to do it is to leave the JTextArea in a JScrollPane, and keep track of the lines yourself:
private static final int MAX_VISIBLE_LINES = 12;
private final Deque<String> lines = new LinkedList<>();
void appendLine(String line,
JTextArea textArea) {
lines.addLast(line);
if (lines.size() > MAX_VISIBLE_LINES) {
lines.removeFirst();
}
String text = String.join("\n", lines);
textArea.setText(text);
textArea.setCaretPosition(text.length());
try {
textArea.scrollRectToVisible(
textArea.modelToView(text.length()));
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}
Trying to commandeer the mouse on a multitasking desktop is just going to make users angry. Would you want an application preventing you from reading your e-mail?
Update:
If you want to base the number of lines of text on the JTextArea’s current height, use the JTextArea’s font metrics. I assume you don’t need to get it exactly right and it’s okay if the number is off by one or two lines. (To account for things like line wrapping would be considerably more difficult.)
private final Deque<String> lines = new LinkedList<>();
void appendLine(String line,
JTextArea textArea) {
FontMetrics metrics = textArea.getFontMetrics(textArea.getFont());
JViewport viewport = (JViewport) textArea.getParent();
int visibleLineCount = viewport.getExtentSize().height / metrics.getHeight();
lines.addLast(line);
while (lines.size() > visibleLineCount) {
lines.removeFirst();
}
String text = String.join("\n", lines);
textArea.setText(text);
textArea.setCaretPosition(text.length());
try {
textArea.scrollRectToVisible(
textArea.modelToView(text.length()));
} catch (BadLocationException e) {
throw new RuntimeException(e);
}
}

Java Listener for looped combo in Eclipse SWT

I have a Java SWT GUI that I've built using Eclipse. I'm using a while loop to reference a text file. The while loop iterates through each line of the text file and builds a series of combo or text boxes for specific items on each line. Each line represents one visual column in the GUI and, depending on how many items I have in the text file, the GUI builds to the right. For simplicity's sake I am including just the code that I am trying to figure out.
For instance, assume I have three lines that create six combo boxes in the GUI (three columns by two rows). I would like a change on the top row in the second column to execute a Listener on the bottom row, also in the second column. However, right now the Listener loops through all of the combo's and makes a change to all three, not just the one I want. I can't figure out how to make this work. See the code below. I appreciate the help.
private void buildMultipleSatPulldowns() {
try {
FileReader fr = new FileReader("MultipleSatellites.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
String[] tempS;
String constellation = null;
String satellite = null;
while ((line = br.readLine()) != null) {
tempS = line.split("~");
constellation = tempS[4];
satellite = tempS[6];
constNameCombo = new Combo(satellitesComposite2, SWT.NONE);
constNameCombo.setToolTipText("Pulldown constellation name");
constNameCombo.setBounds(startX + x2, 71, 125, 28);
constNameCombo.setItems(constNameArray);
constNameCombo.setText(constellation);
constNameCombos.add(constNameCombo);
constNameCombo.addModifyListener(new ModifyListener() { // captures changed combo values
public void modifyText(ModifyEvent arg0) {
setConstellationPD();
}
});
sPullDown(constellation); // builds the satellite array for the constellation and populates each pulldown
satNameCombo = new Combo(satellitesComposite2, SWT.NONE);
satNameCombo.setToolTipText("Pulldown satellite name");
satNameCombo.setBounds(startX + x2, 106, 125, 28);
satNameCombo.setItems(satNameArray);
satNameCombo.setText(satellite);
satNameCombos.add(satNameCombo);
startX = startX + nextX;
}
br.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void setConstellationPD() {
int constellations = 0;
for (Combo constNameCombo : constNameCombos) {
// What do I do here so that only the desired satNameCombo changes to reflect the desired pull down?
setSatellitesPD(constellations, constNameCombo)
constellations++;
}
}
private void setSatellitesPD(int c, String cN) {
int satellites = 0;
for (Combo satNameCombo : satNameCombos) {
if (c == satellites) {
satNameCombo.setText(satNameCombos.get(satellites).toString());
satNameCombo.removeAll();
sPullDown(cN);
satNameCombo.setText("select Satellite");
}
satellites++;
}
}
private void sPullDown(String cName) {
// sPullDown takes the constellation name and returns a String Array of all objects in the constellation. This code works correctly when called.
}
If I understood correctly, you need a way to know which combo fired the event in order to affect some other components.
SWT events like ModifyEvent have the method getSource() which will return the object on which the event occurred.
Having that you just need to properly identify it; for example you could simply use constNameCombos.indexOf(eventCombo) to retrieve its index.
Or, more efficiently, you could attach some data to your combos with the method setData and retrieve it inside the event with getData, for example inside the loop:
// "i" would be the index of the combo
constNameCombo.setData("index", i);
i++;
and in the event:
Combo eventCombo = (Combo) arg0.getSource();
int index = eventCombo.getData("index");
With these information you should be able to identify the other components that you want to change.

LibGdx newline TextArea in android

I created an android application with TextArea using LibGdx. My problem is whenever clicked in the touch screen keyboard's newline ("Enter" equivalent in keyboard), it doesn't return a newline. The text still written on the same line. However, it only moves on the second line if it fills the width of the textArea. How could I return a new line on the textarea widget?
Taken from this discussion: http://badlogicgames.com/forum/viewtopic.php?f=11&t=15112
Add the following to the show() function:
final StringBuilder build = new StringBuilder();
final TextArea textArea = new TextArea("", skin);
textArea.setTextFieldListener(new TextFieldListener()
{
#Override
public void keyTyped(TextField textField, char c)
{
// Handle a newline properly. If not handled here, the TextField
// will advance to the next field.
if (c == '\n')
{
textArea.setMessageText(build.append("\n").toString());
}
}
});
This solved the problem for me.

JTextArea line numbers of menu item

I am trying to develop a project using AWT And SWING concepts of Java.
In that I have an one menu item called "Viewline Numbers (i.e. we have chosen a JCheckBox for that)". When I check the Check-box it is displaying line numbers in another Document. But, I want to display the line numbers in same using Document like as Editplus Editor.
Here is my code
private void ViewLineNumbersActionPerformed(java.awt.event.ActionEvent evt) {
lines = new JTextArea("");
lines.setBackground(Color.LIGHT_GRAY);
lines.setEditable(false);
lines.setSize(10,10);
tx.getDocument().addDocumentListener(new DocumentListener(){
public String getText(){
int caretPosition = tx.getDocument().getLength();
// System.out.println("caretPosition"+ caretPosition);
Element root = tx.getDocument().getDefaultRootElement();
// System.out.println("root"+ root);
String text = "1" + System.getProperty("line.separator");
int c=root.getElementIndex( caretPosition );
// System.out.println(c);
for(int i = 2; i < c + 2; i++){
text += i + System.getProperty("line.separator");
}
return text;
}
#Override
public void `enter code here`changedUpdate(DocumentEvent de) {
lines.setText(getText());
}
#Override
public void insertUpdate(DocumentEvent de) {
lines.setText(getText());
}
#Override
public void removeUpdate(DocumentEvent de) {
lines.setText(getText());
}
});
sp.getViewport().add(tx);
// sp.setViewportView(tx);
sp.setRowHeaderView(lines);
}
But, I want to display the line numbers in same using Document like as Editplus Editor.
I doubt very much that the line numbers are part of the Document. They may appear to be displayed as part of the same component, but I'm sure that when you copy/paste text you don't get the line numbers included.
Assuming my above statement is correct you can try using the Text Component Line Number. Since this a component displayed in the row header of the scroll pane you should be able to toggle the visibility of the component based on your checkbox.

How do I allow a user to change his font in a JTextPane using a JComboBox?

I'm finding the amount of helpful documentation/tutorials on the internet are lacking when it comes to the topic of JTextPanes. I'm trying to do a simple text processor, and I want it to be able to select a font family from a JComboBox that populates itself based on the fonts a user has installed on their system. However, no matter what I try with experimenting, I can't figure out how to make it work.
What I have is a toolbar class that is built off of a JTextPane. Currently, it has a bunch of style buttons that work to set alignment and bold, italics and underline.
Here's my code:
/**
* The StyleBar is used to customize styles in a Styled Document. It will take a
* JTextPane as an argument for its constructor and then all actions to be taken
* will affect the text in it.
*
* #author Andrew
*/
public class StyleBar extends JToolBar {
private JLabel fontLbl;
private JComboBox fontBox;
// ...Irrelevant stuff to the problem at hand.
/**
* The initEvents method is used to initialize the necessary events for the
* tool bar to actually do its job. It establishes the focus listener to the
* buttons on the bar, and gives each one its individual functionality. It
* also establishes the Font Selection interface.
*/
public void initEvents() {
//For each item in the tool bar, add the focus listener as well as the
//formatting listeners:
boldFormat.addActionListener(new StyledEditorKit.BoldAction()); //boldFormat is
boldFormat.addActionListener(resetFocus); //a JButton
//Ditto for my italicsFormat and underlineFormat button(s) in the toolbar
leftAlign.addActionListener(new StyledEditorKit.AlignmentAction(null,
StyleConstants.ALIGN_LEFT));
leftAlign.addActionListener(resetFocus); //This listener just resets focus
//back onto the TextPane.
//Ditto for my right and centerAlign buttons
//Set up the Font list, and add a listener to the combo box
buildFontMenu();
}
/**
* The buildFontMenu detects all of the SYstem's available fonts and adds
* them to the Font Selection box.
*/
public void buildFontMenu(){
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
final String[] fontNames = ge.getAvailableFontFamilyNames();
for (int i = 0; i < fontNames.length; i++){
//What do I do here to take the entry at String[i] and make it so that when
//the user selects it it sets the font Family in a similar way to that of
//pressing the boldFormat button or the leftAlign button?
}
}
//Everything else is irrelevant
So to sum up my problem: I have no idea how to properly set the listener to the ComboBox such that a) it's sensitive to the individual font selected and b) somehow uses StyledEditorKit.FontFamilyAction to make life easy?
Slash, if I'm approaching anything about this the wrong way, I'd love to hear the right way. As I said, my sources on the internet aren't very clear on the subject.
Thanks so much!
StyledEditorTest puts the Actions in a JToolBar, but the idea is the same. See also Charles Bell's HTMLDocumentEditor, mentioned here. For example,
bar.add(new StyledEditorKit.FontFamilyAction("Serif", Font.SERIF));
bar.add(new StyledEditorKit.FontFamilyAction("SansSerif", Font.SANS_SERIF));
Addendum: As you are using JComboBox, you can forward the event to the corresponding StyledEditorKit Action, which operates on the current selection by default.
JComboBox combo = new JComboBox();
combo.addItem("Serif");
combo.addItem("Sans");
combo.addActionListener(new ActionListener() {
Action serif = new StyledEditorKit.FontFamilyAction("Serif", Font.SERIF);
Action sans = new StyledEditorKit.FontFamilyAction("Sans", Font.SANS_SERIF);
#Override
public void actionPerformed(ActionEvent e) {
if ("Sans".equals(e.getActionCommand())) {
sans.actionPerformed(e);
} else {
serif.actionPerformed(e);
}
}
});
This may be a bit late, but I found myself stuck on the similar problem, and although the previous answer does help, here is a more complete answer for when you want to use all the fonts available on your computer..
Where "fonts" is a string array containing all the desired fonts to be used in your program
final JComboBox jcb = new JComboBox(fonts);
final Action [] actions = new Action[fonts.length];
for (int i = 0; i < actions.length; i++)
{
actions[i] = new StyledEditorKit.FontFamilyAction(fonts[i], fonts[i]);
}
jcb.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
for (int i = 0; i < actions.length; i++)
{
if (fonts[i].equals((String)jcb.getSelectedItem()))
{
actions[i].actionPerformed(event);
break;
}
}
}
});

Categories