paintComponent isnt called - java

In JFrame i have some buttons and BufferedImgae which will be used to draw on it some shapes and pictures using my own methods ( drawLine, drawing raster picture pixel by pisel and so on).
Here is how i add things to JFrame
public class Main extends javax.swing.JPanel {
JPanel panel;
JFrame fr;
Graphics2D g2;
ImageIcon icon;
BufferedImage img;
public void init()
{
fr = new JFrame("Lab 2");
fr.setMinimumSize(new Dimension(1350, 650));
fr.setMaximumSize(fr.getMinimumSize());
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel glowny = new JPanel(new BorderLayout());
glowny.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
glowny.add(getBorderCenter(), BorderLayout.CENTER);
fr.add(glowny);
fr.pack();
fr.setVisible(true);
}
private JScrollPane getBorderCenter()
{
img = new BufferedImage( fr.getWidth()-40, fr.getHeight()-40-50, BufferedImage.TYPE_INT_RGB); //20+20 odstępy w glowny, 50 - szerokość paska z guzikami
icon = new ImageIcon(img);
return new JScrollPane(new JLabel(icon));
}
public static void main(String [] args)
{
Main m = new Main();
m.init();
}
}
Then i try to draw on BufferedImage using double buffering.
The following example change BufferedImage color from black (current) to white.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paintComponent");
WritableRaster raster = img.getRaster();
DataBuffer db = raster.getDataBuffer();
int[] pixels = ((DataBufferInt)db).getData();
int adres = 0;
for (int y = 0; y < img.getHeight(); y++)
{
adres = y * img.getWidth();
for (int x = 0; x < img.getWidth(); x++)
{
pixels[adres] = 16777215;
adres += 1;
}
}
Graphics2D g2dComponent = (Graphics2D) g;
g2dComponent.drawImage(img, null, 0, 0); // draw buffer on screen
}
As i understand repaint() force calling paintComponent(). The problem is that it doesnt matter how i call repaint()
fr.repaint();
glowny.repaint();
repaint();
its never called.

You never add Main to the GUI. You need to add the JPanel that overrides the paintComponent, the this, to the GUI somewhere and you don't. For example, you would need somewhere something like:
someComponentShownInGui.add(this);
I would get rid of the glowny variable and instead use this.
i.e.,
public void init()
{
fr = new JFrame("Lab 2");
fr.setMinimumSize(new Dimension(1350, 650));
fr.setMaximumSize(fr.getMinimumSize());
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JPanel glowny = new JPanel(new BorderLayout());
// glowny.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// glowny.add(getBorderCenter(), BorderLayout.CENTER);
// fr.add(glowny);
setLayout(new BorderLayout();
setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
add(getBorderCenter(), BorderLayout.CENTER);
fr.add(this);
fr.pack();
fr.setVisible(true);
}
Note that anything components added to the drawing JPanel will cover up its image, and so you may need to make some non-opaque.

You should add all you components inside a JPanel then override paintComponent method of the panel. (JFrame doesn't have paintComponet but paint method and it's not recommanded to override it)

Related

JFrame graphics ignores the first few renders

Here is a minimal code to see the bug:
import javax.swing.*;
import java.awt.*;
public class Main1 extends JFrame {
static Main1 main;
public Main1() {
super("app");
}
public static void main(String[] args) {
main = new Main1();
main.setBounds(300, 300, 800, 500);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
Graphics g = main.getGraphics();
for(int i = 0; i < 100; i++){
g.setColor(new Color(255, 0, 0));
g.fillRect(0, 0, 800, 500);
}
}
}
If i use 100 in the "for" cycle, the frame appears not to be colored, but 200 loops is enough to color it.
I want to make an application where frames change rarely, but this feature ruins the quality of code because I have to make a number of dummy frames.
public static void main(String[] args) {
main = new Main1();
main.setBounds(300, 300, 800, 500);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setVisible(true);
Graphics g = main.getGraphics();
for(int i = 0; i < 100; i++){
g.setColor(new Color(255, 0, 0));
g.fillRect(0, 0, 800, 500);
}
}
This is not how you do Swing graphics. Getting a Graphics object by calling .getGraphics() on a component gives you a short-lived unstable and sometimes null object. For instance, it takes some time for the created JFrame to render, and if you call getGraphics() and try to use it prior to rendering, the object may be null, and certainly won't wokr.
Instead paint within a JPanel's paintComponent method using the Graphics object given by the JVM as per the tutorials:
public class MainPanel extends JPanel {
public MainPanel {
setPreferredSize(new Dimension(800, 500)));
setBackground(new Color(255, 0, 0)); // if you just want to set background
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use g here do do your drawing
}
}
and then use it like so:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
Tutorial: Lesson: Performing Custom Painting
And yes, if you want to drive a simple animation, use a Swing Timer to help drive it like so:
public class MainPanel extends JPanel {
private int x = 0;
private int y = 0;
public MainPanel {
setPreferredSize(new Dimension(800, 500)));
setBackground(new Color(255, 0, 0)); // if you just want to set background
// timer code:
int timerDelay = 15;
new Timer(timerDelay, ()-> {
x += 4;
y += 4;
repaint();
}).start();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// use g here do do your drawing
g.setColor(Color.BLUE);
g.drawRect(x, y, 20, 20);
}
}

In Java, how can I combine CardLayout and GridBagLayout and still be able to switch panels?

New to Java and very new to Java's GUI classes. I'm making a GUI to showcase a few games, but am having difficulties switching panels. I read about CardLayout but I'm having an issue implementing it because I can't get the JPanels that hold the different games' GUIs to send their events back to the class that uses the CardLayout. (This is probably where I'm going wrong -- I can't get my head around how to structure this properly.)
This is my main menu (called mainContainer):
This is the overall structure of the GUI driver:
public class CasinoDriverGUI {
//CardLayout is here in the main method Container contentPane.add(cardLayout)
public static void main(String[] args) throws IOException
//MainContainer is MenuScreen: GridBagLayout for nice button placement
static class MainContainer extends JPanel implements ActionListener{...}
static class CrapsContainer extends JPanel implements ActionListener{...}
static class PokerContainer extends JPanel implements ActionListener{...}
//Button with custom look
class CButton extends JButton
}//end CasinoDriverGUI
Here is the main method: It grabs an image from a website and then adds the menu screen (mainContainer) to the contentPane. The menu screen uses GridBagLayout, but it's where the button components are added. Because of this, I can't figure out how to get the CardLayout of the contentPane to listen to the menu screen's buttons. I tried using ContainerListener but that seemed to be a dead end.
public class CasinoDriverGUI {
public static void main(String[] args) throws IOException {
// load the texture resource image
System.out.println("Please wait, Loading Texture : http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png");
MainContainer.textureImg = ImageIO.read(new URL("http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png"));
System.out.println("Loading finished. Starting the Casino!");
MainContainer.textureImg = MainContainer.textureImg.getSubimage(0, 0, 580, 309);
// Starting the Swing GUI in the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final CardLayout cardLayout = new CardLayout();
JFrame frame = new JFrame("Midnight Casino");
// frame about the size of background src image
frame.setPreferredSize(new Dimension(580, 329));
final Container contentPane = frame.getContentPane();
contentPane.setLayout(cardLayout);
MainContainer mainContainer = new MainContainer();
mainContainer.setPreferredSize( frame.getPreferredSize() );
contentPane.add(mainContainer, "mainContainer");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
As I have it so far, I have just tried using the "menu screen" (mainContainer) to instantiate all the games' panels and use an ActionListener on some buttons to simply call thisGame.setVisible(true). but this is forcing the window to be minimized and re-opened for any change to be detectable.Edit: fixed this.
Any advice on how I can restructure this code to be able to switch the panels from the menu screen to the different game's panels? (Code is below, but the craps and poker GUIs are incomplete.. just using the code as placeholders.
public class CasinoDriverGUI {
public static void main(String[] args) throws IOException {
// load the texture resource image
System.out.println("Please wait, Loading Texture : http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png");
MainContainer.textureImg = ImageIO.read(new URL("http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png"));
System.out.println("Loading finished. Starting the Casino!");
MainContainer.textureImg = MainContainer.textureImg.getSubimage(0, 0, 580, 309);
// Starting the Swing GUI in the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final CardLayout cardLayout = new CardLayout();
JFrame frame = new JFrame("Midnight Casino");
// frame about the size of background src image
frame.setPreferredSize(new Dimension(580, 329));
final Container contentPane = frame.getContentPane();
contentPane.setLayout(cardLayout);
MainContainer mainContainer = new MainContainer();
mainContainer.setPreferredSize( frame.getPreferredSize() );
contentPane.add(mainContainer, "mainContainer");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
static class MainContainer extends JPanel implements ActionListener
{
public BufferedImage gradientImage = null;
public static BufferedImage textureImg; // static for ease
public static boolean loadingFinished = false;
protected JButton pokerJBtn;
protected JButton crapsJBtn;
CrapsContainer crapsContainer;
PokerContainer pokerContainer;
public MainContainer() {
setBorder(new EmptyBorder(50, 50, 50, 50)); // setting the insets
setLayout(new GridBagLayout());
// working with GridBagConstraints
GridBagConstraints labCnst = new GridBagConstraints();
GridBagConstraints txtCnst = new GridBagConstraints();
labCnst.ipady = txtCnst.ipady = 10;
labCnst.fill = GridBagConstraints.HORIZONTAL;
labCnst.gridwidth = 1;
labCnst.weightx = 0.3;
labCnst.gridx = 2;
labCnst.gridy = 2;
labCnst.ipady = 13;
labCnst.insets = new Insets(0, 0, 0, 150);
pokerJBtn = new CButton("5-Card Poker");
add(pokerJBtn, labCnst);
labCnst.gridx = 2;
labCnst.gridy = 20;
labCnst.ipady = 13;
labCnst.insets = new Insets(0, 0, 0, 150);
crapsJBtn = new CButton("Craps");
add(crapsJBtn, labCnst);
crapsContainer = new CrapsContainer();
pokerContainer = new PokerContainer();
add(crapsContainer);
add(pokerContainer);
crapsContainer.setVisible(false);
pokerContainer.setVisible(false);
//Add Action Listeners
crapsJBtn.addActionListener(this);
pokerJBtn.addActionListener(this);
}
public void changeCompFont(JComponent comp)
{
comp.setForeground(Color.WHITE);
comp.setFont(getFont().deriveFont(Font.BOLD, 13));
}
// To PAINT THE TEXTURE ABOVE THE COMPONENTS
#Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D)g.create(); // cloning
Rectangle2D txRect = new Rectangle2D.Double(0, 0, textureImg.getWidth(), textureImg.getHeight());
TexturePaint txPaint = new TexturePaint(textureImg, txRect);
g2d.setPaint(txPaint);
//make the texture transparent
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.233f));
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();// disposing the graphics object
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if(gradientImage==null || gradientImage.getHeight() != getHeight() )
{
gradientImage = createGradientImg();
}
g2d.drawImage(gradientImage, 0, 0, getWidth(), getHeight(), this);
g2d.dispose();
}
public BufferedImage createGradientImg()
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
// background gradient paint, linear gradient paint for the background
// Gradient paint rendering could be made more optimized
LinearGradientPaint lgrPaint = new LinearGradientPaint(0.0f, 0.0f, getWidth(), getHeight(),
new float[] { 0.0f, 0.5f, 0.6f, 1.0f },
new Color[] { new Color(0x0530E),// new Color[] { new Color(0x002AFF),
new Color(0x0A31B),
new Color(0x0A31B),
new Color(0x0530E ) });
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setPaint(lgrPaint);
//g2d.shear(0.2, 0);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
g2d.drawImage(textureImg, 0, 0, getWidth(), getHeight(), null);
return image;
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == pokerJBtn)
{
pokerContainer.setVisible(true);
}
else if (e.getSource() == crapsJBtn){
this.setVisible(false);
invalidate();
crapsContainer.setVisible(true);
revalidate();
repaint();
}
}
}
//Either Flow, Border, or GridBag Layout
static class CrapsContainer extends JPanel implements ActionListener
{...}
//Either Flow, Border, or GridBag Layout
static class PokerContainer extends JPanel implements ActionListener
{...}
//Custom Button to change aesthetic look
class CButton extends JButton
{...}
}

Add drawing in layered plane java

i am new to swing in java. i am trying to add the drawing made by the paintComponent() method in my a frame through layeredPane but it is not showing in the JFrame
However if i place the code frame.getContentPane().add(drawing) and comment the Layered part the code works..
what i am doing wrong?
here is the code:
frame class
public class FrameTest extends JFrame {
static JFrame frame= new JFrame("Frame");
public static void main(String[] args) {
FrameTest test= new FrameTest ();
}
public FrameTest (){
this.openfrane();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public void openframe(){
//window properties
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(1000,600);
frame.setResizable(false);
//changing icon of window
ImageIcon image = new ImageIcon("assets/icon.png");
card.setIconImage(image.getImage());
//label picture background
JLabel background = new JLabel();
ImageIcon back = new ImageIcon("assets/background.jpg");
background.setIcon(back);
background.setLocation(0,-125);
background.setSize(1000,700);
//label for first
JLabel first = new JLabel("Sample text");
first.setForeground(Color.RED);
first.setSize(500,200);
first.setLocation(31, 150);
Draw drawing = new Draw();
JLayeredPane layers = new JLayeredPane();
layers.add(drawing, new Integer(3));
layers.add(first, new Integer(2));
layers.add(background,new Integer(1));
frame.setLayeredPane(layers);
}
}
draw class:
public class Draw extends JPanel {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
int startX = 00;
int startY = 00;
// First circle
Ellipse2D circle1 = new Ellipse2D.Double(startX, startY, 30, 30);
g2.setColor(Color.Black);
g2.draw(circle1);
g2.fill(circle1);
// Second circle
Ellipse2D circle2 = new Ellipse2D.Double(startX+20, startY, 30, 30);
g2.setColor(Color.Black);
g2.draw(circle2);
g2.fill(circle2);
}
}
i am trying to add the drawing made by the paintComponent() method in my a frame through layeredPane but it is not showing in the JFrame
Your DrawPanel does not have a size, so the size is (0, 0) and there is nothing to paint.
However if i place the code frame.getContentPane().add(drawing) and comment the Layered part the code works..
When you add the DrawPanel directly to the content pane then the panel is added to the "CENTER" and the panel size is automatically set to the space available in the frame by the layout manager.

Rectangle does not center vertically in JPanel with GridLayout

as said my rectangle does not center vertically in a JPanel with GridLayout. I have 3 columns. 1st and 2nd column have JLabels and they are centered perfect, but my custom JPanel which is just a rectangle does not. It's y coordinate is always on top of the grid's row.
public class CustomJPanel {
/**
* #param args
*/
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 200);
frame.setResizable(false);
JPanel panel = new JPanel(new GridLayout(0,3));
JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.setBounds(10, 50, 320, 200);
scrollPane.setBorder(BorderFactory.createLineBorder(Color.BLACK));
for(int i=0; i<3; i++){
JLabel nameLabel = new JLabel("Test"+i);
JLabel timeLabel = new JLabel();
timeLabel.setText("0h 0m 0s");
panel.add(nameLabel);
panel.add(timeLabel);
panel.add(new Bar());
}
frame.add(scrollPane);
frame.setVisible(true);
}
private static class Bar extends JPanel {
int width = 100;
Dimension maxDimension = new Dimension(100, 20);
#Override
public void paintComponent(Graphics g){
super.paintComponents(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.fillRect(0, 0, width, 5);
}
#Override
public Dimension getMaximumSize() {
return maxDimension;
}
#Override
public Dimension getPreferredSize(){
return this.getMaximumSize();
}
}
}
Do I have to add other methods to my Bar class?
Thank you :)
That happens because you draw rectangle from y=0, but you need to draw that at the middle of your panel. You can fill rectanle in the middle like next :
g2.fillRect(0, getSize().height/2, width, 5);

How to use images for a JPanel grid?

I'm trying to create an 8x8 grid composed of pre made images to be used for a board game, however I am having difficulty loading the images.
Dimension Size = new Dimension(400, 400);
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(Size);
getContentPane().add(layeredPane);
board.setLayout(new GridLayout(8,8));
board.setPreferredSize(Size);
board.setBounds(0, 0, Size.width, Size.height);
layeredPane.add(board, JLayeredPane.DEFAULT_LAYER);
// Load squares to board
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
JPanel square = new JPanel( new BorderLayout() );
square. // Load .jpg here?????
board.add( square );
}
}
The only method I know is ImageIcon, but that doesn't seem to work... So I'm stuck.
Any help would be appreciated, Thanks.
ImageIcon should work fine. See the Swing tutorial on How to Use Icons for more information and examples.
Try this code snippet, adapted from java2s.com:
class ImagePanel extends JPanel {
private Image img;
public ImagePanel(URL imgURL) {
this(new ImageIcon(imgURL).getImage());
}
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(this), img.getHeight(this));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
#Override
public void paintComponent(Graphics g) {
super.paint(g);
g.drawImage(img, 0, 0, this);
}
}
You can add those ImagePanels inside the JPanel

Categories

Resources