I must say I tried everything and I can't understand what's wrong with my code.
In my SIView class I create MainFrame which extends JFrame with specified resolution (let's say X,Y).
Then I create gamePanel which extends JPanel whith the same resolution as MainFrame, and add it to MainFrame. The problem is that effective resolution of the panel is twice as big (x*2, y*2). It's like the panel is being streched to be twice as big.
Frame will display only a quarter (upper left quarter) of the panel either with pack() or mannualy setting the size, unless I set it to double the resolution in which case It's ok, but that's not a proper way to do that(When calculating positions in the game I have to double everything or divide it by 2 to keep proper proportions). I even tried different Layout managers wthout any succes.
Here's the code of the main view class:
public class SIView implements Runnable {
private final MainFrame mainFrame;
private final GamePanel gamePanel;
public SIView(BlockingQueue<SIEvent> eventQueue) {
this.eventsQueue = eventQueue;
mainFrame = new MainFrame();
gamePanel = new GamePanel();
gamePanel.setVisible(true);
mainFrame.getContentPane().add(gamePanel);
// mainFrame.pack();
#Override
public void run() {
mainFrame.setVisible(true);
}
public void init() {
SwingUtilities.invokeLater(this);
}
//some code not related
}
the frame class:
public class MainFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 6513420589842315661L;
public MainFrame() {
setTitle("Space Intruders");
setSize(new Dimension(SIParams.RES_X, SIParams.RES_Y));
setResizable(false);
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
panel class:
public class GamePanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 8112087715257989968L;
private final PlayerShipView playerShip;
private final ArrayList<SmallEnemyShipView> smallEnemyShip;
private final ArrayList<LightMissleView> lightMissle;
public GamePanel() {
setPreferredSize(new Dimension(SIParams.RES_X, SIParams.RES_Y));
setMaximumSize(new Dimension(SIParams.RES_X, SIParams.RES_Y));
setBounds(0, 0, SIParams.RES_X, SIParams.RES_Y);
setBackground(new Color(0, 0, 0));
setLayout(new OverlayLayout(this));
setDoubleBuffered(true);
// TODO
playerShip = new PlayerShipView();
smallEnemyShip = new ArrayList<SmallEnemyShipView>();
lightMissle = new ArrayList<LightMissleView>();
this.add(playerShip);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
//some code not related
}
If I use LayoutManager and properly override getPreferredSize() in GamePanel, the code seems to work as expected:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jfree.ui.OverlayLayout;
public class SIView implements Runnable {
public static interface SIParams {
int RES_X = 500;
int RES_Y = 400;
}
public static class GamePanel extends JPanel {
public GamePanel() {
setBackground(new Color(0, 0, 0));
setLayout(new OverlayLayout());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(SIParams.RES_X, SIParams.RES_Y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
// some code not related
}
private JFrame mainFrame;
private GamePanel gamePanel;
#Override
public void run() {
mainFrame = createMainFrame();
gamePanel = new GamePanel();
mainFrame.getContentPane().add(gamePanel);
mainFrame.pack();
mainFrame.setVisible(true);
}
private JFrame createMainFrame() {
JFrame frame = new JFrame();
frame.setTitle("Space Intruders");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return frame;
}
public void init() {
SwingUtilities.invokeLater(this);
}
// some code not related
public static void main(String[] args) {
new SIView().init();
}
}
I also dropped the MainFrame class since it is not needed to extend JFrame in this context.
I just solved everything :D But I must say I feel stupid. The problem was with painting my components, in paintcomponent() method I painted rectangle on a relative position while changing component position also relatively. That gave the effect of 2xtimes movement etc. because while the component was moving the rectangle was moving inside of it too. I guess I have a lot to learn about Swing ;) Sorry for all this trouble ;)
PS. I didn't have to change anything in Panel/Frame classes except for using pack() method after everything.
Related
I was working on this lab in class and when I tried changing the background color it would stay at its default of white can someone please explain where I my programming went wrong.
import javax.swing.*;
import java.awt.*;
public class DemoPoly extends JFrame {
// constructor
public DemoPoly() {
// defines Frame characteristics
int size = 300;
setSize(size,size);
setTitle("a random window");
getContentPane().setBackground(Color.red);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main (String[] args){
// instantiates a JFrame
// exits on close (opional)
JFrame object = new DemoPoly();
}
public void paint (Graphics g){
// This provides the Graphics object g, where
// you are going to use you graphics primitive
// to paint on the content pane of the frame.
int[] arr = {0,100,100,0};
int[] yarr = {0,0,100,100};
Square object = new Square(arr,yarr,Color.red);
AbstractPolygon randSquare = new Square(arr, yarr, Color.red);
}
I see a couple of problems in your code:
Extending JFrame is like saying your class is a JFrame, JFrame is a rigid container, instead create your GUI based on JPanels. See Java Swing extends JFrame vs calling it inside of class for more information.
You're breaking the paint chain by removing the super.paint(g) call on the paint(...) method. When changing your GUI to extend JPanel instead of JFrame you should use the paintComponent(...) method instead. Take the Lesson: Performing Custom Painting in Swing.
You forgot to add #Override notation on the paint(...) method.
You're not placing your program on the Event Dispatch Thread (EDT) which could cause threading issues.
You can solve this by changing your main() method like this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
Instead of setting the JFrame size, override the getPreferredSize() method and call pack(). See Should I setPreferred|Maximum|MiniumSize in Java Swing?. The general consensus says yes.
Your problem gets solved by adding
super.paint(g);
on the paint(...) method:
#Override
public void paint(Graphics g) {
super.paint(g); //Never remove this
//Your code goes here
}
With all the above recommendations taken into account, your code should look like this now:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class DemoPoly {
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DemoPoly().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
CustomPanel cp = new CustomPanel();
cp.setBackground(Color.RED);
frame.add(cp);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
class CustomPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
Which produces this output (and is the same output that you'll get with your current code but better because it gives you more control over your components)
I'm don't understand your question. But here is code for change your background to RED;
public class DemoPoly extends JFrame {
public DemoPoly() {
// defines Frame characteristics
int size = 300;
setSize(size, size);
setTitle("a random window");
//change background here
getContentPane().setBackground(Color.red);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// instantiates a JFrame
// exits on close (opional)
JFrame object = new DemoPoly();
}
}
Your code is well. Maybe use #override in your paint method.
I've created a JFrame.
Inside this JFrame, I've created a JPanel.
Inside this JPanel I've created another JPanel (lets call it "A").
I've drawn in "A" a rectangle, and wanted to create buttons using graphics.
There is no rectangle in my gui. I could see that the paintComponent() method inside "A" is not being invoked.
Code:
The JPanels: (the child JPanel is inner class)
public class MemoryPanel extends JPanel {
public MemoryPanel(){
setPreferredSize(new Dimension(350,448));
}
#Override
public void paintComponent(Graphics g) {
//POSITIONING
setLayout(new BorderLayout());
//CREATE MEMORY BUTTONS
MemButton a=new MemButton();
//Drawing Rectangles for Memory
add(a,BorderLayout.CENTER);
}
private class MemoryButton extends JPanel{
public MemoryButton(){
setLayout(null);
setPreferredSize(new Dimension(87,40));
}
#Override
public void paintComponent(Graphics g){
Graphics2D td= (Graphics2D)g;
td.drawRect(0, 0, 20, 20);
}
}
}
You should program the JButtons first in order for your graphics to work as buttons. I belive this post will help you with that:
Creating a custom button in Java
I you want a rectangle to be the background for your buttons you can draw it in your main panel and add the buttons on it. Try using different Layouts to mantain some order.
I've made a simple GUI to test your code and the rectangle appears correctly.
I made no relevant changes in the code that you posted.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimpleJFrameProgram extends JFrame {
private static final long serialVersionUID = 1L;
public SimpleJFrameProgram() {
super("TEST");
initComponents();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private void initComponents() {
MemoryPanel memoryPanel = new MemoryPanel();
this.add(memoryPanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
new SimpleJFrameProgram();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
I've applyed minor changes to your MemoryPanel: replaced MemButton by your MemoryButton and fill the rectangle in red to improve its visibility for the test. Without this last change, the rectangle appears too.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class MemoryPanel extends JPanel {
public MemoryPanel(){
setPreferredSize(new Dimension(350,448));
}
#Override
public void paintComponent(Graphics g) {
// POSITIONING
setLayout(new BorderLayout());
// CREATE MEMORY BUTTONS
MemoryButton a = new MemoryButton();
// Drawing Rectangles for Memory
add(a,BorderLayout.CENTER);
}
private class MemoryButton extends JPanel{
public MemoryButton(){
setLayout(null);
setPreferredSize(new Dimension(87,40));
}
#Override
public void paintComponent(Graphics g) {
Graphics2D td = (Graphics2D) g;
td.setColor(Color.red);
td.fillRect(0, 0, 20, 20);
}
}
}
This is the obtained result:
Maybe your problem is located on initializing the parent JFrame.
Changing the class name of MemoryButton fixed it.
I had another package with the same class name.
I searched all over the Internet but could not find out why the circle is appears to be distorted beyond the middle of the JFrame(sorry,no image because i needed 10 reputation to post images).
I checked my code but found no errors.I'm a newbie to java GUI programming .
This is my code so far:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class test1 extends JPanel implements MouseMotionListener
{
private static final long serialVersionUID = -2068330714634802982L;
public int Mousex,Mousey;
public void init()
{
addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e)
{
Mousex=e.getX();
Mousey=e.getY();
repaint();
}
public void mouseDragged(MouseEvent e){}
public void paintComponent(Graphics g)
{
Graphics2D g2=(Graphics2D)g;
g2.setColor(Color.GREEN);
g2.fillOval(Mousex,Mousey,50,50);
}
public static void main(String[] args)
{
test1 t=new test1();
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1305,650);
frame.setLocationRelativeTo(null);
frame.getContentPane().add(t);
frame.setResizable(true);
frame.setVisible(true);
}
}
You need to call
t.init();
to register the MouseMotionListener. Also super.paintComponent(g); in the needs to be invoked in the paintComponent method to repaint the parent container otherwise the last rectangle wont be clearly visible.
You are never calling init() on your panel so you don't add the MouseMotionListener to the panel. Try adding
t.init();
after creating your panel object. Alternatively, add a constructor to your class that adds the MouseMotionListener instead, so it's adden right when you create an object of the class:
public test1 () {
addMouseMotionListener(this);
}
I have been trying to implement a GlassPane for my games' in-game HUD, but right now I cant seem to get the JFrame to set my GlassPane as its own i;ve used setGlassPane() and Ive been reading up a few examples trying to find my mistake, but nothing. So I wrote a SSCCE that demonstrates my problem. I have a JFrame to which I add a Jpanel with a label "TESTIING" then I initiate my galss pane and call setGlassPane() on my frames instance. My GlassPane has a MouseListener, a JPanel and 2 JLabels, and an overriden paint() however the MouseListener wont work the paint() wont show and my labels are not there (so basically my GlassPane is not being set as my frames new GlassPane)-
/*Main.java*/
import java.awt.EventQueue;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TestGlassPane testGlassPane=new TestGlassPane();
testGlassPane.setVisible(true);
}
});
}
}
/*TestGlassPane.java*/
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
class TestGlassPane extends JFrame{
private GlassGamePane m_glassPane;
private JPanel drawingPanel;
private JLabel testLabel;
public TestGlassPane() {
createUI();
}
private void createUI() {
setTitle("Test GlassGamePane");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(800, 700);
setResizable(false);
setLocationRelativeTo(null);
createComponents();
//add components to frames content pane
addComponentsToContentPane(getContentPane());
//setting glassPane
m_glassPane = new GlassGamePane();
//set opaque to false, i.e. make transparent
m_glassPane.setOpaque(false);
m_glassPane.setVisible(true);
getRootPane().setGlassPane(m_glassPane);
}
private void addComponentsToContentPane(Container contentPane) {
drawingPanel.add(testLabel);
contentPane.add(drawingPanel, BorderLayout.CENTER);
}
private void createComponents() {
drawingPanel=new JPanel(new BorderLayout());
testLabel=new JLabel("TESTIING");
}
}
/*GlassGamePane.java*/
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GlassGamePane extends JPanel implements MouseListener {
private JPanel statusPanel;
private JLabel healthLabel;
public GlassGamePane() {
createGlassPane();
}
private void createGlassPane() {
setLayout(new BorderLayout());
createComponents();
statusPanel.add(healthLabel);
add(statusPanel, BorderLayout.NORTH);
addMouseListener(this);
}
private void createComponents() {
statusPanel = new JPanel(new GridLayout(2, 6));
healthLabel = new JLabel("Player Health:");
healthLabel.setForeground(Color.RED);
healthLabel.setBackground(Color.BLUE);
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.red);
//Draw an oval in the panel
g.drawOval(10, 10, getWidth() - 20, getHeight() - 20);
}
#Override
public void mouseClicked(MouseEvent me) {
Toolkit.getDefaultToolkit().beep();
}
#Override
public void mousePressed(MouseEvent me) {
Toolkit.getDefaultToolkit().beep();
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
}
Thanks you.
It seems that you have to first add the custom GlassPane as your frames GlassPane before making the GlassPane visible! This code here seemed to work:
//setting glassPane
m_glassPane = new GlassGamePane();
setGlassPane(m_glassPane);
//set opaque to false, i.e. make transparent
m_glassPane.setOpaque(false);
m_glassPane.setVisible(true);
From the JavaDoc: http://docs.oracle.com/javase/7/docs/api/javax/swing/JRootPane.html#setGlassPane(java.awt.Component)
You need to set the glasspane to visible after adding it the JRootPane.
seems like as Glasspane is correcty created, but Glasspane to overlay only lightweight JComponent otherwise is behind, hidden be heavyweight Swing or AWT J/Component
Glasspane has not implemented any LayoutManager, you have to set proper LayoutManager
for testing put non opaque JLabel with some Background
I m love Glasspane, but you can to use JLayer (Java7) based on JXLayer (Java6) or OverlayLayout, as easiest of ways
i am writing a stand alone app in java using a couple of JPanel with different layouts in order to arrange the user interface.
now my problem is that when i take the upper side of the window (its a pannel in a border layout which is inside another panel which using border layout),im tring to add a class that extends panel is order to paint an icon on the top of my window (draw on the panel) . the problem is that the layout is cuting a part of the icon, or in other words, minimazing the panel to a certain size.
i tried changing to flowlayout and others but is does the same...
so i wanted to ask if an option which tells the layout that a container (panel or others) can not be set to a size lower then a given size exists? other suggestions will allso help but keep in mind that i am tring to add the icon with mininal change to the GUI.
thanks for reading this and helping
moshe
Container can hold MinimumSize for JComponent, simple example,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CustomComponent extends JFrame {
private static final long serialVersionUID = 1L;
public CustomComponent() {
setTitle("Custom Component Graphics2D");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponents());//
pack();
// enforces the minimum size of both frame and component
setMinimumSize(getSize());
setVisible(true);
}
public static void main(String[] args) {
CustomComponent main = new CustomComponent();
main.display();
}
}
class CustomComponents extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}