I want to draw my background image in the middle of the frame. As my image is not as big as the window, I want to put a black background.
Here is the code I use:
public void paint(Graphics g)
{
if(this.background != null)
{
int bounds_top = getHeight() / 2;
int bounds_left = getWidth() / 2;
int half_height = this.background.getHeight(null) / 2;
int half_width = this.background.getWidth(null) / 2;
g.drawImage(this.background, bounds_left - half_width, bounds_top - half_height, this.background.getWidth(null), this.background.getHeight(null), this);
this.setBackground(Color.black);
//this.setOpaque(false);
}
}
If I set the frame to be opaqe, my image is displayed but the background is gray.
If I set opaque to false, my frame is just black, no image is displayed.
So here is my question, how can I display my image and have a back background?
If you are doing this in a JPanel child, call setBackground(Color.black); in the constructor, and implement the code in paintComponent first calling super.paintComponent(g); for the black background.
You are drawing the image to the background, and then setting the background color to black. Try setting the background color to black first, and then draw the image to it. Otherwise it looks like you are drawing black over the image.
I found a litle trick to solve it:
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.BLACK);
g2.fill(new Rectangle2D.Double(0, 0, getWidth(), getHeight()));
g.drawImage(this.background, bounds_left - half_width, bounds_top - half_height, this.background.getWidth(null), this.background.getHeight(null), this);
This works well.
Related
I am coding a Swing Application, it uses Apache PDFBox to draw a PDF page to the Graphics2D object of a JPanel in the paintComponent method. The drawing takes a while, so when my application needs to display many PDF pages simultaneously, it get's slow and laggy. I know, since the JPanel I draw the PDF page to is part of the GUI, it needs to be drawn in the Event Dispatch Thread. But is there absolutely no possibility to draw each JPanel in an own thread? Like using SwingWorker or so?
Example code (simplified):
public class PDFPanel extends JPanel {
#Override
protected void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g2 = (Graphics2D) graphics;
int scale = 1; // (simplified this line)
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
try {
pdfRenderer.renderPageToGraphics(pageNumber, g2, (float) scale, (float) scale);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Use a BufferedImage image field. It has a method createGraphics() where you can draw to. Afterward call Graphics.dispose() to clean up resources.
Then in paintComponent check the availability of the image, for displaying it.
The rendering can be done in a Future, SwingWorker or whatever. You are right that heavy operations should never be done in paintComponent especially as it may be called repeatedly.
Better launch the rendering in the constructor, or in your controller.
BufferedImage image = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = image.createGraphics();
try {
pdfRenderer.renderPageToGraphics(pageNumber, g2, (float) scale, (float) scale);
} finally {
g2d.dispose();
}
Initially width and height are not filled, so better use width and height from the PDF. Also not that a Graphics2D allows scaling; you could easily add zooming.
How to atomically handle passing the rendered image is probably clear.
I want to draw a circle on a buffered image that act like a png
i want to use this circle in order to replace the mouse cursor for a paint application i am working on.
i cant download a circle png from google as i need to keep changing the size of this circle depending on the width of the tool i am using it for.
here is my attempt so far
public static BufferedImage getCircle() {
BufferedImage bufferedImage = new BufferedImage(30, 30, BufferedImage.TYPE_INT_RGB);
Color transparent = new Color(0x00FFFFFF, true);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
//trying to make the bufferedImage transparent
g.setComposite(AlphaComposite.Src);
g.setColor(transparent);
g.setBackground(transparent);
g.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
//drawing the circle
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g.drawOval(0, 0, 200, 200);
return bufferedImage;
}
it should look like:
However my code currently only creates a white square.
Your code has two problems (as already shown in the comments). The first is that you draw a circle with a radius of 200px into an image of dimensions 30px. If you closely look you can barely see a black pixel in the lower right corner.
Fix it by adjusting your dimensions such that it fits inside, for example like:
BufferedImage bufferedImage = new BufferedImage(60, 60, BufferedImage.TYPE_INT_RGB);
...
g.drawOval(5, 5, 50, 50);
Next is that you want to achieve a transparent background. To do so you need to set the type of the image to a color model which supports transparency, like ARGB (A = Alpha = transparency) instead of RGB:
BufferedImage bufferedImage = new BufferedImage(60, 60, BufferedImage.TYPE_INT_ARGB);
Last you probably want to increase the thickness of your border to achieve the image you showed. You do so by using g.setStroke(...):
g.setColor(Color.BLACK);
g.setStroke(new BasicStroke(5));
g.drawOval(5, 5, 50, 50);
With this setting you achieve the following result (with transparency):
Play with the values to adjust the circle to your exact needs.
I am new to the graphics and paint on java swing component. I have a few code issue related to these areas.
I have a customJPanel that extends JPanel. Inside the panel, there is a "+" and "-" button to increase the number of image by 1 at a time (minimum 1 image, maximum 50 image). The images are already stored in a list. The buttons are listener that takes care of the add/remove image on the customJPanel:
//ADD BUTTON LISTENER
imagePanel.add(imageList.get(i);
add(imagePanel, BorderLayout.CENTER); //customPanel contains a imagePanel(center), and another panel(south)
repaint();
revalidate();
Once the images are added, I have a function that draws lines to link the images to a fixed point(x1, y1) on the JPanel.
public void drawLinkedLine(){
Graphics2D g2d = (Graphics2D) imagePanel.getGraphics();
g2d.setColor(Color.BLACK);
for(int i = 0; i < imagesList.size(); i++){
//some codes to get the image location on the imagePanel
g2d.drawLine(x1, y1, x2, y2);
}
}
This method is called by the override paintComponent(Graphics g):
public void paintComponent(Graphics g){
super.paintComponent(g);
drawLinkedLine();
}
The issues I am facing now is when I click on the button, it adds/removes 1 image. It suppose to draw line from that image to (x1,y1). However, I can see the lines appear in a flash and disappear. Why would this happening and is there a way to solve this?
I am trying to plot a graph using the java 2d graphics library and I thought I had it. I want to plot in the coordinate system where 0,0 is in the center of the panel on the left edge. I used the following code and it seemed to give me the result I needed.
private void doDraw(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
AffineTransform saveAT = g2d.getTransform();
// get the height of the panel
int height = getHeight();
// Find the middle of the panel
double yTrans = ((double)height)/2.0;
AffineTransform tform = AffineTransform.getTranslateInstance( 0.0, yTrans);
g2d.setTransform(tform);
//draw the line for the x-axis.
g2d.drawLine(0, 0, 100, 0);
//restore the old transform
g2d.setTransform(saveAT);
}
This plotted the origin centered in the window.
The problem shows itself when I added a menu. Then the origin was offset in the y direction about twice the size of the menu higher then it should be. Do I need to account for the size of the menu and other containers that I add to the panel?
private void doDraw(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
int height = getHeight();
double yTrans = ((double)height)/2.0;
AffineTransform tform = AffineTransform.getTranslateInstance( 0.0, yTrans);
g2d.transform(tform);
//draw the line for the x-axis.
g2d.drawLine(0, 0, 100, 0);
}
works, thank you for your help
You might try the approach outlined here. Override paintComponent() to obtain a graphics context relative to the enclosing panel, rather than the enclosing frame.
To center the origin at the left edge, use
g2d.translate(0, h / 2);
To get upright, cartesian coordinates, use
g2d.scale(1, -1);
Changing the BasicStroke of a Graphics2D object to anything other than 1 causes it to not draw something on the center of a JPanel on startup.
This is a JPanel which is on a JFrame. This is the basic idea of my project, but it is not the entire thing.
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if(this.centered){
this.myShape.setCenterX(this.getWidth()/2);
this.myShape.setCenterY(this.getHeight()/2);
}
g2.setStroke(new BasicStroke(3)); //new BasicStroke(1) works fine
g2.draw(this.myShape);
}
When you click and drag the myShape, myShape will immediately jump to the center. But when I initially compile and run it, paintComponent() paints it about a centimeter above the center of the screen if the stroke is not 1.
Is there something wrong with how I'm centering? I defined the MyShape class, so there could be an error there. Maybe the distance between the center and the drawing point is the space between JPanel and the top of the JFrame? How do I fix it?
Edit: added picture
http://s21.postimage.org/dfpmz73et/Untitled_1.png
The first shape is right where I want it. The other two are above where I want it. But it appears the displacement from the center are the same regardless of stroke size.
Yes, I believe this is the normal behaviour for a shape. It assumes an outline of 1 pixel. So you need to change the center calculation when you know you are going to change the basic stroke size. Something like:
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
BasicStroke stroke = new BasicStroke(3);
int adjustment = stroke.getLineWidth() - 1;
if(this.centered){
this.myShape.setCenterX(this.getWidth() + adjustment / 2);
this.myShape.setCenterY(this.getHeight() + adjustment / 2);
}
g2.setStroke(stroke);
g2.draw(this.myShape);
}