Canvas/JPanel not displaying on the JFrame? - java

I have a MyFrame class which extends JFrame . I added components(Controls i.e buttons) to this frame using the design options in NET BEANS. I have a MyCanvas class which extends JPanel with an overridden paintComponent() method . I am trying to add this component to MyFrame class. But when i add it and make it visible the canvas(JPanel) doesn't show itself on the JFrame.
(First I was trying to add Mycanvas class extended by Canvas. But then i read a thread here to try and change it to JPanel. I didn't work either. And for canvas i obviously use paint not paintcomponent())
My code is here below
MyCanvas Class
public class MyCanvas extends javax.swing.JPanel{
MyCanvas()
{
super();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics2D=(Graphics2D)g;
graphics2D.drawRect(10, 10, 10, 10);
graphics2D.drawOval(0, 0, 100, 100);
}
}
MyFrame
public class Myframe extends javax.swing.JFrame {
public Myframe() {
initComponents();
#SuppressWarnings("unchecked")
+generatedcode by the designer
private void RectangleActionPerformed(java.awt.event.ActionEvent evt) {
}
private void SquareActionPerformed(java.awt.event.ActionEvent evt) {
}
private void CircleActionPerformed(java.awt.event.ActionEvent evt) {
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Myframe().setVisible(true);
}
});
}
public void run() {
new Myframe().setVisible(true);
}
// Variables declaration - do not modify
private javax.swing.JButton Circle;
private javax.swing.JButton Rectangle;
private javax.swing.JButton Square;
// End of variables declaration
}
My Main Program
public static void main(String[] args) {
MyCanvas c = new MyCanvas();
Myframe f= new Myframe();//Works if used JFrame instead of MyFrame
f.add(c);
f.setVisible(true);
}
Basically i want to create a GUI in which i want Buttons which can trigger events and change what is drawn on a canvas. I tried it with an empty jframe. added the canvas/panel to the JFrame . It worked. Also I changed my Panel/Canvas and refresehed the frame. That also worked fine. But i am unable to do it like this.

The is that you are mixing creating JFrame with IDE and creating JPanel yourself, remember the IDE adds all components to JFrame in initComponents() which is ideally where you'd want to have your Canvas added.
either create the JFrame and JPanel by yourself (without use of Netbeans GUI Builder)
or
You can use the Palette Manager of Netbeans to add your Component to the palette, then you can use it in the GUI builder as you would any other class:
How can I use a custom subclass of a Swing component?
(Simply drag the Canvas class from the projects tree on to the JFrame in the GUI designer)
To make sure your custom Canvas functions:
override getPrefferedSize(..) and return a size which fits
Reference:
How to include custom panel with NetBeans GUI Builder?

Try changing it to:
public static void main(String[] args) {
MyCanvas c = new MyCanvas();
Myframe f= new Myframe();//Works if used JFrame instead of MyFrame
f.add(c);
c.setVisible(true);
f.setVisible(true);
}
Also, the code in your MyFrame class:
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Myframe().setVisible(true);
}
});
}
won't be executed unless you are running MyFrame instead of your program main.
Also check that you have a super() call in your MyFrame constructor.

#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
Graphics2D graphics2D=(Graphics2D)g;
graphics2D.drawRect(10, 10, 10, 10);
graphics2D.drawOval(0, 0, 100, 100);
}

Related

How do i switch between screens in swing

This has been asked before but I would like clarification, I'm new to java coding (sort of, started coding last month) and would like to know simply how can I switch between UIs in one JFrame, Picture this, a settings menu, How do I make it in one JFrame window instead of just make a new window with all the settings, If you don't get it, ask for clarification.
You can implement a frame (JFrame) and, for example, two panels (JPanel). Initially you embed panel A inside frame, when you want to show panel B then call the method showPanelB()
public class MyFrame extends JFrame {
PanelA panelA = new PanelA();
PanelB panelB = new PanelB();
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MyFrame().setVisible(true);
}
});
}
public MyFrame() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new BorderLayout());
showPanelA();
}
public void showPanelA() {
getContentPane().add(panelA, BorderLayout.CENTER);
}
public void showPanelB() {
getContentPane().add(panelB, BorderLayout.CENTER);
}
}
class PanelA extends JPanel {
// Panel implementation
}
class PanelB extends JPanel {
// Panel implementation
}

How can I make changes to a JFrame GUI outside of the runnable in main?

I'm currently learning Java GUI, and I'm making a Java program where you can edit shapes with text within a GUI. I've created a JFrame which contains a custom MyCanvas object and a text field. The idea is that the MyCanvas object has a MouseListener and will contain shapes, these shapes when clicked will enable the text field in the GUI so that the user can enter a new message to be displayed in the shape. However, I'm running the GUI with a Runnable inside the GUI class's main method, and I can't enable the text box from the MyCanvas class since it's outside of the Runnable. Could anyone help me how to make this possible?
Here's the basic structure of my code (pseudocode):
// GUI class
public class GUI extends JFrame implements ActionListener {
private static MyCanvas c = new MyCanvas(); // canvas
private static TextField editor = new TextField(); // text field
public static void init() {
// initialize GUI elements and disable text box
}
public static void enableTextBox() {
// enables the text field
}
public static void disableTextBox() {
// disables the text field
}
public void actionPerformed(ActionEvent e) {
// get message from text box
}
public static void main(String[] args) {
// Run the GUI frame
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
init();
/* Add a RectTextBox (a Rectangle object with text inside,
* class defined elsewhere)
*/
c.addShape(new RectTextBox("Hello World");
}
}
}
}
// Canvas class
class MyCanvas extends JPanel implements MouseListener {
// ArrayList of blocks on the canvas
ArrayList<RectTextBox> blocks = new ArrayList<RectTextBox>();
// Ctor
public MyCanvas() {
// Initialize canvas and add MouseListener to this canvas
}
public void paintComponent(Graphics g) {
// Paints all blocks on canvas
}
public void addShape(RectTextBox b) {
// Adds the text box b to the blocks ArrayList
}
public void mouseClicked(MouseEvent e) {
// check if any blocks from the ArrayList is clicked
/* enables the text field from GUI to enter messages, then set the
* message entered to the block
*/
}
}
So, you're off to a good start. MyCanvas has functionality which can be called by other classes, for example, addShape...
// Canvas class
class MyCanvas extends JPanel implements MouseListener {
// ArrayList of blocks on the canvas
ArrayList<RectTextBox> blocks = new ArrayList<RectTextBox>();
// Ctor
public MyCanvas() {
// Initialize canvas and add MouseListener to this canvas
}
public void paintComponent(Graphics g) {
// Paints all blocks on canvas
}
public void addShape(RectTextBox b) {
// Adds the text box b to the blocks ArrayList
}
public void mouseClicked(MouseEvent e) {
// check if any blocks from the ArrayList is clicked
/* enables the text field from GUI to enter messages, then set the
* message entered to the block
*/
}
}
Next, you need to pass a reference of MyCanvas to those classes which want to perform some operation on it, as a "really" basic example...
public class EditorPane extends JPanel {
private MyCanvas canvas;
public EditorPane(MyCanvas canvas) {
this.canvas = canvas;
// Build UI as required
}
}
Then when EditorPane wants to make a change, it can use canvas to call the methods it needs to.
Then, we you build your UI, you would make an instance of MyCanvas, pass that reference to both the EditorPane and add it to the UI, for example...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MyCanvas canvas = new MyCanvas();
EditorPane editor = new EditorPane(canvas);
JFrame frame = new JFrame();
frame.add(canvas);
frame.add(editor, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
Now, personally, I'd fold much of this up into interface to prevent EditorPane from doing more to MyCanvas then it should, but that's a topic for another day ;)

JPanel doesn't want to focus so KeyAdapter doesn't work

Background
I had a simple game. I had one JPanel class and there were every thing (menu, game, game end).
Then I decided, that I should make my game better and I made two panels(one for menu, and second for game lvls).
Every thing were good, but my KeyAdapter class doesn't work at my JPanel. I don't know why it doesn't want to focus.
There is what I have:
Main class which extends JFrame and here I add my panels (and KeyListener to first panel)
public class JavaGame2 extends JFrame {
public JavaGame2(){
gamePanel = new GamePanel();
menuPanel = new MenuPanel();
setContentPane(menuPanel);
menuPanel.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
menuPanel.changeCursor();
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
menuPanel.changeCursor();
}
if (menuPanel.getCursorPos()==1){
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
setContentPane(gamePanel);
//add(gamePanel);
}
}
else{
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
System.exit(0);
}
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
}
MenuPanel class extends JPanel
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(){
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
public void actionPerformed(ActionEvent e) {
}
}
And here GamePanel class
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (){
addKeyListener(new GameAdapter());
setFocusable(true);
requestFocus();
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
private class GameAdapter extends KeyAdapter{
public void keyReleased(KeyEvent e) {
ship.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
ship.keyPressed(e);
}
}
}
It doesn't work. GamePanel don't want to focus, I tried to do every thing that I read.
I think u will say that JPanel is not focusable component. But when there was one panel it somehow worked.
How can I fix this focus problem?
Maybe u will say that u prefer don't use KeyAdapter, but I think it looks pretty nice in my code.
setFocusable()? or requestFocus()? requestFocusInWindow()? How should I use them? Maybe I have mistake before and this is not my first problem?
Thanks in advance.
And Thanks for editing.
Short answer, use the key bindings API, it allows you to control the level of focus that a component requires before key events are triggered.
Longer answer, the active panel needs to have keyboard focus. You can use requestFocusInWindow, but there is no guarantee that the component will actually receive focus. When to call this is a tricky thing. You could try overriding addNotify of the panels and calling to there, just make sure you call super.addNotify first, weird things happen when you don't
You will also need to consider what will happen if the component loses focus
As a side note:
setDoubleBuffered(true); is irrelevant, as Swing components are double buffered by default. Generally you might disable this if you wanted to print the component. No harm in calling it though
Calling setSize on your components is irrelevant, as you components will be under the control of a layout manager, which will determine the size of the component itself. You'd be better off overriding getPreferredSize and returning an appropriate size for the layout manager
Calling setSize on JFrame is also a bad idea. Frames have borders, this means that your viewable area will be the frame size - the frames border insets, which will be less the 800x600 you've specified. Better to utilise the previous comment and call pack on the JFrame, which will pack the frame around the content so that it meets the contents requirements...
Personally, I would also localise the KeyListener to the actually component itself, this allows the component to act as it's own controller making it more portable...IMHO
Updated with controller idea...
A "really" simplified concept would be to have some kind of "controller" that the menu and game panel could communicate through, for example...
public interface GameController {
public void showMenu();
public void showGame();
}
You would then pass a reference of this interface to the MenuPanel...
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
And the GamePanel...
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
You would, obviously, need to construct a implementation of the controller...
public class CardLayoutGameController implements GameController {
public static final String GAME_PANEL = "GamePanel";
public static final String MENU_PANEL = "MenuPanel";
private Container container;
private CardLayout cardLayout;
public CardLayoutGameController(Container parent, CardLayout layout) {
container = parent;
cardLayout = layout;
}
public void showMenu() {
cardLayout.show(container, MENU_PANEL);
}
public void showGame() {
cardLayout.show(container, GAME_PANEL);
}
}
You would then construct your UI around this controller, for example...
public class JavaGame2 extends JFrame {
public JavaGame2(){
CardLayout layout = new CardLayout();
setLayout(layout);
GameController controller = new CardLayoutGameController(getContentPane(), layout);
gamePanel = new GamePanel(controller);
menuPanel = new MenuPanel(controller);
add(gamePanel, CardLayoutGameController.GAME_PANEL);
add(menuPanel, CardLayoutGameController.MENU_PANEL);
controller.showMenu();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
});
}
}
Is this just an "example" to help spark the idea, haven't tested this, just hacked out here so it might blow up :P

PaintComponent in JPanel not being called

I'm writing an Java Application and trying to paint an BufferedImage. In my main, the JFrame is being created and the JPanel is being created and is being added to the JFrame. There is also a Thread being started for repainting, but it shows nothing and my System.out.println() in the paintComponent isn't called, too. I've googled this a lot, but i found nothing to solve my problem.
What am i doing wrong and why is it wrong???
My Code:
The main + Thread:
public class Main extends Thread
{
public static Frame frame = new Frame();
public static void main(String[] args) throws IllegalStateException, IOException
{
frame.activePanel = new LoginPanel();
frame.add(frame.activePanel);
new Main();
}
public Main()
{
this.start();
}
#Override
public void run()
{
while(true)
{
if(Main.frame.activePanel != null)
Main.frame.activePanel.repaint();
try{Thread.sleep(15);}catch(InterruptedException e){}
}
}
}
The JFrame:
public class Frame extends JFrame
{
public JPanel activePanel = null;
public Frame()
{
super();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(this.getToolkit().getScreenSize().width / 2 - 640,this.getToolkit().getScreenSize().height / 2 - 400,1279,799);
this.setResizable(false);
this.setUndecorated(true);
this.setVisible(true);
}
}
and the JPanel:
public class LoginPanel extends JPanel
{
BufferedImage loginImg;
public LoginPanel() throws IOException
{
loginImg = ImageIO.read(new File("src/images/Login.PNG"));
}
#Override
protected void paintComponent(Graphics g)
{System.out.println("painting");
g.drawImage(loginImg, 0, 0, null);
}
}
Looks to me like you are adding the panel to the frame AFTER the frame is visible. When you do this the layout manager is not invoked and the size of the panel is (0, 0) so there is nothing to paint.
Restructure your code. The creation of the panel should be done in the Frame class, not Main class.
Also, use a better name instead of Frame. The AWT already has a class called Frame so you name is very confusing. Make your class name more descriptive.

Pass a JPanel class to the main class in JAVA

I need to pass a JPanel extending class to the main class.
Here is what I have so far:
Main class
import java.awt.Color;
import javax.swing.*;
public class main {
private gamePanel gamepanel = new gamePanel();
public JPanel createContentPane(){
// We create a bottom JPanel to place everything on.
JPanel totalGUI = new JPanel();
//We set the Layout Manager to null so we can manually place
// the Panels.
totalGUI.setLayout(null);
//Now we create a new panel and add it to the bottom JPanel.
totalGUI.add(gamepanel);
totalGUI.setOpaque(true);
return totalGUI;
}
private static void createAndShowGUI(){
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] There's a JPanel in here! [=]");
//Create and set up the content pane.
main demo = new main();
frame.setContentPane(demo.createContentPane());
//The other bits and pieces that make your program a bit more stable.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,500);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a jog for the event-dispatching thread:
//creating and showing this application's GUI.
System.out.println(gamepanel);
SwingUtilities.invokeLater(new Runnable() {
public void run(){
createAndShowGUI();
}
});
}
}
The gamePanel class
public class gamePanel extends JPanel implements Commons {
private Dimension d;
private ArrayList snowmens;
private coreFunctions functions = new coreFunctions();
private int snowmenX = 150;
private int snowmenY = 5;
private final String snowmenpix = "snowman.png";
private JPanel background;
public gamePanel() {
add(new JLabel("TEST"));
setFocusable(true);
setDoubleBuffered(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 700, 700);
}
}
I can't figure out why the blue background and the label is not being shown...
EDIT:
Here are more details:
Ok so I am trying to make a little 2D game. For that I need to create some snowmen on the gamePanel class and display it via the main class. To start it off, the createContentPane creates a background panel, the root panel if you want. The createandshowgui creates a JFrame.
The gamepanel class is in fact a JPanel which has 1 panel as of now, which is the background panel. For now, I only want it to have a blue background.
I tried putting it like this because I saw some examples and they were pretty similar to what I have, but for some reason, I can't get it to work....
Thank you,
Ara
You should use LayoutManager instead of setLayout(null); and if only one component is being added no need for it either (that component will stretch to fill unless others are added)
see here for tutorial on LayoutManagers:
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
If all you are trying to do is have a blue background (on which you can add components) then simply override paintComponent() of your gamePanel and paint the background blue:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
then you can add your JLabel as if it was a normal Panel as the background is now being painted blue and not set by/as a component.
If you have an image look into g.drawImage(Image image,int x,int y,ImageObserver iO)
EDIT
DROP THE CALL TO:
setLayout(null);
and it will work

Categories