When drawing on my extended JPanel I want the size to be variable. I've worked out the code to always outline a 1 pixel margin. My code works but I don't understand why I must adjust the height and width and height of the dimension by -1 when drawing the rectangle.
If I draw a rectangle that has 1,1 as a size it draws a single pixel square so shouldn't drawing the width and the height work without the -1 modifier.
If any one can explain why there is a discrepancy between the size of my extended JPanel or explain a better way to get the exact dimensions of the drawing area I would appreciate it.
public class Engine extends JPanel {
Engine(){
}
#Override
public void paintComponent(Graphics g){
Dimension a = this.getSize();
g.setColor(Color.RED);
g.drawRect(0, 0, a.width-1, a.height-1);
}
}
Remember, most values are 0 based. But instead of having to say, " I want the width of my panel to be 199" so you get a panel that is 200 pixels wide (0-199), Swing allows you to specify 1 based values and makes adjustments internally
If you create a rectangle of 1, 1, 1, 1, your actually creating a rectangle at position 1x1, whose width & height is 1 pixel (1 + 1 would be 2)
"or explain a better way to get the exact dimensions of the drawing area I would appreciate it."
Override getPreferredSize() in your JPanel class
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
When you you paint, make use of getWidth() and getHeight(), inherited from the JPanel class. Using these methods, your painting will resize dynamically with the resizing of the panel.
int width = getWidth();
int height = getHeight();
g.fillRect((int)(width * 0.9), (int)(height * 0.9),
(int)(width * 0.8), (int)(height * 0.8));
Side Note
You should call super.paintComponent inside the paintComponent method so as not to break the paint chain.
paintComponent should be protected not public
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
I've worked out the code to always outline a 1 pixel margin.
Don't do custom painting. Use a Swing Border. See How to Use Borders. You probably want a LineBorder.
Related
If you run the code below, you will see that there is a red square with a blue line along the bottom and right edges of the square. However, as you can see in the code, the parameters for the rectangle being drawn are the same as the rectangle being filled.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.blue);
g.drawRect(50, 50, 100, 100);
g.setColor(Color.red);
g.fillRect(50, 50, 100, 100);
}
};
panel.setPreferredSize(new Dimension(200, 200));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
Does anyone know the reasoning behind this behavior? Or is this a bug in Java's codebase?
It seems like drawing the rectangle adds 1 to the width and height of the rectangle you specify. This seems like un-intuitive behavior for one, but in my case it is also causing some undesired effects for a gui I am building.
This behavior is also found when drawing polygons with horizontal/vertical lines. Is there a simple way of getting some consistency in what is painted between the graphics draw and fill functions? It would be great if there was a way for any arbitrary polygon to completely paint over a previously drawn polyline using the same points.
One approach I had thought of was to both draw and fill whenever I want to fill a polygon and then just draw when I want to draw the polygon.
This would actually work in cases of opaque polygons, but in my case I have both opaque and transparent polygons so this approach is not an option.
This is clearly documented in the Graphics API:
drawRect
public void drawRect(int x,
int y,
int width,
int height)
Draws the outline of the specified rectangle. The left and right edges of the rectangle are at x and x + width. The top and bottom edges are at y and y + height. The rectangle is drawn using the graphics context's current color.
and
fillRect
public abstract void fillRect(int x,
int y,
int width,
int height)
Fills the specified rectangle. The left and right edges of the rectangle are at x and x + width - 1. The top and bottom edges are at y and y + height - 1. The resulting rectangle covers an area width pixels wide by height pixels tall. The rectangle is filled using the graphics context's current color.
Note the difference in the calculation for the right and bottom edges. Although this difference is clearly documented, there is no justification for this difference.
Finally, note that the first line of paintComponent() should be super.paintComponent(g);. This will ensure that the super class has a chance to initialize things, including clearing the region where you will draw.
I have a paint component where I draw some shapes but the problem my shapes exceed jPanel Size . because of that I search a solution of zoom jpanel. I don't know if this possible could someone help me I use net beans gui builder
If you want the shapes to size according to your JPanel, make use of the JPanel's getWidth() and getHeight() e.g.
int x = (int)(getWidth() * 0.1);
int y = (int)(getHeight() * 0.1);
int width = (int)(getWidth() * 0.8);
int height = (int)(getheight() * 0.8):
g.fillRect(x, y, width, height);
See a full running example here
You can see here how to customize initialization code for your JPanel in GUI Builder
Add your JPanel to a JScrollPane and add the JScrollPane to the container you were originally adding your JPanel to. Make sure to setPreferredSize to a size large enough to see all of your drawings whenever you draw a new shape or however you are doing your graphics.
I am trying to create a shape inside of a JPanel, and as the JPanel increases and decreases the size of the shape also changes accordingly.
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(0,100,50,0);
}
My problem is that I don't know how to scale it using something along the lines of this.getHeight() or this.getLength().
Besides the path outlined by #MadProgrammer, there are two other ways I can think of to scale graphics.
Swing components can generally rely on the Graphics object actually being a Graphics2D object.
We can then use Graphics2D.scale(sx,sy).
A scale instance of an AffineTransform (obtained using getScaleInstance(sx,sy). Set it to the Graphics2D before drawing.
Using either method, the original co-ordinates will be scaled as needed.
Assuming you mean you want to maintain a proportional ratio as the component size changes...
There are a few ways to do this...
You could start by determining the "default" values, that is, if the "preferred" width was 200, the line start point would 50% of the width and the end point would be 25% of the width.
This would allow you to do something like...
int width = getWidth();
int x1 = (int)(Math.round(width * 0.5d);
int x2 = (int)(Math.round(width * 0.25d);
g.drawLine(0, x1, x2, 0);
I have a JScrollPane with a JPanel where I can draw by mouse and code.
I need the possibility to zoom on details in my drawing.
But soon I get a outOfMemoryError. I think because I make my drawing to big while zooming.
This is my code:
private BufferedImage _bufferedImage;
private int _panelWidth = 2000, _panelHeight = 1500;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(_bufferedImage != null){
g.drawImage(_bufferedImage, 0, 0, this);
}
}
public void draw(float zoomFactor){
try {
int width = (int)(_panelWidth * zoomFactor);
int height = (int)(_panelHeight * zoomFactor);
_bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = _bufferedImage.createGraphics();
g2.setBackground(Color.WHITE);
g2.setPaint(Color.BLACK);
g2.scale(zoomFactor, zoomFactor);
drawHouse(g2); ...
g2.dispose();
}
catch (Exception e) {
e.printStackTrace();
}
repaint();
}
There must be better practice then what I did.
I can just draw the area of the scrollpane, but then I can't use the scrollbars,
then I have to use buttons with arrow up, right, left, down to scroll in my drawing.
Anyone who can me give a hint?
but then I can't use the scrollbars
Scrollbars work when the preferred size of the component is greater than the size of the scrollpane. If you are zooming the image in the paintComponent() method then you would also need to override the getPreferredSize() method to return the appropriate size of the image that takes into account the zooming factor.
So in your case the preferred size would be the size of your image.
If you want to zoom in, I am assuming you are no trying to make "bigger pixels", but to draw the same figures at a higher scale. In that case, you should not be using a BufferedImage at all -- instead, you should draw to a suitably scaled JPanel or similar. You can always take a snapshot of whatever you are rendering whenever you need it; but rendering to a BufferedImage without need is wasteful (of time and memory).
See this answer for details.
Is there anything obvious wrong with this line of code? I want rectangle to stay centered regardless the size of the window. But this donĀ“t work for some reason, the rectangle stays the same place.
public void run() {
setSize(800, 800);
createEntireFigure();
}
private void createEntireFigure(){
int centerOfWindowWidth = getWidth() / 2;
int centerOfWindowHeight = getHeight() / 2;
GRectWithGLabel ("A String",centerOfWindowWidth, centerOfWindowHeight);
}
Your rectangle size code is only called on rectangle creation, and so it makes sense that the rectangle's position will not change if the GUI is re-sized. You need to somehow listen for size changes in your GUI and call code to re-position the rectangle then for this to work. What graphics library are you using?