I have the following problem, when i want to add 2JPanels to my JFrame only one is visible, depending on which I added to the frame last. I overrided the JPanels default paintComponent() method on both of the JPanels. How can i fix this?
Code snippet:
Border:
public class BorderDrawer extends JPanel{
private int _width,_height;
BorderDrawer(int width,int height)
{
setOpaque(false);
_width = width;
_height = height;
}
#Override
protected void paintComponent(Graphics g) {
final int BUTTON_WIDTH = 20,BUTTON_HEIGHT = 20;
int MINES_HORIZONTALLY = _width;
int MINES_VERTICALLY = _height;
super.paintComponent(g);
try{
BufferedImage topLeftCorner = ImageIO.read(this.getClass().getResource("topLeftCorner.png"));
g.drawImage(topLeftCorner, 0, 0, null);
....// drawing other border components
}
}
Clock:
public class GraphicTimer extends JPanel{
Timer _aktTimer = null;
int seconds;
int _width = 0;
GraphicTimer(int width)
{
setSize(52, 31);
setOpaque(false);
_width = width;
int delay = 1000; //milliseconds
_aktTimer = new Timer(delay, taskPerformer);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
try
{
final int BUTTON_WIDTH = 20,BUTTON_HEIGHT = 20;
int MINES_HORIZONTALLY = _width;
int HORIZONTAL_ENDING = 15+BUTTON_WIDTH*MINES_HORIZONTALLY;
BufferedImage clock = ImageIO.read(this.getClass().getResource("clock.png"));
g.drawImage(clock,HORIZONTAL_ENDING-54,22, null);
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
....
}
JFrame:
public class DrawerField extends JFrame implements Serializable{
//...
public DrawerField()
{
super("MineSweeper");
_FIELD = new Field();
constructorInit();
}
public void constructorInit()
{
_buttons = new FieldButton[_height][_width];
_isMouseEventEnabled = true;
fieldPanel = new JPanel();
smilePanel = new JPanel();
//INITS
int fieldSizeWidth = (_width)*20;
int fieldSizeHeight = (_height)*20; // Magic size
fieldPanel.setSize(fieldSizeWidth,fieldSizeHeight); // 20x20
fieldPanel.setLocation(15, 70);
fieldPanel.setLayout(new GridLayout(_width,_height));
int fullWindowWidth = fieldSizeWidth+36;
int fullWindowHeight = fieldSizeHeight+142;
setSize(fullWindowWidth,fullWindowHeight);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
restartButton = new RestartButton(this);
smilePanel.setSize(34,34);
smilePanel.add(restartButton);
smilePanel.setLayout(new GridLayout(1,1));
smilePanel.setLocation((int)fullWindowWidth/2-(34/2)-1,20);
///INITIALS
for(int i = 0; i < _height; i++)
{
for(int j = 0; j < _width ; j++)
{
_buttons[i][j] = new FieldButton(_hidden[i][j],true,i,j,this);
fieldPanel.add(_buttons[i][j]);
}
}
add(smilePanel);
add(fieldPanel);
borderDrawer = new BorderDrawer(_width,_height);
_graphicTimer = new GraphicTimer(_width);
_graphicTimer.start();
add(_graphicTimer); // This is the two lines which change the result
add(borderDrawer);
MenuBar menuBar = new MenuBar(this);
setJMenuBar(menuBar);
setVisible(true);
}
//...
}
Easier and compilable example:
public class Main {
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(500, 500);
MyPanel panel1 = new MyPanel(30,30);
frame.add(panel1);
MyPanel panel2 = new MyPanel(70,30);
frame.add(panel2);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.repaint();
frame.setVisible(true);
}
public static class MyPanel extends JPanel
{
int _x,_y;
MyPanel(int x, int y)
{
_x = x; _y = y;
}
#Override
public void paint(Graphics g) {
g.drawOval(_x,_y,20,20);
}
}
}
My main goal is to add 2 circles to the JFrame without using any Layout.( As you can see in the example above I already have a lot of things on my JFrame that's why I don'T want to use layouts). The problem is the same in this example, when i add the 2nd circle the first is disappearing.
Its simple. Adding a panel in a frame adds it to the content pane of the frame. This contentpane has a default layout of BorderLayout which means, every time you add a panel, it gets added to the center of the content pane and gets replaces the previous one. This is the reason why you see only the last one. Its always good to use a Jpanel set to the layout of your choice put everything that needs to be shown on the screen in that panel. If you don't want to do that, you may also call getContentPane() from the frame and play with the returned instance of JPanel.
Here is the example code for you:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Frame extends JFrame {
public Frame() {
setTitle("Two panels");
setSize(new Dimension(500,500));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Here goes your code
JPanel p= (JPanel) getContentPane();
p.setLayout(new GridLayout(1,2)); //set your own layout
p.add(new MyPanel(Color.BLUE)); //add panel with blue border
p.add(new MyPanel(Color.GREEN));//add panel with green border
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Frame f= new Frame();
f.setVisible(true);
}
});
}
}
class MyPanel extends JPanel {
public MyPanel(Color color) {
setBorder(BorderFactory.createLineBorder(color));
}
}
Run it and see... You should be able to see something like this:
Related
I am trying to implement a GUI for a maze-based game I created that meets the following specific conditions:
The GUI itself has a set size and is not resizable (line 41) .
The master panel (line 57) that contains all the maze images is scrollable. All maze image components are flush with each other.
If maze is small enough, then entire maze will be visible in master panel.
If maze is very large, then user would need to scroll.
The master panel needs to be accessed by a mouse listener (line 130) that returns the component that is being clicked.
The following code seems to meet criteria 1 and 3, but fails criteria 2:
public class MazeGui extends JFrame implements DungeonView {
private final Board board;
public MazeGui(ReadOnlyModel m) {
//this.setSize(m.getNumRows()*100, m.getNumCols()*100);
this.setSize(600, 600);
this.setLocation(200, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.board = new Board(m);
JScrollPane scroller = new JScrollPane(board);
this.add(scroller, BorderLayout.CENTER);
setTitle("Dungeon Escape");
}
private class Board extends JPanel {
private ReadOnlyModel m;
public Board(ReadOnlyModel m) {
this.m = m;
GridLayout layout = new GridLayout(m.getNumRows(),m.getNumCols(), 0, 0);
// layout.setHgap(-100);
// layout.setVgap(-100);
this.setLayout(layout);
this.setSize(m.getNumRows()*64,m.getNumCols()*64);
for (int i = 0; i < m.getNumRows() * m.getNumCols(); i++) {
try {
// load resource from the classpath instead of a specific file location
InputStream imageStream = getClass().getResourceAsStream(String.format("/images/%s.png", m.getRoomDirections(i + 1)));
// convert the input stream into an image
Image image = ImageIO.read(imageStream);
// add the image to a label
JLabel label = new JLabel(new ImageIcon(image));
label.setPreferredSize(new Dimension(64, 64));
JPanel panel = new JPanel();
panel.setSize(64, 64);
String name = String.format("%d", i);
panel.setName(name);
panel.add(label);
// add the label to the JFrame
//this.layout.addLayoutComponent(TOOL_TIP_TEXT_KEY, label);
this.add(panel);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, e.getMessage());
e.printStackTrace();
}
}
}
}
#Override
public void addClickListener(DungeonController listener) {
Board board = this.board;
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println(String.format("(%d,%d)", e.getX(), e.getY()));
JPanel panel = (JPanel) board.getComponentAt(e.getPoint());
System.out.println(panel.getName());
}
};
board.addMouseListener(mouseListener);
}
#Override
public void refresh() {
this.repaint();
}
#Override
public void makeVisible() {
this.setVisible(true);
}
}
Here is an image of what it produces:
First, I'd make use of a different layout manager, one which would try and expand to fit the size of the underlying container.
Then, I would let the components do their jobs. I don't know why you're adding the label to another panel, the panel doesn't seem to be adding additional functionality/features and is just adding to the complexity.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
List<Maze.Direction> directions = new ArrayList<>(32);
directions.add(Maze.Direction.EAST_SOUTH);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.EAST_SOUTH_WEST);
directions.add(Maze.Direction.SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_EAST_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_SOUTH_WEST);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH_SOUTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
directions.add(Maze.Direction.NORTH);
System.out.println(directions.size());
Maze maze = new DefaultMaze(5, 6, directions);
MazeGui frame = new MazeGui(maze);
frame.addClickListener(null);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Maze {
enum Direction {
EAST_SOUTH("EastSouth.png"), EAST_SOUTH_WEST("EastSouthWest.png"), SOUTH_WEST("SouthWest.png"),
NORTH_EAST_SOUTH("NorthEastSouth.png"), NORTH_EAST_SOUTH_WEST("NorthEastSouthWest.png"),
NORTH_SOUTH_WEST("NorthSouthWest.png"), NORTH_SOUTH("NorthSouth.png"), NORTH("North.png");
private BufferedImage image;
private Direction(String name) {
try {
image = ImageIO.read(getClass().getResource("/images/" + name));
} catch (IOException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
public BufferedImage getImage() {
return image;
}
}
public int getRows();
public int getColumns();
public Direction getRoomDirections(int index);
}
public class DefaultMaze implements Maze {
int rows;
int columns;
private List<Direction> directions;
public DefaultMaze(int rows, int columns, List<Direction> directions) {
this.rows = rows;
this.columns = columns;
this.directions = directions;
}
public int getRows() {
return rows;
}
public int getColumns() {
return columns;
}
#Override
public Direction getRoomDirections(int index) {
return directions.get(index);
}
}
public class MazeGui extends JFrame {
// Missing code
public interface DungeonController {
}
private final Board board;
public MazeGui(Maze m) {
this.setSize(600, 600);
this.setResizable(false);
this.board = new Board(m);
JScrollPane scroller = new JScrollPane(board);
this.add(scroller, BorderLayout.CENTER);
setTitle("Dungeon Escape");
}
public Board getBoard() {
return board;
}
public void addClickListener(DungeonController listener) {
Board board = getBoard();
board.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Component cell = board.getComponentAt(e.getPoint());
System.out.println(cell.getName());
board.highlight(cell.getBounds());
}
});
}
private class Board extends JPanel {
private Rectangle selectedCell;
private Maze maze;
public Board(Maze maze) {
this.maze = maze;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
for (int index = 0; index < maze.getRows() * maze.getColumns(); index++) {
Maze.Direction direction = maze.getRoomDirections(index);
JLabel label = new JLabel(new ImageIcon(direction.getImage()));
label.setName(direction.name());
add(label, gbc);
gbc.gridx++;
if (gbc.gridx >= maze.getColumns()) {
gbc.gridx = 0;
gbc.gridy++;
}
}
// addMouseListener(new MouseAdapter() {
// #Override
// public void mouseClicked(MouseEvent e) {
// Component component = getComponentAt(e.getPoint());
// selectedCell = null;
// if (component != null) {
// selectedCell = component.getBounds();
// }
// repaint();
// }
// });
}
public void highlight(Rectangle bounds) {
selectedCell = bounds;
repaint();
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (selectedCell != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(0, 0, 255, 128));
g2d.fill(selectedCell);
g2d.dispose();
}
}
}
}
}
The GUI itself has a set size and is not resizable
So the issue here is that you are forcing the "board" panel to have an arbitrary size.
this.setSize(600, 600);
The actual size of the panel should be 8 * 64 = 512. So extra space is being added to each grid.
Don't hardcode size values.
It is the job of the layout manager to determine the preferred size of each component.
So instead of using setSize(...) you should pack() the frame before making it visible:
this.pack();
this.setVisible(true);
When you do this you will see that the maze fits completely in the frame.
If you want extra space around the maze then you need to add a "border" to your board:
setBorder( new EmptyBorder(88, 88, 88, 88) );
GridLayout layout = new GridLayout(m.getNumRows(),m.getNumCols(), 0, 0);
Turns out I should have been using GridBagLayout!
There is no need to change layout managers, only use the layout managers more effectively.
If you really for some reason need to specify a fixed frame size then you can make the following change:
//this.add(scroller, BorderLayout.CENTER);
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(scroller, new GridBagConstraints());
this.add(wrapper, BorderLayout.CENTER);
This will allow the "board" panel to be displayed at its preferred size and the "board" panel will be centered in its parent container.
Using these tips will help you effectively create more complicated layouts.
I have 2 classes: GameOfLife() and PanelGrid. When a new object of panelgrid is created, the (overwritten) method paintComponent is not called. Putting "repaint()" in the constructor doesn't work either.
import java.util.Scanner;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class GameOfLife {
JFrame frame = new JFrame("Game of life");
PanelGrid panelGrid;
void buildIt() {
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(buttonStart, BorderLayout.SOUTH);
frame.add(buttonStop, BorderLayout.NORTH);
panelGrid = new PanelGrid();
panelGrid.setOpaque(true);
frame.add(panelGrid);
}
public static void main(String[] args) {
new GameOfLife().buildIt();
}
}
class PanelGrid extends JPanel implements ActionListener {
Timer timer;
int delay;
JLabel label;
int height; // get length from the file
int width; //get width of array from the file
//constructor
public PanelGrid() {
delay = 1000;
timer = new Timer(delay, this);
width = 4;
height = 5;
//if there exists a file with an initial configuration, initial[][], width and height are updated.
//if not, the default array is used
readInitial();
//repaint(); putting repaint() here din't make a difference.
}
#Override
public void paintComponent(Graphics g) {
System.out.println("if you read this, the method is called");
super.paintComponent(g); //erases panel content
this.setLayout(new GridLayout(width, height));
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
JPanel panel = new JPanel();
if (grid[r][c].isAlive() == true) {
panel.setBackground(Color.BLACK);
} else {
panel.setBackground(Color.WHITE);
}
this.add(panel);
}
}
//the rest of this class I have left out for clarity
}
}
I think you need to add your PanelGrid to theJFrame. If it's not in a visible top-level container paint() and therefore paintComponent() won't be called. Maybe. Worth a shot...
There is a window in which I want to place a button, and then paint the whole area beneath it. In other words, button should cover a piece of painting.
import java.awt.*;
import javax.swing.*;
class Window
{
private JFrame frame;
private JButton launchButton;
private JPanel pnllaunchButton;
private JPanel paintingPanel;
//width and height of client area
private Rectangle dim;
//w,h - width and height of the whole window
public Window(String title,int w,int h)
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(0,0);
frame.setMinimumSize( new Dimension(110,110));
frame.setSize(w, h);
frame.setVisible(true);
frame.setTitle(title);
frame.setResizable(false);
addLaunchButton();
}
private void addLaunchButton()
{
pnllaunchButton = new JPanel();
launchButton = new JButton("Plot!");
dim = new Rectangle();
frame.getContentPane().getBounds(dim);
pnllaunchButton.setBounds(dim.width-100,dim.height-25,100,25);
launchButton.setBounds(dim.width-100,dim.height-25,100,25);
pnllaunchButton.setLayout(null);
pnllaunchButton.add(launchButton);
frame.getContentPane().add(pnllaunchButton);
frame.getContentPane().setComponentZOrder(pnllaunchButton, new Integer(2));
}
public void drawCoordinateSystem()
{
paintingPanel = new JPanel();
paintingPanel.add(new CoordinateSystem());
frame.getContentPane().add(paintingPanel);
frame.getContentPane().setComponentZOrder(paintingPanel,new Integer(3));
}
}
class CoordinateSystem extends JPanel
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Dimension size = this.getSize();
g.setColor(Color.BLACK);
g.drawLine(0,size.height/2,size.width, size.height/2);
g.drawLine(size.width/2, 0, size.width/2, size.height);
}
}
public class GC {
public static void main(String[] args)
{
Window h = new Window("GC",800,600);
h.drawCoordinateSystem();
}
}
This code doesn't fulfill the specification. Program creates an empty window and outputs:
run:
Exception in thread "main" java.lang.IllegalArgumentException: illegal component position
at java.awt.Container.checkAdding(Container.java:504)
at java.awt.Container.setComponentZOrder(Container.java:759)
at Window.addLaunchButton(Window.java:46)
at Window.<init>(Window.java:26)
at GC.main(GC.java:10)
Could you point out my mistake? setComponentZOrder() method doesn't seem to be described precisely in javadoc.
Rename your class. The Window class is already part of the standard core Java libraries, and your class name could cause present or future problems.
Don't us null layouts and setBounds(...). This is bad, bad, bad, and will make it very difficult to maintain or upgrade your application. Instead, learn about and use the layout managers.
Consider making a JLabel the contentPane, make it opaque, give it a layout and an ImageIcon and add your components to it.
The ImageIcon can hold a BufferedImage with a grid.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyWindow {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final Color COLOR0 = Color.red;
private static final Color COLOR1 = Color.blue;
private static final float COLOR_REPEAT_DIST = 30f;
private JLabel backGroundLabel = new JLabel();
public MyWindow() {
backGroundLabel.setOpaque(true);
backGroundLabel.setLayout(new BorderLayout());
int eb = 15;
BufferedImage bkgrndImg = createBkgrndImage();
ImageIcon icon = new ImageIcon(bkgrndImg);
backGroundLabel.setIcon(icon);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new FlowLayout(SwingConstants.RIGHT, eb, eb));
bottomPanel.setOpaque(false);
bottomPanel.add(new JButton("Plot"));
backGroundLabel.add(bottomPanel, BorderLayout.PAGE_END);
}
private BufferedImage createBkgrndImage() {
BufferedImage img = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setPaint(new GradientPaint(0f, 0f, COLOR0, COLOR_REPEAT_DIST, COLOR_REPEAT_DIST, COLOR1, true));
g2.fillRect(0, 0, PREF_W, PREF_H);
g2.dispose();
return img;
}
public JComponent getMainPane() {
return backGroundLabel;
}
private static void createAndShowGui() {
MyWindow mainPanel = new MyWindow();
JFrame frame = new JFrame("MyWindow");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel.getMainPane());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Which looks like so:
Pass an int instead of an Integer to the setComponentZOrder method.
private void addLaunchButton()
{
pnllaunchButton = new JPanel();
launchButton = new JButton("Plot!");
dim = new Rectangle();
frame.getContentPane().getBounds(dim);
pnllaunchButton.setBounds(dim.width-100,dim.height-25,100,25);
launchButton.setBounds(dim.width-100,dim.height-25,100,25);
pnllaunchButton.setLayout(null);
pnllaunchButton.add(launchButton);
frame.getContentPane().add(pnllaunchButton);
frame.getContentPane().setComponentZOrder(pnllaunchButton, 2);
}
I want to use JScrollBar to zoom in and zoom out images but it doesn't work. What's wrong with my code?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class piczoominandout extends JFrame
{
public JScrollBar scroll;
public JLabel lbl;
public Image image;
public int x, y, width, height;
public piczoominandout()
{
super("picture zoom");
Toolkit toolkit = Toolkit.getDefaultToolkit();
image = toolkit.getImage("Snake.jpg");
Container c = getContentPane();
ImagePanel imagePane = new ImagePanel(image);
c.setLayout(new BorderLayout());
lbl = new JLabel("0");
c.add(lbl, BorderLayout.SOUTH);
scroll = new JScrollBar(
JScrollBar.HORIZONTAL,50,10,0,100);
scroll.addAdjustmentListener(new AdjustmentListener() {
public void adjustmentValueChanged(
AdjustmentEvent evt) {
JScrollBar s = (JScrollBar)evt.getSource();
if ( !s.getValueIsAdjusting() ) {
int v = (int)s.getValue();
width +=v;
height +=v;
repaint();
lbl.setText(Integer.toString(v));
}
} });
c.add(imagePane,BorderLayout.CENTER );
c.add(scroll, BorderLayout.NORTH);
}
class ImagePanel extends JPanel
{
public ImagePanel(Image img) { image = img;}
public void paintComponent(Graphics g)
{
Insets ins = getInsets();
super.paintComponent(g);
width = image.getWidth(this);
height = image.getHeight(this);
x = ins.left+5; y = ins.top+5;
g.drawImage(image,x,y,width,height,this);
}
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
piczoominandout frame = new piczoominandout();
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.setSize(600,300);
frame.setVisible(true);
}
});
}
}
There is so many errors in your code. It needs general rethinking.
I'll give you some basic hints only:
You use a ImagePanel contructor that don't set a listener (look out for NullPointerException);
You're not scaling image - on paintComponent you just painting image as it is;
You're adding to width and height in listener scroll value and you try to reset them in paintComponent - this is not what you should do. HINT: there's a method of Graphics class: g.drawImage(image, x, y, width, height, this);;
Every Swing component must be created and changed on EDT:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
//etc.
}
});
}
I've hit a wall (in my brain) trying to update my board on button presses. Am I right in thinking that the GameBoard class is the one that needs to be repaint()ed?
GameBoard.java
public class GameBoard extends Panel {
static Compass compass = new Compass();
private static final long serialVersionUID = 1;
Graphics2D g2d;
static final Dimension WINDOW_SIZE = new Dimension(1150, 800);
public void boardMaker() throws Exception {
JFrame frame = new JFrame("Display image");
JPanel panel = new JPanel();
/* unimportant stuff
.....
*/
//
DieRoll roll = new DieRoll("Roll Dies");
roll.setC(compass);
roll.setG2D(g2d);
//
Button button = new Button("new");
button.setGameBoard(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
buttonPanel.add(roll);
buttonPanel.setPreferredSize(new Dimension(200,100));
frame.getContentPane().add(buttonPanel, BorderLayout.NORTH);
//
frame.getContentPane().add(panel);
frame.setVisible(true);
}
public void paint(Graphics g) {
// not important I think
}
}
Button.java
public class Button extends JButton implements ActionListener {
private static final long serialVersionUID = 1L;
JPanel panel = new JPanel();
JFrame frame = new JFrame();
Compass c = new Compass();
GameBoard gb = new GameBoard();
Button(String text) {
this.setText(text);
this.addActionListener(this);
}
void setGameBoard(GameBoard gb) {
this.gb = gb;
}
#Override
public void actionPerformed(ActionEvent e) {
gb.g2d.setColor(Color.black);
gb.g2d.fillRect(100, 100, 100, 200);
gb.repaint();
}
}
This gives a null pointer exception. So any idea how to repaint my GameBoard? I'm not mad if I've to rewrite everything because of stupidity! ;)
Thanks
You have the wrong idea about how to draw in Java. Components like Panels draw themselves, and all drawing takes place on the UI thread.
Check out this tutorial: docs.oracle.com/javase/tutorial/2d/index.html
The article Painting in AWT and Swing may offer some perspective on application-triggered painting. The example below illustrates the principle. Note that setForeground() calls repaint() automatically because the foreground color is a bound property, but you can always call it yourself.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SwingPaint {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
final GamePanel gp = new GamePanel();
f.add(gp);
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
gp.update();
}
}), BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class GamePanel extends JPanel {
private static final Random r = new Random();
public GamePanel() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
public void update() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = this.getSize();
int d = Math.min(size.width, size.height) - 10;
int x = (size.width - d) / 2;
int y = (size.height - d) / 2;
g.fillOval(x, y, d, d);
g.setColor(Color.blue);
g.drawOval(x, y, d, d);
}
}
}