Ok i have a JPanel such as this one :
public class GUI {
JFrame frame = new JFrame("Net");
JPanel panel = new JPanel();
public GUI()
{
frame.setSize(835,650);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
frame.add(panel);
panel.setSize(600,600);
panel.setLocation(215,5);
panel.add(new DrawPlanes(300,300,200,Color.BLACK));}
There are some other panels in there tables etc. My main is this one :
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
//new GUI();
new GUI().buildTable();
}
});
And there i another class this one :
public class DrawPlanes extends JPanel
{
private static int centreX, centreY, radius;
private Color colour;
public DrawPlanes()
{
centreX = 300;
centreY = 300;
radius = 200;
colour = Color.BLACK;
}
public DrawPlanes(int centreX,int centreY, int radius, Color colour)
{
this.centreX = centreX;
this.centreY = centreY;
this.radius = radius;
this.colour = colour;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("ppp");
Graphics2D g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(2F));
g.setColor(Color.BLACK);
g.drawOval(centreX - radius , centreY - radius, radius * 2 , radius * 2);
......
}
}
Ok so i ve setted the background colour of my panel red to see whats going on the whole panel its red but there is a small grey square where i believe the drawings are. I ve tried to change opaque as there might be an incompatibility issue but nothing changed at all.Any suggestions,is there anything that i m missing?
link of what is the result of
panel.add(new DrawPlanes(300,300,200,Color.BLACK))
http://dc626.4shared.com/img/FeYopZC1/s7/142d22f1be0/2013-12-08_142846.png?async&rand=0.9010817544924218
what does the DrawPlanes class draws when i checked it having the main and a panel etc in the DrawPlanes itself http://dc626.4shared.com/img/NPDkiQRJ/s7/142d22f23b0/1451491_586878858047235_191988.jpg?async&rand=0.27479583155781395 .When i apply a layout manager that grey square just moves to the center when i use getPreferredSize overriden or not the whole red panel appears grey.
frame.add(component) function eventually add your component to frame's content pane which has BorderLayout as default layout manager.
A JPanel uses FlowLayout as default layout which respect component's preferred size.
As your 'panel' and 'frame' is satisfying above two as a default, size hint with setSize(Dimension) or setBounds(Dimenstion) to component won't have effect.
You should provide size hint using setPreferredSize(Dimenstion)(to DrawPanel instance of your context) and if specifying minimum/maximum size is needed setMinimumSize(Dimenstion) and setMaximumSize(Dimenstion).
However it is considered as a better practice to override getXXXSize(Dimenstion): xxx represents Preferred/Minimmum/Maximum always which allows to adjust size of component with it's content.
Instead of calling setSize(Dimension) on a window it is preferable to call pack() at the end of addition of child components.
We should call setVisible(true) after finishing addition of all of the child components and following above point, after pack().
Please, start with the tutorial: Laying Out Components Within a Container
Edit:
Let us edit your GUI() constructor code and see what happens:
public GUI()
{
frame.setSize(835,650);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//frame.setVisible(true); // <<--- call it at the end of the code
frame.add(panel);
//panel.setSize(600,600); <<--- removing set size
panel.add(new DrawPlanes(300,300,200,Color.BLACK));
frame.setVisible(true);
}
And the DrawPnales will extend JComponent:
public class DrawPlanes extends JComponent{
public DrawPlanes(int centreX,int centreY, int radius, Color colour)
{
this.centreX = centreX;
this.centreY = centreY;
this.radius = radius;
this.colour = colour;
}
#Override
public Dimension getPreferredSize() {
return new Dimenstion(width, height);
// ^ provide your required size
}
}
If this still doesn't make any sense to you, then please try learning Swing layout managers a little bit further. Otherwise no matter how hard we hit our head on the table, possibly we won't be able to achieve any thing.
You're missing the fact that panels are laid out inside their container using a LayoutManager. The default layout manager of JPanel is a FlowLayout. The FlowLayout uses the preferred width and height of the components it lays out to decide where to place them in the container, and which size they should have. But your DrawPlanes panel doesn't override getPreferredSize(), so its preferred size is the default one.
Every time you use setSize() on a component or frame, you have a 99.9% probability of doing something wrong. Learn layout managers. If you design a custom component like your DrawPlanes component, which is not just a container for other components, but has a custom paintComponent() method, then override getPreferredSize(), getMaximumSize() and getMinimumSize() to tell the layout managers how they should display your component, and to make sure your custom component always has the appropriate size. You never set the size of a JButton, right? That's because the JButton itself decides, based on the text and icon it contains, which size it should have.
Related
I have a board game (think Monopoly) where multiple game pieces can be located on a single tile. I want to be able to arbitrarily place game pieces on the any given tile. I want the tile to have a background (image or just flat color) and be able to place up to 4 game pieces on the tile in a grid. I am currently using this code but the circles do not display.
tank.png is a 135 x 135 pixel background.
GraphicsTile:
public class GraphicsTile extends JPanel {
public static final Dimension SIZE = new Dimension(135, 135);
public static final GridLayout MGR = new GridLayout(4, 4);
public GraphicsTile() {
super();
setLayout(MGR);
initGraphics();
setSize(SIZE);
add(new CirclePanel());
}
private void initGraphics() {
JLabel panel = null;
try {
Image image = ImageIO.read(new File("tank.png"));
panel = new JLabel(new ImageIcon(image));
panel.setSize(SIZE);
} catch (IOException e) {
e.printStackTrace();
}
add(panel);
}
}
CirclePanel:
public class CirclePanel extends JPanel {
public CirclePanel() {
setSize(33, 33);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.RED);
Ellipse2D.Float circle = new Ellipse2D.Float(50, 50, 0, 0);
g2d.draw(circle);
g2d.fill(circle);
}
}
public class GraphicsTile {
I don't know how your code compiles since your GraphicsTile doesn't extend any Swing component yet you use methods like setLayout(...) and setSize(...) which implies you are trying to use it like a JPanel.
You should not be using setSize(...). A Swing component should have a preferred size. Then the layout manager will set the size and location of the component based on the rules of the layout manager. I'm guessing you have a problem because the preferred size is (0, 0).
I also have no idea how you add the GraphicsTile to the parent component. Again it looks like you are using setSize() when you should let the layout manager position the tiles on the game board.
Also, if you want to have a background image with circles on top then you need a hierarchical structure. That is you need something like:
panel
background image
circle component.
So my suggestions are:
CirclePanel needs to implement the getPreferredSize(...) method to return the size of your custom painting.
Your GraphicsTile class needs to extend JPanel. You would then override the paintComponent(...) method to draw your background image. Now you can add the CirclePanel instances to the this panel which will use the GridLayout.
I want to draw customized elements on a JFrame.
I've tried it by creating a class UI (extends JFrame) and a class Component (extends JPanel). The component draws something on itself and the UI just adds this component. So until now, I've written this code:
File UI.java
package UIComponent;
import javax.swing.JFrame;
public class UI extends JFrame {
public UI(){
this.setSize(1024,684);
this.setTitle("This is just a test program.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
}
}
File Component.java
package UIComponent;
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.Graphics;
public class Component extends JPanel {
int x, y, w, h;
public Component(int x, int y, int w, int h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
#Override
public void paintComponent(Graphics g){
g.setColor(Color.red);
g.fillRect(this.x, this.y, this.w, this.h);
}
}
But the result is not that what I accept. It draws just one Rectangle.
The x/y/w/h values have no bearing on the actual size of the compnent which is likely to be 0x0, meaning that you'd be painting out side of the visible area of the component.
Start by overriding the getPreferredSize method and return a area which would allow you painting to be visible, something like....
public Dimension getPreferredSize() {
return new Dimension(x + w, y + h);
}
For example.
JFrame uses a BorderLayout by default, which means that it will only allow one component to be visible within any of its 5 available positions.
This means that your example will only show the last component added.
Depending on what you intend to achieve, you might consider using an OverlayLayout or some other layout manager.
Personally, unless you had a particular need, I would not worry about the x/y position of the painting, and simply paint from the 0x0 position of component, allowing the containers layout manager to deal with the actually positing.
I'd as reconsider some of your naming, as Component already exists in the API and may cause confusion, and components already have a concept of position and size...
Remember, the position of the component within its container has no effect on where the components drawing starts. That is, 0x0 is always the top left corner of the component.
Don't extend JFrame. You are not adding any new behaviour to the frame.
Don't call your class Component. There is already an AWT class by that name so you will probably cause Swing to stop working.
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
The default layout manager for a JFrame is a BorderLayout. By default when you add components to the frame without specifying a constraint they go to the CENTER. The CENTER can only contain a single component, so that is why you only see the last one added.
Instead try adding one component to the BorderLayout.NORTH and one to the SOUTH.
Also, the components won't paint properly because you need to override the getPreferredSize() method of you custom component so the layout manager can do its job:
#Override
public Dimension getPreferredSize()
{
return new Dimension(w, h);
}
Also, the paintComponent() method should invoke super.paintComonent().
Check out the Swing tutorial. You should be reading the sections on Custom Painting and Layout Managers for more information.
Also, the painting of your rectangles should be done at an x/y location of (0, 0) so that the entire painting will fit in the width/height of your component. If you want the rectangle to appear at a specific location then you should be using a null layout in which case you are responsible for setting the location and size of the component.
If you are trying to just paint shapes on a panel then you should probably be playing with the Shape class instead of creating custom components. See Playing With Shapes for more ideas.
Just adding a LayoutManager should give your the two rectangles you're looking for
public class UI extends JFrame {
public UI(){
this.setSize(1024,684);
this.setTitle("This is just a test program.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(new GridLayout(1, 2)); // I used a simple grid layout.
this.add(new Component(20,20,20,20));
this.add(new Component(40,30,20,20));
}
public static void main(String[] args){
SwingUtlities.invokeLater(new Runnable(){
public void run(){
new UI();
}
});
}
}
Try to draw a rectangle with different size, How to fit it in one frame proportionally(assume the frame is fixed)?
public class Draw extends JComponent {
public void paint(Graphics g) {
int width = 100;
int length = 100;
g.drawRect(10, 10, width, length);
}
}
public class DrawRect {
public static void main(String[] a) {
JFrame frame = new JFrame();
frame.setSize(400, 600));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Container content = frame.getContentPane();
content.add(new Draw());
}
}
Custom painting is done by overriding the paintComponent(...) method, not the paint() method. This advice is made daily. Search the forum for more information and examples.
If you want to know the space available to the component then you can invoke the getWidth() and getHeight() method. Once you know these values you can determine how big you want to paint your rectangle.
Components should be added to the frame BEFORE the frame is made visible.
You don't need to use the getContentPane() method. Since JDK5 you can just add components directly to the frame and they will be added to the content pane for you.
I believe JViewport does work with JPanel, but when I build a new class that extends JPanel, it seem as if the JViewport is ignore by the program. I don't know if I do anything wrong, so this is the test I conduct and still get the same result:
public class panel extends JPanel
{
public panel()
{
super();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawString("Hello World", 50, 50);
g.setColor(Color.RED);
g.fillRect(50,50,100,100);
g.setColor(Color.BLACK);
g.fillOval(100, 100, 50, 50);
}
}
public class test extends JFrame
{
private panel p;
public void init()
{
this.setSize(1000, 1000);
this.setLayout(new BorderLayout());
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
p = new panel();
p.setOpaque(false);
JViewport v = new JViewport();
v.setViewSize(new Dimension(200,200));
v.setViewPosition(new Point(2000,2000));
v.setView(p);
this.add(v,BorderLayout.CENTER);
}
public test()
{
init();
}
public static void main(String[] args)
{
test t = new test();
}
}
It suppose to show part of the painted JPanel, but the JFrame window just display the whole JPanel. Therefore, I don't know if I did any wrong or JViewport is not built for this purpose. If it is the latter, then it would be great if anyone can suggest a workaround solution.
Thanks
The BorderLayout you're using is causing the viewport, which is placed in the center, to take the entire space inside the frame, since there are no other components in that layout. That's how the BorderLayout works.
Thus the viewport is also given a bigger size than defined (the size is overwritten by the layout manager). Since the panel doesn't have a fixed size either, it will also be resized.
In order to change that, either use a different layout manager or set a minimum/maximum size for the viewport and override getPreferredSize() for the panel.
As a side note: don't use lower case class names like panel.
I need to restrict movement of a component (JInternalFrame) inside a JPanel.
More exact: a component should only move along one axis when dragged by the user.
I tried to do it by adding a component listener and reset the position
of one axis everytime the component moves. But it "vibrates"
(moves rapidly during dragging).
I even wrote a custom layout manager, it didn't help a little!
I guess, the problem is: Both the layout manager and the listener
handle the movement-event after the component is actually moved, right?
Any suggestions?
Should (can I) intercept some event, and modify it, before it's delivered?
There is no "event" you need to intercept. Once Swing processes the mouse event, it tells the component to move - and that's where you can tweak the movement values.
move, setLocation and resize are all just wrappers to setBounds. Extend JInternalFrame, override the setBounds() method and ignore the new value of x (or y if you want horizontal movement) before calling super.setBounds().
import javax.swing.JInternalFrame;
public class VerticalOnlyFrame extends JInternalFrame {
public void setBounds(int x, int y, int width, int height) {
super.setBounds(getBounds().x, y, width, height);
}
}
That should solve your example, although looking at the JRE code setBounds() is actually a wrapper to the deprecated reshape() method so if you're feeling brave override reshape() instead.
you might want to subclass your InternalFrameUI. I see in BasicInteralFrameUI.BorderListener.mouseDragged(event)(line 885 in version 1.129) a call to getDesktopManager().dragFrame(frame, newX, newY);
You could extend BasicInternalFrameUI to return a custom DesktopManager (extension of DefaultDesktopManager), where in dragFrame() you test the identity of your frame and adjust the axis.
edit:
thinking about it, you are right - it is too complex. as the UI for the internal frame defers to the DesktopManager of the JDesktopPane, you can set it there. here is a poc:
public Demo() {
JFrame frame = new JFrame();
frame.setSize(300,300);
JDesktopPane df = new JDesktopPane();
DesktopManager dm = df.getDesktopManager();
df.setDesktopManager(new DefaultDesktopManager(){
public void dragFrame(JComponent f, int newX, int newY) {
super.dragFrame(f, newX, 5);
}
});
JInternalFrame jif = new JInternalFrame("test ");
jif.setLocation(5, 5);
jif.setSize(150,100);
jif.setVisible(true);
df.add(jif);
frame.setContentPane(df);
frame.setVisible(true);
}