Painting multiple JComponent on JPanel not working - java

I just don't get this. I want to add Highlight extends JComponent objects to a PdfPage extends JPanel but the Highlight components are simple not painted. I can see that their paint() and paintComponent() methods are getting called in correct order but they do not show. The only thing that fixes my problem is to add:
for(Component component : this.getComponents()) {
component.paint(g);
}
into the PdfPanel.paint() method but this is not how I want to do that. I want PdfPage extends JPanel to render any JComponent I'm adding but not override paint() if possible.
This is how I add Highlight components to PdfPage panels:
for (DatasheetError datasheetError : datasheetErrorList) {
int pageNumber = datasheetError.getPageNumber();
Highlight highlight = createErrorHighlight(datasheetError);
PdfPage pdfPage = pdfPages[pageNumber];
pdfPage.add(highlight);
}
This is how PdfPage looks like. Note that I am not using a LayoutManager as I am calling super(null);:
public class PdfPage extends JPanel {
private static final long serialVersionUID = 7756137054877582063L;
final Image pageImage;
public PdfPage(Image pageImage) {
// No need for a 'LayoutManager'
super(null);
this.pageImage = pageImage;
Rectangle bounds = new Rectangle(0, 0, pageImage.getWidth(null), pageImage.getHeight(null));
this.setBounds(bounds);
this.setLayout(null);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintPdfPage(g);
}
private void paintPdfPage(Graphics g) {
// For now transparent background to see if `Highlight` gets painted
g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.0f));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
In Highlight.java you can see that I call this.setBounds(bounds);
public class Highlight extends JComponent {
private static final long serialVersionUID = -1010170342883487727L;
private Color borderColor = new Color(0, 0, 0, 0);
private Color fillColor;
public Highlight(Rectangle bounds, Color fillColor) {
this.fillColor = fillColor;
this.setBounds(bounds);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle bounds = this.getBounds();
g.setColor(this.fillColor);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
g.setColor(this.borderColor);
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
}

Looks like problem is coordinate space
protected void paintComponent(Graphics g) {
...
Rectangle bounds = this.getBounds();
g.setColor(this.fillColor);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
...
}
The getBounds() returns the component's rectanle on parent container. So when you can call just g.fillRect(0, 0, bounds.width, bounds.height);

Related

Is it possible to write paint on screen program in java/swing?

I'm writing paint on screen program using Java Swing. It working on ubuntu linux. But windows shows black screen instead of transparent panel. I included similar example code. What is wrong in my code?
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Example {
public static final Color COLOR_TRANSPARENT = new Color(0,0,0,0);
public Example() {
Canvas drawArea = new Canvas();
drawArea.setBackground(COLOR_TRANSPARENT);
drawArea.setOpaque(true);
JWindow drawingFrame = new JWindow();
drawingFrame.setBackground(COLOR_TRANSPARENT);
drawingFrame.setContentPane(drawArea);
drawingFrame.pack();
drawingFrame.setSize(640, 460);
drawingFrame.setVisible(true);
drawingFrame.setLocationRelativeTo(null);
drawingFrame.setAlwaysOnTop(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(Example::new);
}
class Canvas extends JPanel{
private Image image;
private Graphics2D g2;
public Canvas() {
super();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
g2.setPaint(Color.RED);
g2.fillOval(x-10, y-10, 20, 20);
repaint(x-10, y-10, 20, 20);
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image == null){
image = createImage(getWidth(), getHeight());
g2 = (Graphics2D) image.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setBackground(COLOR_TRANSPARENT);
clear();
}
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(image, 0,0, null);
}
public void clear(){
System.out.println("clearing canvas ");
g2.setComposite(AlphaComposite.Clear);
g2.setBackground(COLOR_TRANSPARENT);
g2.setColor(COLOR_TRANSPARENT);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.clearRect(0, 0, getWidth(), getHeight());
g2.setPaint(Color.RED);
g2.setComposite(AlphaComposite.SrcOver);
repaint();
}
}
}
Here is screenshot what I wanted.
Example code updated. Now code should work without any other additional code.
For windows I made a couple of changes:
image = createImage(getWidth(), getHeight());
image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
I used a BufferedImage to you can set the alpha values of the image to be transparent.
//public static final Color COLOR_TRANSPARENT = new Color(0,0,0,0);
public static final Color COLOR_TRANSPARENT = new Color(0,0,0,1);
I made the alpha value non-zero, because a value of zero means the Java application won't receive the MouseEvent because it is passed to the application under the window.

JSlider image behind track

I want to put an image (visualization of an audio) behind the JSlider which represents the audioplayer, the process of playing.
First I tried to overwrite the paint-method of the Slider
public void paintComponent(Graphics g) {
// Draw the previously loaded image to Component
g.drawImage(img, 0, -100, null);
super.paintComponent(g);
}
this worked, but the image is higher than the slider, so my next try was a JLayeredPane, where I put the JSlider above a JLabel with the image. Looks good for the first moment. But I mentioned that I need the image behind the track of the slider, not the whole slider. There is space to the left and right. Can anybody tell me a way how to calculate this space? Or the width and offset of the track to the border of the slider? This should run under Windows and MacOs, so different LookAndFeels, so I think hard coded values will not work.
Example Slider with background image
Thankyou.
My solution for this Problem is now to overwrite the SliderUI. So this is a very special component, so it's nonrelevant that it looks the same on all LookAndFeels.
It supports also jumping directly to mouse position, which is different to BasicSliderUI.
/**
*
* Custom SliderUI for AudioPlayer with audioimage in background
*/
public class AudioSliderUI extends BasicSliderUI {
private BasicStroke stroke = new BasicStroke(1f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 0f);
public AudioSliderUI(AudioSlider b) {
super(b);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
protected Dimension getThumbSize() {
return new Dimension(2, 200);
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Color.WHITE);
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
} else {
g2d.drawLine(trackRect.x + trackRect.width / 2, trackRect.y,
trackRect.x + trackRect.width / 2, trackRect.y + trackRect.height);
}
g2d.setStroke(old);
Image img = ((AudioSlider)slider).getImage();
g2d.drawImage(img, trackRect.x, trackRect.y, trackRect.width, trackRect.height, slider);
}
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = 100;
int newStarty = knobBounds.height/2- h/2;
g.translate(knobBounds.x, knobBounds.y);
// "plain" version
g.setColor(Color.YELLOW);
g.fillRect(0, newStarty, w, h);
}
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new TrackListener() {
#Override
public void mousePressed(MouseEvent e) {
if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag")
&& SwingUtilities.isLeftMouseButton(e)) {
JSlider slider = (JSlider) e.getComponent();
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
slider.setValue(valueForYPosition(e.getY()));
break;
case SwingConstants.HORIZONTAL:
slider.setValue(valueForXPosition(e.getX()));
break;
default:
throw new IllegalArgumentException(
"orientation must be one of: VERTICAL, HORIZONTAL");
}
super.mousePressed(e); // isDragging = true;
super.mouseDragged(e);
} else {
super.mousePressed(e);
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
};
}
}
Matching Slider:
public class AudioSlider extends JSlider {
private Image img;
public AudioSlider() {
setOpaque(false);
}
/**
* #return the img
*/
public Image getImage() {
return img;
}
public void setImage(Image img) {
this.img = img;
}
}
Works for me, maybe covers not all prospects.

Change Color BufferImage

I want to change the color of my BufferdImage.
When I do it like in this post: BufferedImage draw white when I say red it works only in my method which constructs my JFrame with all the components.
But when I want to use it in an ActionEvent in my Controller class, it does nothing, but the rest of the ActionEvent works, like for example change text in text field.
Methods in the JPanel class:
public void testImage(){
System.out.println("Methode suc. called");
Graphics g = image.getGraphics();
tempC = Color.GREEN;
g.setColor(tempC);
g.fillRect(150, 300, 100, 100);
tempC = Color.CYAN;
g.setColor(tempC);
g.fillOval(0, 0, 100, 100);
g.dispose();
if(image == null){System.out.println("Image is null");}
}
public void clearImage(){
Graphics g = image.getGraphics();
tempC = Color.WHITE;
g.setColor(tempC);
g.fillRect(0, 0, darstellungsBreite, darstellungsHoehe);
g.dispose();
}
The ActionListener:
public void actionPerformed(ActionEvent arg0) {
if(arg0.getActionCommand().equals(view.ACTION_CLEAR))
{
//Clear Graphics
view.drawArea.clearImage();
//view.useClear();
}

Blurred image instead of solid colours?

I am using BufferedImage for my background but when I reproduce it with the following code to make it bigger why does my image code produce blurred edges instead of solid colours?
public final class State_Play extends State_Template {
private BufferedImage background;
private int[] pixelelements;
private int width,height;
State_Play(){
init();
}
public void init(){
width=8; //Configuration.appwidth,
height=6; //Configuration.appheight
background=new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
pixelelements=((DataBufferInt) background.getRaster().getDataBuffer()).getData();
maketuringarray();
}
public void maketuringarray(){
int singlecolor=new Random().nextInt();
pixelelements[new Random().nextInt(width*height)]=singlecolor | 0xFF000000;
}
#Override
public void update() {
maketuringarray();
}
#Override
public void render(Graphics g) {
g.drawImage(background, 0, 0, Configuration.appwidth, Configuration.appheight, null);
}
Instead of solid colours?
Most likely the problem is that the interpolation on your platform is by default set to cubic or bicubic. This will make upscaling blurry.
Explicitly set it to nearest neighbour, to get the "blocky pixel" effect you want (if I understand you correctly):
#Override
public void render(Graphics g) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.drawImage(background, 0, 0, Configuration.appwidth, Configuration.appheight, null);
}

Cursor disappears while calling repaint in mouseMoved?

I have a problem with drawing horizontal and vertical lines from the cursor position while the cursor is moving. The cursor seem to disappear.
I've attached a MouseInputAdapter to my swing component, which has a mouseMoved method which call repaint();
Calling repaint will cause a paintComponent(Graphics g) to be called. In paintComponent i paint the horizontal and vertical line:
Dimension dim = getSize();
g2.setColor(Color.white);
g2.fillRect(0, 0, dim.width, dim.height);
g2.setColor(Color.black);
Point pos = this.getMousePosition();
g2.draw(new Line2D.Double(0, pos.y, dim.getWidth(), pos.y));
g2.draw(new Line2D.Double(pos.x, 0, pos.x, dim.getHeight()));
Here is a screenshot:
The cursor should be in the white area that exists between the big horizontal line and the vertical one and should be at the left of the big number 1.2434307...
When i move the cursor with my mouse i can see the cursor (crosshair) flickering which makes me believe my paint method is painting over the cursor.
Anyone know where the problem may lie?
As requested i've added a little test code.
public class TestApp extends JFrame {
public TestApp() {
super("TestApp");
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(new CustomComponent(), BorderLayout.CENTER);
this.setSize(300, 300);
this.setVisible(true);
}
class CustomComponent extends JComponent {
public CustomComponent() {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
MouseInputAdapter mia = new MouseInputAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
repaint();
}
};
addMouseMotionListener(mia);
addMouseListener(mia);
}
#Override
public void paintComponent(Graphics g) {
Dimension dim = getSize();
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.white);
g2.fillRect(0, 0, dim.width, dim.height);
g2.setColor(Color.black);
Point pos = this.getMousePosition();
if (pos != null) {
g2.draw(new Line2D.Double(0, pos.y, dim.getWidth(), pos.y));
g2.draw(new Line2D.Double(pos.x, 0, pos.x, dim.getHeight()));
g2.drawString("where is my cursor?", pos.x, pos.y);
}
}
}
public static void main(String[] args) {
new TestApp();
}
}

Categories