I am trying to define the Font for an AWT Label.
While I can manage to use fonts for a Java2D graphics environment, same font seems not to work with AWT Labels. I would like to understand if there is any limitation on font usage I am not aware about it for AWT Labels, or if I am simply not using the right syntax/procedure.
this is my code, it basically adds a Label and text to the graphics context:
package com.company.test;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
public class TestTest extends Frame {
Label myLabel = new Label();
Font myFont = new Font("Roboto Condensed Light", Font.PLAIN, 12);
Graphics2D g2d;
public TestTest() {
setSize(500,200);
setLocation(10,10);
setUndecorated(false);
myLabel.setBackground(Color.red);
myLabel.setFont(myFont);
myLabel.setText("ROBOTO CONDENSED, THIS DOES NOT WORK!");
add(myLabel, BorderLayout.SOUTH);
setVisible(true);
}
public void paint(Graphics g) {
g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(0.0f));
g2d.setFont(myFont);
g2d.setColor(Color.BLACK);
g2d.drawString("ROBOTO CONDENSED THIS WORKS!",50, 50);
}
public static void main( String[] args ) {
TestTest window = new TestTest();
}
}
This is the result:
While font is properly defined (as it is used in the Text element in the Graphics component), it is not being applied to the AWT Label component.
Any tip is welcomed.
Note: please do not suggest to use SWING or JavaFX, I am well aware that they are the recommended way of using widgets. Question is specifically related to AWT Label widget.
Ok you have to create your own label; the idea is to get to the graphics of things. I have added my inline class but you can create a proper class; then you have to pass the string or other parameters to that class:
class TestTest extends Frame {
Font myFont = new Font("Rockwell Nova", Font.PLAIN, 12);
Graphics2D g2d;
public TestTest() {
Label myLabel = new Label() {
public void paint(Graphics g) {
g.setFont(myFont);
g.drawString("ROBOTO CONDENSED, THIS DOES NOT WORK!", 0, 20);
}
};
setSize(500,200);
setLocation(10,10);
setUndecorated(false);
myLabel.setBackground(Color.red);
add(myLabel, BorderLayout.SOUTH);
setVisible(true);
}
public void paint(Graphics g) {
g2d = (Graphics2D) g;
g2d.setStroke(new BasicStroke(0.0f));
g2d.setFont(myFont);
g2d.setColor(Color.BLACK);
g2d.drawString("ROBOTO CONDENSED THIS WORKS!",50, 50);
}
}
Related
I have a JLabel with text. The text displays in different colors and since I also want the background to change color, I found sometimes the text it's hard to read. That is why I want to add a shadow to the font like this: React Native font outline / textShadow
Can someone tell me how to get this effect in a Java Swing label or, if not possible, which Swing component I should use instead?
You can convert the text to an outline and stroke it.
import javax.swing.*;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
class Test extends JFrame {
public Test() throws HeadlessException {
setSize(500, 500);
add(new JOutlineLabel("test"));
}
class JOutlineLabel extends JComponent {
int width = 3;
Shape outline;
public JOutlineLabel(String string) {
BufferedImage temp = new BufferedImage(200, 200, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2 = temp.createGraphics();
FontRenderContext frc = g2.getFontRenderContext();
Font font = new Font("Helvetica", 1, 60);
TextLayout textLayout = new TextLayout(string, font, frc);
outline = textLayout.getOutline(null);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.translate(0, outline.getBounds().height);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(width));
g2.draw(outline);
}
}
public static void main(String[] args) {
new Test().setVisible(true);
}
}
You'll want to avoid the executing heavyweight bits like instantiating the Font, converting the text to an outline, etc every draw.
My application is a simple game of Brick Breaker. In order to paint the visuals of the application I'm using the paintComponent method. The application also has several buttons that are added using the following code:
levelMenu = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double scale = screenSize.getHeight()/1080;
Graphics2D g2d = (Graphics2D) g;
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
}
};
levelMenu.setLayout(new FlowLayout());
JPanel subPanel = new JPanel(new GridLayout(20, 2, 10, 10));
subPanel.setBackground(Constants.CLEAR);
subPanel.add(new JLabel());
subPanel.add(new JLabel());
for (JButton level: levelList) {
subPanel.add(level);
}
subPanel.add(new JLabel());
subPanel.add(back);
levelMenu.add(subPanel);
this.add(levelMenu);
The issue Im having is that the buttons are being added, but also they seem to be painted in the background image of the application:
The buttons on the right dont work, and are just images. Any clue how to fix this issue.
The primary issue comes down to...
Graphics2D g2d = (Graphics2D) g;
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
The Graphics context passed to the paintComponent method is a shared resource, all the components rendered within the paint pass will use it. This means that any changes you make to it will also affect them. You should be especially aware of transformations (like translate and scale).
A general practice is to make a snapshot of the state of Graphics context before you use it, this allows you to make changes to the copy with affecting the original, something like...
Graphics2D g2d = (Graphics2D) g.create();
g2d.scale(scale, scale);
g2d.drawImage(background, 0, 0, null);
g2d.dispose();
The other issue is subPanel.setBackground(Constants.CLEAR);. I'm assuming that this is a alpha based color. Swing component's don't support alpha based colors, they are either fully opaque or fully transparent (although you can fake it). This is controlled through the use of setOpaque
Now, I strongly recommend that you stop and go have a read through:
Performing Custom Painting
Painting in AWT and Swing
Use below code snippet for your reference:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicPanelUI;
class MyPanelUI extends BasicPanelUI {
public void paint(Graphics g, JComponent c) {
Toolkit toolkit = Toolkit.getDefaultToolkit();
Graphics2D g2d = (Graphics2D) g;
Image img = toolkit.getImage("/usr/share/backgrounds/warty-final-ubuntu.png");
g2d.drawImage(img, 0, 0, null);
}
public Dimension getPreferredSize(JComponent c) {
return super.getPreferredSize(c);
}
}
public class PanelBGTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setUI(new MyPanelUI());
panel.setLayout(new FlowLayout());
panel.add(new JButton("This is button"));
SwingUtilities.updateComponentTreeUI(frame);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
using paint component is not good practice so its always better to extent your component UI class from basic component UI class and override the paint() method. This way swing will take care of all the rendering / re-rendering part and your component(s) added to panel will be visible too.
Now, I strongly recommend that you stop and go have a read through:
Performing Custom Painting
Painting in AWT and Swing
BufferStrategy and BufferCapabilities
How to Use Layered Panes
We all know that the drawString method can be used this way:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Driver {
public static void main(String[] args) {
JFrame frame = new JFrame("Frame Heading");
frame.setSize(1000,500);
myComponent comp = new myComponent();
frame.add(comp);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class myComponent extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello World", 300, 300);
}
}
But, how do we adjust the font size of the string being displayed? I want to make it larger.
class myComponent extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
int fontSize = 20;
Font f = new Font("Comic Sans MS", Font.BOLD, fontSize);
g2.setFont(f);
g2.drawString("Hello World", 300, 300);
}
}
You can change the style, size and Font because you probably don't want to use Comic Sans.
See also Graphics#setFont.
how do we adjust the font size of the string being displayed?
You can derive a new Font based on the current font:
public void paintComponent(Graphics g)
{
super.paintComponent(g); // don't forget this.
g.fillRect(0, 0, getWidth(), getHeight()); // make sure the background is cleared
Font font = g.getFont().deriveFont( 20.0f );
g.setFont( font );
g.drawString(...);
}
You don't need a Graphics2D object to draw a string.
Or instead of forcing the Font to be a specific size in the paintComponent() method you can customize your object by using:
MyComponent comp = new MyComponent();
comp.setFont( comp.getFont().deriveFont( 20.0f );
In this case you use your current painting code.
Also, class names should start with an upper case character you your class should be "MyComponent".
I have a Graphics2D object and I want to use its drawString method. I can call that method and pass a String and (x, y) positions, which is very nice. However, I also have the possibility to change the font of my Graphics2D object, using the setFont method, which expects a Font object. This is also very nice. Unfortunately this is not enough for me, because I intend to define multiple font texts to my Font object.
This is the textual representation I would like to transfer to my Font object:
font-family:"Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif
I have seen that I have the possibility to use the AttributedCharacterIterator interface to solve my problem, however, I am not sure how should I use that. I have seen that there is actually an implementation called AttributedString, which has a set of Attributes, but I am not sure how could I create an AttributedString object which could be used by the constructor of Font in such a way that my Graphics2D object will recognize the multiple fonts and apply them when I call drawString.
EDIT:
public static AttributedString getFontByAttributes(String atts, String value)
{
String[] attributes = atts.split(",");
AttributedString attributedString = new AttributedString(value);
for (int attributeIndex = 0; attributeIndex < attributes.length; attributeIndex++)
{
attributedString.addAttribute(TextAttribute.FONT, attributes[attributeIndex].trim());
}
return attributedString;
}
//...
public void drawTitle(Graphics2D g2d)
{
//...
g2d.drawString(getFontByAttributes(Settings.titleFontString, Settings.title).getIterator(), Settings.headerWidthOffset, Settings.headerHeightOffset);
//...
}
In the code above I have tried with Andale Mono, which is known on the system where I test this application, however, in the generated graphics, the text is drawn in Times New Roman font. Something is wrong and unfortunately I don't have a clue about what could I be missing.
Basically, AttributedString provides methods to allow you to apply rendering attributes to a String. Seems obvious really.
After that, you can pass the AttributedString's AttributedCharacterIterator to Graphics2D for rendering...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.LineMetrics;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestAttributedString {
public static void main(String[] args) {
new TestAttributedString();
}
public TestAttributedString() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AttributedString text = new AttributedString("Bunny rabits and flying ponies");
text.addAttribute(TextAttribute.FONT, new Font("Arial", Font.BOLD, 24), 0, "Bunny rabits".length());
text.addAttribute(TextAttribute.FOREGROUND, Color.RED, 0, "Bunny rabits".length());
text.addAttribute(TextAttribute.FONT, new Font("Arial", Font.BOLD & Font.ITALIC, 32), 17, 17 + "flying ponies".length());
text.addAttribute(TextAttribute.FOREGROUND, Color.BLUE, 17, 17 + "flying ponies".length());
FontMetrics fm = g2d.getFontMetrics();
LineMetrics lm = fm.getLineMetrics(text.getIterator(), 0, text.getIterator().getEndIndex(), g);
g2d.drawString(text.getIterator(), 0, (int)lm.getAscent() + lm.getHeight());
g2d.dispose();
}
}
}
You can check out this for more details
Graphics2D has a drawString(AttributedCharacterIterator, int, int) method that you'll want to use.
Simply build up your AttributedString with all the different TextAttribute.FONT properties you want for each specific sub-range of the string, then call:
g2d.drawString(myAttributedString.getIterator(), x, y);
import javax.swing.*; // For JPanel, etc.
import java.awt.*; // For Graphics, etc.
import java.awt.geom.*; // For Ellipse2D, etc.
import java.awt.event.*;
public class ShapeExample extends JPanel {
private Rectangle2D.Double square =
new Rectangle2D.Double(50, 50, 100, 100);
private Rectangle2D.Double square1 =
new Rectangle2D.Double(10, 10, 200, 200);
private Ellipse2D.Double circle =
new Ellipse2D.Double(50, 50, 100, 100);
public void paintComponent(Graphics g) {
clear(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(Color.red);
//g2d.fill(square);
g2d.draw(square);
g2d.draw(square1);
g2d.fill(square1);
}
}
// super.paintComponent clears offscreen pixmap,
// since we're using double buffering by default.
protected void clear(Graphics g) {
super.paintComponent(g);
}
protected Rectangle2D.Double getsquare() {
return(square);
}
public static void main(String[] args) {
WindowUtilities.openInJFrame(new ShapeExample(), 100, 100);
}
}
Get rid of the WindowUtilites class and build your frame manually so you understand what is going on. Then you add a panel containing your sliders to the top/bottome of the frame. Add your painting panel to the center. Start by reading the Swing tutorial on How to Use Sliders for working examples of creating a basic GUI with sliders. You can then post your SSCCE if you have problems.