For my application, I am going to have syntax highlighting, in my text box. What I am not sure of, is how to do multi-color in one box instead of just one color.
I know I can do this, but it sets all of the text to one color.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ssccee;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JTextArea;
/**
*
* #author ryannaddy
*/
public class Sscce extends JFrame{
JTextArea txt = new JTextArea();
public Sscce(){
setLayout(null);
txt.setBounds(3, 3, 300, 200);
add(txt);
Font font = new Font("Verdana", Font.BOLD, 12);
txt.setFont(font);
txt.setForeground(Color.BLUE);
txt.setText("\n \n JTextArea font & color change example");
}
public static void main(String[] args){
Sscce jtxt = new Sscce();
jtxt.setSize(313, 233);
jtxt.setTitle("JTextArea font & color settings");
jtxt.show();
}
}
So, how can I accomplish this?
A JTextArea is a plain text component. It can display text in different fonts, but all of the text is in the same font. You'll want to use something like JSyntaxPane.
A very simple to use and extend JEditorKit that supports few languages. The main goal is to make it easy to have nice looking Java Swing Editors with support for Syntax Highlighting.
Related
I have a panel of buttons that represent an inventory, and in order to give emphasis to one button in particular I increased its border size. The border increases inward, however, which would be totally fine it didn't cover up the highlight effect buttons have when the mouse hovers over them. Is there any way to make the button highlight effect still show up in some way if it's covered up by the border? Maybe by increasing the highlight effect's border size?
This picture is an example of what I'm talking about. The top button is the emphasized button with the increased border size. The second button is a normal button being highlighted by the cursor(the mouse cursor doesn't show up in snip snapshots). As the picture shows, the increased border size is bigger than the highlight effect so when you try to highlight the first button seemingly nothing happens. The third/fourth are just normal buttons with no effect.
Sorry if the wording here is a little confusing but I'm not sure what the best way to phrase my probelm is.
Here is a simple example. The button with the red border no longer highlights when your mouse cursor hovers over it.
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class Test {
JFrame window;
JPanel screen1;
Border borderThick = BorderFactory.createLineBorder(Color.red, 3);
public Test(){
//Frame Window
window = new JFrame();
window.setSize(800,600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.blue);
//Screen 1
screen1 = new JPanel();
screen1.setBounds(100, 100, 600, 205);
screen1.setBackground(Color.blue);
JButton buttonThickBorder = new JButton("Thick Button");
buttonThickBorder.setBorder(borderThick);
screen1.add(buttonThickBorder);
JButton buttonNormalButton = new JButton("NormalButton");
screen1.add(buttonNormalButton);
window.add(screen1);
window.setVisible(true);
}
public static void main(String[] args){
new Test();
}
}
JButtons come with their own default Border which is the one you are seeing by default (which comes with hover effects, press effects, etc). If you change the border to provide your own, then the default border is gone.
To fix this, one way is to implement your own border which will listen for hover events, which is easier done by listening to the JButton's model changes, like so:
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Custom {
private static void createAndShowGUI() {
JFrame window;
JPanel screen1;
Border borderThick = BorderFactory.createLineBorder(Color.red, 3);
//Frame Window
window = new JFrame();
window.setSize(400,300);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.blue);
//Screen 1
screen1 = new JPanel();
screen1.setBounds(100, 100, 600, 205);
screen1.setBackground(Color.blue);
JButton buttonThickBorder = new JButton("Thick Button");
buttonThickBorder.setBorder(borderThick);
screen1.add(buttonThickBorder);
//Changes:
Border borderThickRollover = BorderFactory.createLineBorder(Color.CYAN, 3);
buttonThickBorder.getModel().addChangeListener(e -> {
final ButtonModel model = (ButtonModel) e.getSource();
if (model.isRollover())
buttonThickBorder.setBorder(borderThickRollover);
else
buttonThickBorder.setBorder(borderThick);
});
JButton buttonNormalButton = new JButton("NormalButton");
screen1.add(buttonNormalButton);
window.add(screen1);
window.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Custom::createAndShowGUI);
}
}
Similarly you can listen for other events, like the button being pressed, armed, selected or enabled (all those via the button's model) and change the border accordingly. For even more events, you can use listeners on the button itself (like FocusListener for example).
One other way to fix the issue you are seeing is to use the default border itself, along with your custom border, by constructing a CompoundBorder, for example like so:
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Default {
private static void createAndShowGUI() {
JFrame window;
JPanel screen1;
//Border borderThick = BorderFactory.createLineBorder(Color.red, 3);
//Frame Window
window = new JFrame();
window.setSize(400,300);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().setBackground(Color.blue);
//Screen 1
screen1 = new JPanel();
screen1.setBounds(100, 100, 600, 205);
screen1.setBackground(Color.blue);
JButton buttonThickBorder = new JButton("Thick Button");
//buttonThickBorder.setBorder(borderThick);
screen1.add(buttonThickBorder);
//Changes:
Border borderThickRollover = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.CYAN, 5), buttonThickBorder.getBorder());
buttonThickBorder.setBorder(borderThickRollover);
JButton buttonNormalButton = new JButton("NormalButton");
screen1.add(buttonNormalButton);
window.add(screen1);
window.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Default::createAndShowGUI);
}
}
This way you are getting the default border plus your extra border. This way you don't necessarily need to listen for model changes.
Notice, in the second example, that when you hover over the outside border of the compound one (ie the cyan sub-border) the button model changes to rolled over which makes the inside (default) border to be notified. This happens because the compound border is maintained by the button, so hovering the compound border anywhere will make the button's model rolled over. If this is not desired, then the simplest workaround I can think of right now is that you can just add the button inside a JPanel which will have a cyan LineBorder and install the button on that panel.
Generally speaking, you can obtain a JButton's default Border, without the need to actually construct a JButton, through the UIManager like so:
Border buttonDefaultBorder = javax.swing.UIManager.getBorder("Button.border");
...unless of course you install your own Look And Feel (L&F) which behaves differently, in which case you can obtain the default border after constructing the button, but that's a different story (and probably an erroneous L&F implementation).
I want to set bold font style for selected text in JTextArea instance.
I tried this way:
textArea.getSelectedText().setFont(new Font("sansserif",Font.BOLD, 12));
But it does not work. Also I've tried JTextPane and JEditorPane instead of JTextArea but without effect.
How can I do that?
I want to set bold font style for selected text in JTextArea instance.
You can't do this for a JTextArea. You need to use a JTextPane.
Then you can use the default Action provided by the StyledEditorKit. Create a JButton or JMenuItem to do this:
JButton boldButton = new JButton( new StyledEditorKit.BoldAction() );
JMenuItem boldMenuItem = new JMenuItem( new StyledEditorKit.BoldAction() );
Add the button or menu item to the frame. Then the use can click on the button/menu item to bold the text after it has been selected. This is the way most editor work. You can also add an acceleration to the Action to the Action can be invoked just by using the keyboard.
Read the section from the Swing tutorial on Text Component Features for more information and a working example.
Introduction
The (useful) answers for how to do what you want to do have already been posted by #Freek de Bruijn and #Gilbert Le Blanc, but none of them explain why what you're trying to do doesn't work. This isn't an answer for
How can I do that?
but an explanation for
But it does not work.
Edit: #camickr posted what I believe is the correct approach.
Answer
From the tutorial about about JTextArea:
You can customize text areas in several ways. For example, although a given text area can display text in only one font and color, you can set which font and color it uses.
(all emphasis in quotes are mine) and
If you want the text area to display its text using multiple fonts or other styles, you should use an editor pane or text pane.
This is because JTextArea uses PlainDocument (see this):
PlainDocument provides a basic container for text where all the text is displayed in the same font.
However, a JTextPane uses DefaultStyledDocument:
a container for styled text in no particular format.
You have to set up a caret listener on a JTextPane to listen for when some or all of the text is selected.
Here's the GUI I created.
And here's the code:
package com.ggl.testing;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
public class JTextPaneTest implements Runnable {
private JTextPane textPane;
private StyledDocument styledDocument;
public static void main(String[] args) throws BadLocationException {
SwingUtilities.invokeLater(new JTextPaneTest());
}
public JTextPaneTest() throws BadLocationException {
this.styledDocument = new DefaultStyledDocument();
this.styledDocument.insertString(0, displayText(), null);
addStylesToDocument(styledDocument);
}
#Override
public void run() {
JFrame frame = new JFrame("JTextPane Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
textPane = new JTextPane(styledDocument);
textPane.addCaretListener(new SelectedText());
textPane.setPreferredSize(new Dimension(250, 125));
JScrollPane scrollPane = new JScrollPane(textPane);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
private String displayText() {
return "This is some sample text. Pick part of the text to select "
+ "by double clicking on a word.";
}
private void addStylesToDocument(StyledDocument styledDocument) {
Style def = StyleContext.getDefaultStyleContext().getStyle(
StyleContext.DEFAULT_STYLE);
Style s = styledDocument.addStyle("bold", def);
StyleConstants.setBold(s, true);
}
private class SelectedText implements CaretListener {
#Override
public void caretUpdate(CaretEvent event) {
int dot = event.getDot();
int mark = event.getMark();
if (dot != mark) {
if (dot < mark) {
int temp = dot;
dot = mark;
mark = temp;
}
boldSelectedText(mark, dot);
}
}
private void boldSelectedText(int mark, int dot) {
try {
int length = dot - mark;
String s = styledDocument.getText(mark, length);
styledDocument.remove(mark, length);
styledDocument.insertString(mark, s,
styledDocument.getStyle("bold"));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
}
You could use a JTextPane component similar to changing the color as described in the following answer: How to set font color for selected text in jTextArea.
For example:
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
public class BoldSelected {
public static void main(final String[] args) {
new BoldSelected().launchGui();
}
private void launchGui() {
final String title = "Set bold font style for selected text in JTextArea instance";
final JFrame frame = new JFrame("Stack Overflow: " + title);
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
final JTextPane textPane = new JTextPane();
textPane.setText(title + ".");
final Style style = textPane.addStyle("Bold", null);
StyleConstants.setBold(style, true);
textPane.getStyledDocument().setCharacterAttributes(4, 33, style, false);
frame.getContentPane().add(textPane);
frame.setVisible(true);
}
}
So I just found the Netbeans JFrame Form referenced in an online tutorial to help with layout (my textbook hadn't made mention of it in the GUI section, at least that I've seen!) Since I'm having a difficult time with the layout of the program I'm working on (I can't get the text area to behave itself and stay in the center of the window instead of taking up the entire window!) I thought a visual aid might be helpful, however, as you might have guessed I already have a large amount of code sunk into this program. Is it possible to link a new JFrame Form with an existing class? If so, how would I go about doing it? I can provide my code if you need it, but we're talking 500 lines of code in just one of the main three classes.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package theproblem;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.TextArea;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* #author Heather
*/
public class TheProblem {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
JFrame window2 = new JFrame();
TextArea battleLogging = new TextArea(3,10);
JScrollPane logScrollPane = new JScrollPane(battleLogging);
JLabel BattleLog = new JLabel();
JLabel p1HPLabel= new JLabel();
JLabel p2HPLabel= new JLabel();
String attack1ButtonContents = "Just an attack";
String attack2ButtonContents = "Just another attack";
JButton attack1=new JButton(attack1ButtonContents);
JButton attack2=new JButton(attack2ButtonContents);
window2.setLayout(new BorderLayout());
window2.setSize(400,400);
JPanel attackPanel = new JPanel();
attackPanel.add(attack1);
attackPanel.add(attack2);
// attack1 = new JButton(p1A1);
// attack2 = new JButton(p1A2);
// attack1.addActionListener(new Attack1());
// attack2.addActionListener(new Attack2());
//window2.add(attackPanel, BorderLayout.CENTER);
window2.add(battleLogging, BorderLayout.CENTER);
battleLogging.setEditable(false);
logScrollPane.setVerticalScrollBarPolicy(
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
logScrollPane.setPreferredSize(new Dimension(50, 50));
//battleLogging.setLineWrap(true);
//battleLogging.setWrapStyleWord(true);
window2.add(BattleLog, BorderLayout.NORTH);
window2.add(p1HPLabel, BorderLayout.WEST);
window2.add(p2HPLabel, BorderLayout.EAST);
window2.setVisible(true);
window2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
To answer your question directly, you can create a JFrame (actually a custom class extending JFrame) and design it in your Netbeans visual designer, then instantiate it in your existing class. You can use composition (http://en.wikipedia.org/wiki/Object_composition) and have a reference to the JFrame as a field in your existing class. You can provide additional methods in your JFrame to pass data to it.
Is there a way to improve font rendering in Swing JTextFields? Here's what I'm getting right now:
As you can see, it looks pretty jagged. Is there a way I can improve that? I'm using the GTKLookAndFeel, just in case anyone needs to know.
(I looked at this question, but it didn't help much.)
SSCCE:
public class foo extends JFrame{
foo(){
add(new JTextField);
setVisible(true);
}
}
I'm on Linux, so that might have something to do with it. I'm using Infinality in linux for better fonts.
Using the sscce below, I see the following appearance with the GTK+ L&F.
Addendum: As a workaround, you might try setting a UI delegate property, for example,
JTextField tf = new JTextField();
UIManager.put("TextField.font", tf.getFont().deriveFont(Font.BOLD));
import component.Laf;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
/** #see http://stackoverflow.com/a/18969361/230513 */
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(0, 1));
// http://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(new JTextField("bla#foo.com"));
f.add(new JPasswordField("*****"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
To get a smother text, you should enable anti-aliasing:
$ java -jar lib/application.jar -Dswing.aatext=true
Using this code you can change the font and font color in a JTextArea.
We have created a JTextArea called txt. With a few simple lines of code you can change its font, color & size settings:
Font font = new Font("Verdana", Font.BOLD, 12);
txt.setFont(font);
txt.setForeground(Color.BLUE);
There are several font settings in the Font class including PLAIN, BOLD, ITALIC and 13 different colors in the Color class (listed below).
BLACK
BLUE
CYAN
DARK_GRAY
GRAY GREEN
LIGHT_GRAY
MAGENTA
ORANGE
PINK
RED
WHITE
YELLOW
I would like to understand why a JLabel, rendering HTML, shifts the vertical position of it's output text, whereas a JLabel which renders non-HTML, does not.
Java version used: 1.6.0_37
Swing Look and Feel used: Windows ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")
OS: Windows 7 64 Bit
I did not put a SSCCE together since the code is really trivial. But if it helps please say so.
I rather give an examples using an images displaying the behavior:
I put a JPanel as the container around the JLabel to visualize the label's bounds. After setting the font and text for the JLabel, the
jLabel.getPreferredSize()
method returns the bounds of the rendered plain text or HTML (and this is the exact size I set for the surrounding JPanel). You can clearly see, that, if rendering HTML, the whole text is shifted a small amount down.
I would like to know why this happens and what I can do to correct the placement.
One workaround would be to translate the Graphics2D on which to render the text, to compensate the vertical shift, like this:
g2d.translate( 0, -20 );
But I don't know the correct y value in relation to the font metrics (e.g. font size). Anyway, this workaround also feels "wrong".
I really appreciate your answers, thanks a lot!
It seems that if we set the Font (family,size etc) for the HTML JLabel using setFont(..) the font is not rendered to the correct metrics of JLabel.
Here is an example I made to demonstrate (Both JLabels shown are using HTML):
A simple work around is to the the font size, family etc in HTML too.
As we can see the cyan HTML JLabel used setFont(..) (and was incorrectly rendered) while the green HTML JLabel used HTML to set the font and was rendered correctly:
JLabel labelHtml2 = new JLabel("<html><font size=10 family='Calibri'>" + text + "</font></html>");
Test.java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static Font font = new Font("Calibri", Font.PLAIN, 38);
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new Test();
}
});
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String text = "Hello world";
//this label will not render correctly due to setting font via setFont(..)
JLabel labelHtml1 = new JLabel("<html>" + text + "</html>");
labelHtml1.setBackground(Color.CYAN);
labelHtml1.setOpaque(true);//so background will be painted
labelHtml1.setFont(font);
//this label will render correcty font is set via html
JLabel labelHtml2 = new JLabel("<html><font size=10 family='Calibri'>" + text + "</font></html>");
labelHtml2.setBackground(Color.GREEN);
labelHtml2.setOpaque(true);
//labelHtml2.setFont(font);
frame.add(labelHtml1, BorderLayout.NORTH);
frame.add(labelHtml2, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}