Antialiasing of text in Swing components , using JDK 7 - java

please tell me how to enable antialiasing for text in Swing components (using JDK 7), not overriding method paintComponent() parent class. To read about this topic , which says that for this method is used
putClientProperty(
com.sun.java.swing.SwingUtilities2.aa_text_property_key, Boolean.TRUE);
requires a package com.sun.java.swing.SwingUtilities2, which is absent in the JDK older 5th version. Do not want to include in the project the outdated methods and libraries, could you please tell me what methods are used now for smoothing text of the components(similar putClientProperty()).
PLEASE DON'T WRITE about the use methods
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_On);
//or
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIAsing,
RenderingHints.VALUE_TEXT_ANTIALias_on);
because they do NOT WORK EVEN IF YOU OVERRIDE the paintComponent() parent class, the example below:
JButton button = new JButton("Button X O") {
#Override
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
//g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
//RenderingHints.VALUE_ANTIALIAS_On);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIASING_ON);
super.paintComponent(g2d);
g2d.dispose();
}
};
It's not Work! Please, help.

Global settings using system properties:
System.setProperty("awt.useSystemAAFontSettings","on");
System.setProperty("swing.aatext", "true");
By the way, the override should work if you override paint(Graphics g) (which then paints the component, border and children) in the root container instead of paintComponent(Graphics g).

Related

Java (re)painting mechanism [duplicate]

In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).

I want my JLayeredPane to catch all events

I have a JFrame and I want to set it disabled on some loading processes. For that purpose I've created the DisablingLayeredPane class:
public class DisablingLayeredPane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
g2d.setColor(Color.BLACK); // With 0.2f alpha it looks like light gray
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
On the loading process start, I call
frame.getLayeredPane().add(darkeningPane, JLayeredPane.MODAL_LAYER);
But the problem is, this darkening pane does not catch any events, I still can press buttons on my frame. I've also tried AWTEventListener to consume all of events for this frame, but there is another issue: sometimes I need to show modal dialog for some confirmation, and events for modal dialog are consumed too (I can't press any button). Of course, I can use some tricks like using transparent window above my frame instead darkening pane, or use a lot of if-else statements at AWTEventListener, but I'm looking for a some beautiful solution, if any.
Thanks in advance.
UPD:
I've also tried to add Mouse and Key Listeners to layered panel, but there is a new issue: if use JDialog instead JFrame, the KeyListener of layered panel would not catch ESC key pressing and dialog would dispose.
UPD2:
I've tried frame.setGlassPane(darkeningPane) instead setting as layer, but there is no effect.
It is impossible to intercept events by adding a simple component as a layer in terms of JLayeredPane. It seems that a lot of developers are not aware of this. Events are usually dispatched directly to the deepest child component containing the coordinates of a mouse event or to the focused component in case of a key event ignoring the parents, not to speak layers that are not even parents of the target component.
Thankfully there was a component added in Java 7 which does the complicated trick for you, JLayer, not to confuse with JLayeredPane.
Here is an example of how to use it:
JFrame f=new JFrame("Disabling via JLayer");
final JLayer<JTree> layer = new JLayer<JTree>(new JTree(), new LayerUI<JTree>() {
#Override
public void eventDispatched(AWTEvent e, JLayer<? extends JTree> l) {
if(e instanceof InputEvent) ((InputEvent)e).consume();
}
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, c.getWidth(), c.getHeight());
g2d.dispose();
}
});
f.setContentPane(layer);
layer.setLayerEventMask(~0);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);

Why is paintComponent() run even though no one calls it?

I was wondering if someone could explain how/why paintComponent() is called right after all the statements in main() are run. The reason I am confused is that there is no explicit call to painComponent() but it is run regardless.
// JComponent is a base class for custom components
public class SimpleDraw extends JPanel {
public static void main(String[] args) {
SimpleDraw canvas = new SimpleDraw();
JFrame f = new JFrame("SimpleDraw"); // jframe is the app window
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 400); // window size
f.setContentPane(canvas); // add canvas to jframe
f.setVisible(true); // show the window
}
// custom graphics drawing
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g; // cast to get 2D drawing methods
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // antialiasing look nicer
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(32)); // 32 pixel thick stroke
g2.setColor(Color.BLUE); // make it blue
g2.drawLine(0, 0, getWidth(), getHeight()); // draw line
g2.setColor(Color.RED);
g2.drawLine(getWidth(), 0, 0, getHeight());
}
}
Here is a decent little write-up on how paintComponent is handled.
Excerpt:
Who calls paintComponent
... This method is called because the user did
something with the user interface that required redrawing, or your
code has explicitly requested that it be redrawn. Called automatically
when it becomes visible When a window becomes visible (uncovered or
deminimized) or is resized, the "system" automatically calls the
paintComponent() method for all areas of the screen that have to be
redrawn. Called indirectly from a user-defined listener via repaint() ...
There's more in the write-up as well as some reference links, which, unfortunatelly, are all broken.
I also found this blog post which discusses painting/drawing in Java from a very basic point of view. Check out the first paragraph:
Why do we put all our graphical drawing code into a paintComponent()
method? It seems odd, since it would seem we should be able to simply
stick some simple graphics commands into our main() method in a Java
application and just get the drawing done. Where does paintComponent
come from? If we never call it in our code, how does it get executed?
In the Java docs you actually have to read up on paint to start getting an idea of what going on. The paintComponent documentation is not very helpful.

Drawing shapes does not work in graphics2D

The below code is to display a triangle in applet.But it does not work for me. If i pass Graphics g instead of Graphics2D g then it works fine.But i want to know what the mistake i am doing while using Graphics g. I am new to java and learning from some online tutorials. So please correct my program and tell me what mistake i am doing.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Vehicle extends JFrame {
final int WIDTH = 900;
int HEIGHT = 650;
public void init() {
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
System.out.println(d);
int[] yPoints={150,250,250};
int[] xPoints={200,150,250};
g2.setColor(Color.green);
g2.drawPolygon(xPoints, yPoints, 3);
g2.drawRect(100, 100, 100, 100);
g2.setColor(Color.red);
g2.fillPolygon(xPoints, yPoints, 3);
}
public static void main(String[] args) {
Vehicle v= new Vehicle();
v.init();
}
}
The method paint(Graphics g) is defined in java.awt.Component. This is more or less legacy code. However, this API hasn't changed for a long time and is inherited by modern Swing components, such as JFrame.
You can't simply change the method signature (in your case to paint(Graphics2D g)), you have to live with the signature defined by the API.
So, in your case, the paint(Graphics2D g) does not override the API method paint(Graphics g), and thus is not called when updating the JFrame. Nothing is painted.
Change your code like this:
----------------%<----------------------
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g) { // <-- Change from Graphics2D to Graphics
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
System.out.println(d);
int[] yPoints={150,250,250};
int[] xPoints={200,150,250};
---------------->%----------------------
Take a good look at what your program is doing before looking for assistance. (Not scolding you, just trying to help for the future.)
You have public void paint(Graphics2D g), which, as Petersen stated, is not a method in the JFrame class. A good trick to use to check if your methods in swing will do what tutorials say they will do is to put #Override above the method. If it errors, it means that method is not in JFrame or whatever superclass you have. Otherwise, it is overriding the method.
Additionally, another flag would be the next line: Graphics2D g2 = (Graphics2D) g;
Here you're casting a Graphics2D object as a Graphics2D object... which should never need to happen.. haha
If you are just getting started with swing and Graphics2D I suggest learning some of the Panels systems and other low-level things like drawImage or drawString, if you haven't done so already.
Working with Java2D it often helps to imagine your application as an animation. Imagine that at one point one specific frame(I am talking about animation frames okay) is drawn on the screen. When some event occurs we replace this frame with another frame incorporating the change much like the way cartoons or animation movies are built. How we draw animation frames? How do we switch between frames?
Java API provides a paint(graphics g) method for its components to be drawn. And then to update the same component you really call repaint() which simply calls paint(Graphics g) again and displays any changes on to the screen. This API method has a strict signature that we shall follow. It is paint(Graphics g). But Graphics2D is much like a cool kid on the block that provides more functionality because Graphics was too old(legacy) and not cool anymore. So how do we do this because paint(Graphics g) only accepts Graphics not Graphics2D? Graphics2D is a subclass of Graphics okay.
Protocol is simple,
Use the legacy paint(Graphics g) method of every component.
Once we have used super.paint(Graphics g) (if needed) ,we can typecast the Graphic object that we were using for legacy purposes to Graphics2D to get enhance functionality.(you have done this step right)
Problem with your code:
It is only the signature. Java and the repaint() expect the method to be paint(Graphics g) but you have changed the signature and now the above protocol (or contract) is broken. The idea is to keep the contract(by not changing the signature) and then typecast and override to add extended features. Java is not able to find paint(Graphics g) and so repaint() will not also find paint(Graphics g).

JButton Transparency on an BufferedImage

I have a Problem:
I'm rendering a BufferedImage in a JFrame. Then i add a JButton to the same frame.
when i try to make the button transparent, the button becomes transparent, but disregarding its actual position, its always transparent like it is stuck in the top left corner of the frame.
I testet some different methods to make the button transparent, always with the same result.
any ideas?
thanks
public class TestPanel extends JPanel {
public TestPanel(){
JButton foo = new JButton("test");
foo.setBackground(new Color(0, 0, 0, 0));
foo.setBounds(20, 100, 300, 50);
this.add(foo);
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(ImageFactory.getImg(), 0, 0, null); //get a BufferedImage
g2.dispose();
}
}
I see several problems, even if I'm not sure on which of them cause your problem.I try to list them in order:
Your TestPanel doesn't specify a LayoutManager (I hope you are specifying it somewhere else in your code).
You are extending a JPanel without call super paintComponent method (don't use paint). You should do this before anything else in your paintComponent method:
public void paintComponent(Graphics g){
super.paintComponent(g);
}
remove the dispose method call. You must not destroy your graphic object.
EDIT:
this is a problem:
foo.setBounds(20, 100, 300, 50);
you are trying to explicitly set the bounds of your JButton. You shouldn't do that. If you are using a LayoutManager it probably ignore this directive. If you are using a null layout this could be a problem too.
Several problems
it's wrong to override paint, instead override paintComponent
the button has a fully transparent background but returns true for opaque, thus fooling the paint mechanism
it's wrong to dispose the Graphics passed in as parameter
working code (Edit: accidentally removed the transparent color-setting line, fixed)
public TestPanel(){
JButton foo = new JButton("test");
foo.setBackground(new Color(0, 0, 0, 0));
foo.setOpaque(false);
foo.setBorder(BorderFactory.createLineBorder(Color.RED));
this.add(foo);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(ImageFactory.getImg(), 0, 0, null); //get a BufferedImage
// g2.dispose();
}
As others already noted: LayoutManagers are a must in Swing/AWT - not using them makes the ui code brittle and hard to maintain.
setBound() will work only if you have set your layout to null. Your code does not say anything like that.
Now, the default layout manager of JPanel is FlowLayout. By default, this layout manager will arrange your components from left to right then top to bottom.
Now, to make your code work as expected. Add this line inside your constructor: setLayout(null).
But remember, setting the layout to null is a very poor practice.
Also, the points Heisenbug has mentioned are very worthy. Try to follow them.

Categories