Skip to content

Example: Setting the theme

bobbylight edited this page Jan 10, 2022 · 5 revisions

What if you don't like the colors RSyntaxTextArea uses to highlight code by default? What if the default font isn't to your liking? What if you're crazy and like to use proportional fonts while programming?

Changing the color scheme or fonts used can be done either programmatically, or via loading an XML file conforming to the project's theme DTD. While this example will cover both methods, the latter is of course preferred, because it separates styling logic from code, and gives your users an easy way to configure the code editor in your application.

Care must be taken when using the API to change the syntax scheme, because in the default scheme, keywords are bold and comments are italicized - in other words, these token types use a different java.awt.Font than the default. This means when changing the font, you'll have to make more than a single method call if you want to use a single font for all styles.

RSTA includes some default themes in the org.fife.ui.rsyntaxtextarea.themes package (see here), or you can write your own. The example below shows how you can programmatically load the themes baked into the library.

Loading a Theme via XML

Loading a theme for RSyntaxTextArea via XML is easy. Simply create an XML file that follows the theme DTD, and use the Theme class to load it and apply it to RSyntaxTextArea instances. The API to do so is simple:

  • theme.load(InputStream in) - Load a theme from XML.
  • theme.apply(RSyntaxTextArea textArea) - Apply a theme to a text editor.

Use the sample theme provided with this demo, or any of the sample themes included in the project, as a guide to create your own themes.

Setting individual fonts and colors via the API

As with all JTextComponents, an RSyntaxTextArea's base font is accessed with getFont() and setFont(Font). This is the font that is used for a token type (i.e. keyword, variable) if no font is specified for that specific type. Similarly, the text area's foreground color (getForeground()/setForeground(Color)) is used as the color for a token type if no foreground color is explicitly specified.

Token type-specific colors and fonts are specified in an RSyntaxTextArea's SyntaxScheme. You can grab an RSTA's SyntaxScheme via the getSyntaxScheme() and setSyntaxScheme(SyntaxScheme) methods. A SyntaxScheme contains several different Style objects, one per token type supported by RSTA. You reference a Style for a particular token type by using one of the integer constants defined in the TokenTypes class, such as TokenTypes.RESERVED_WORD or TokenTypes.COMMENT_EOL, and calling syntaxScheme.getStyle(tokenType).

A Style has public fields allowing you to change the following properties of a token type and how it is painted:

  • background - The background color to use. If this is null, the background for the token will not be painted.
  • font - The font to use for this token type. If this is null, the text area's default font (i.e. getFont()) will be used.
  • foreground - The foreground color to use. If this is null, the text area's foreground color (i.e. getForeground()) will be used.
  • underline - Whether this token type should be underlined.

Modifying these fields (and revalidating the text area via textArea.revalidate(); textArea.repaint();) will cause the RSTA to take the changes at runtime.

Example

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;

import org.fife.ui.rtextarea.*;
import org.fife.ui.rsyntaxtextarea.*;

/**
 * A simple example showing how to modify the fonts and colors used in an
 * RSyntaxTextArea. There are two methods to do this - via the Java API, and via
 * an XML file. The latter method is preferred since it's more modular, and
 * provides a way for your users to customize RSTA in your application.<p>
 *
 * This example uses RSyntaxTextArea 3.1.4.
 */
public final class SyntaxSchemeDemo extends JFrame implements ActionListener {

   private static final long serialVersionUID = 1L;

   private RSyntaxTextArea textArea;

   private static final String TEXT = "public class ExampleSource {\n\n" +
         "   // Check out the crazy modified styles!\n" +
         "   public static void main(String[] args) {\n" +
         "      System.out.println(\"Hello, world!\");\n" +
	   	 "   }\n\n" +
         "}\n";

   private SyntaxSchemeDemo() {

      JPanel cp = new JPanel(new BorderLayout());

      textArea = new RSyntaxTextArea(20, 60);
      textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
      textArea.setCodeFoldingEnabled(true);
      textArea.setAntiAliasingEnabled(true);
      RTextScrollPane sp = new RTextScrollPane(textArea);
      cp.add(sp);

      textArea.setText(TEXT);

      JMenuBar mb = new JMenuBar();
      JMenu menu = new JMenu("File");
      mb.add(menu);
      JMenuItem changeStyleProgrammaticallyItem = new JMenuItem(
            "Change Style Programmatically");
      changeStyleProgrammaticallyItem
            .setActionCommand("ChangeProgrammatically");
      changeStyleProgrammaticallyItem.addActionListener(this);
      menu.add(changeStyleProgrammaticallyItem);
      JMenuItem changeStyleViaThemesItem = new JMenuItem(
            "Change Style via Theme XML");
      changeStyleViaThemesItem.setActionCommand("ChangeViaThemes");
      changeStyleViaThemesItem.addActionListener(this);
      menu.add(changeStyleViaThemesItem);
      setJMenuBar(mb);

      setContentPane(cp);
      setTitle("Syntax Scheme Demo");
      setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      pack();
      setLocationRelativeTo(null);

   }

   /**
    * Listens for the selection of a menu item and performs an action
    * accordingly.
    */
   @Override
   public void actionPerformed(ActionEvent e) {
      String command = e.getActionCommand();
      if ("ChangeProgrammatically".equals(command)) {
         changeStyleProgrammatically();
      } else if ("ChangeViaThemes".equals(command)) {
         changeStyleViaThemeXml();
      }
   }

   /**
    * Changes the styles used in the editor programmatically.
    */
   private void changeStyleProgrammatically() {

      // Set the font for all token types.
      setFont(textArea, new Font("Comic Sans MS", Font.PLAIN, 16));

      // Change a few things here and there.
      SyntaxScheme scheme = textArea.getSyntaxScheme();
      scheme.getStyle(Token.RESERVED_WORD).background = Color.pink;
      scheme.getStyle(Token.DATA_TYPE).foreground = Color.blue;
      scheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).underline = true;
      scheme.getStyle(Token.COMMENT_EOL).font = new Font("Georgia",
            Font.ITALIC, 12);

      textArea.revalidate();

   }

   /**
    * Changes the styles used by the editor via an XML file specification. This
    * method is preferred because of its ease and modularity.
    */
   private void changeStyleViaThemeXml() {
      try {
         Theme theme = Theme.load(getClass().getResourceAsStream(
               "/org/fife/ui/rsyntaxtextarea/themes/eclipse.xml"));
         theme.apply(textArea);
      } catch (IOException ioe) { // Never happens
         ioe.printStackTrace();
      }
   }

   /**
    * Set the font for all token types.
    *
    * @param textArea The text area to modify.
    * @param font The font to use.
    */
   private static void setFont(RSyntaxTextArea textArea, Font font) {
      if (font != null) {
         SyntaxScheme ss = textArea.getSyntaxScheme();
         ss = (SyntaxScheme) ss.clone();
         for (int i = 0; i < ss.getStyleCount(); i++) {
            if (ss.getStyle(i) != null) {
               ss.getStyle(i).font = font;
            }
         }
         textArea.setSyntaxScheme(ss);
         textArea.setFont(font);
      }
   }

   public static void main(String[] args) {
      // Start all Swing applications on the EDT.
      SwingUtilities.invokeLater(() -> new SyntaxSchemeDemo().setVisible(true));
   }

}