PaintComponent in JPanel not being called - java

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.

Related

Add element to JFrame from other class

I have two classes in one JFrame creation:
public class Window extends JFrame {
public void createWindow() throws IOException {
setTitle(GeneralValues.PROGRAM_NAME);
setSize(1100, 600);
setResizable(false);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setLayout(null);
setVisible(true);
}
}
And in the second I have a JLabel:
public class InitialConfiguration {
Window w = new Window();
public void main() {
JLabel blauncherIcon = new JLabel();
blauncherIcon.setBounds(100, 100, 100, 100);
blauncherIcon.setOpaque(true);
blauncherIcon.setText("Text");
w.add(blauncherIcon);
}
}
My main method:
public class Main {
Window w = new Window();
InitialConfiguration ic = new InitialConfiguration();
public static void main(String[] args) {
w.createWindow();
ic.main();
}
}
I wanted to add a label from the InitialConfiguration class to the frame from the Window class but unfortunately this code creates a frame but does not add the label from the InitialConfiguration class. Can it be done at all?
Your issue is, that you went wrong with the instances of your Window. Your InitialConfiguration has a member variable of Window, to which the label is being added. But this is not the same instance of the Window that you have in your Main class.
So all in all, you create and show the window, but never show the second window you actually added your label to.
So altogether, if you really want to keep your structure this way (I would advise against that but you may have your reasons), passing the correct Window instance as a method parameter should fix it.
public class InitialConfiguration {
// Removed second Window here
public void main(Window w) { // rename this method please
JLabel blauncherIcon = new JLabel();
blauncherIcon.setBounds(100, 100, 100, 100); // use layout managers
blauncherIcon.setOpaque(true);
blauncherIcon.setText("Text");
w.add(blauncherIcon);
}
}
And your "Main":
public class Main {
Window w = new Window(); // rename the class Window please
InitialConfiguration ic = new InitialConfiguration();
public static void main(String[] args) {
w.createWindow();
ic.main(w);
}
}
You didn't start the Jframe at window class and I don't know your main class so I made it for your understanding. Check this codes;
(Edited)
Main: Example code:
public class MainMenu{
public static void main(String[] args) {
Windows w = new Windows();
InitialConfiguration ini = new InitialConfiguration(w);
w.createWindow();
ini.main();
}
}
ICONFIG class example code:
public class InitialConfiguration {
Window w;
public InitialConfiguration(Windows w){
this.w = w;
}
public void main() {
JLabel blauncherIcon = new JLabel();
blauncherIcon.setBounds(100, 100, 100, 100);
blauncherIcon.setOpaque(true);
blauncherIcon.setText("Text");
w.add(blauncherIcon);
w.repaint();
}
}
Window class example code:
public class Window extends JFrame {
public void createWindow(){
setTitle("Your title");
setSize(1100, 600);
setResizable(false);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setLayout(null);
setVisible(true);
}
}

Issue with adding JLabel to JPanel

I'm looking to display an image on a JPanel, but when I run the code, the panel is blank. The method I'm attempting is a slightly modified version of this tutorial.
I've confirmed that all methods in the code are actually called using println. My frame and panel are visible, and I'm fairly certain I've added both the icon to the label, and the label to the panel. What am I missing?
The relevant parts of my code:
public class SYSTEM
public static void start() {
GameFrame GF = new GameFrame();
GamePanel GP = new GamePanel();
GF.add(GP);
GP.loadSprite("Player", new Dimension(0,0));
}
}
public class GameFrame extends JFrame {
public GameFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(SYSTEM.windowSize);
setVisible(true);
}
}
public class GamePanel extends JPanel {
ArrayList<Sprite> sprites = new ArrayList<Sprite>();
GamePanel() {
setVisible(true);
setSize(SYSTEM.windowSize);
setLayout(null);
}
public void loadSprite(String spriteName, Dimension pos) {
sprites.add(new Player());
add(sprites.get(0).getIcon());
}
public class Sprite {
protected JLabel icon;
protected BufferedImage image;
protected String filePath;
protected Dimension pos;
public JLabel getIcon() {
return icon;
}
}
public class Player extends Sprite {
public Player() {
filePath = "FILEPATH_OMITTED";
pos = new Dimension(0,0);
try {
image = ImageIO.read(new File(filePath));
} catch (IOException e) {
System.out.println(e);
}
icon = new JLabel(new ImageIcon(image));
}
}
Don't use components for games, you've thrown out the layout manager which is responsible for determining the size and location of the components, but you've failed to compensate for it. I'd recommend that you use a custom painting approach instead, see Painting in AWT and Swing and Performing Custom Painting for starters.
Just so I'm clear, you problem is directly related to setLayout(null); which is bad regardless of what you're doing

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

Canvas/JPanel not displaying on the JFrame?

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);
}

Why is there no Picture in my Panel/Window?

whats wrong with my code? I just want to have a Picture in my Window...
//class ImagePanel:
public class ImagePanel extends JPanel {
private static final long serialVersionUID = -7664761101121497912L;
public Image i;
public ImagePanel(Image i) {
this.i = i;
}
#Override
public void paintComponents(Graphics g) {
super.paintComponent(g);
g.drawImage(this.i, 0, 0, null);
}
}
//class Main
public class Main extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(1024, 768);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImagePanel panel = null;
try {
panel = new ImagePanel(ImageIO.read(new File("D:/test.JPG")));
} catch (IOException e) {
e.printStackTrace();
}
frame.getContentPane().add(panel);
frame.setVisible(true);
}
}
There is just a Window without a picture :(
Whats the problem? And is there an easy way to set size of the window == picture size?
Thank you!
You must override paintComponent(Graphics g) instead of paintComponents(Graphics g).
The best solution is to use a JLabel. Don't reinvent wheel. There is no need for you to do custom painting.
But if you do custom painting then you need to override the getPreferredSize() method to be the size of the image so the layout manager can do their job.
please read this tutorials about Icon in Swing and your Image would by placed to the JLabel but with same way/funcioanlities as to the JPanel
I not at all familiar with Java panes, but don't you need to set the size of ImagePanel before you add it to the content pane.

Categories