display JLabels dynamically in JPanel/JFrame - java

I am trying display images in sequential manner, but having difficulties in displaying(only last image is getting displayed on screen). I tried using CardLayout but as my number of JLabels(which contains ImageIcon) are high so it's giving me outofmemory exception. here's my code:
I have JFrame inside that I have JPanel in which I am trying to display JLabel one by one.
public class ImageMain extends JFrame implements ActionListener{
private static final long serialVersionUID = 2916361361443483318L;
private JFileChooser fc = null;
private JMenuItem item1,item2;
private BufferedImage image = null;
private JPanel panel = null;
private int width = 0;
private int height = 0;
private BorderLayout card;
private Container contentPane;
public ImageMain() {
JFrame frame = new JFrame("Image Extraction Tool");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = frame.getContentPane();
panel = new JPanel();
card = new BorderLayout();
panel.setLayout(card);
panel.setBackground(Color.white);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
item1 = new JMenuItem("Browse an image");
item2 = new JMenuItem("Exit");
item1.addActionListener(this);
item2.addActionListener(this);
menu.add(item1);
menu.add(item2);
frame.setJMenuBar(menuBar);
contentPane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ImageMain img = new ImageMain();
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == item1){
if(fc == null)
fc = new JFileChooser();
int retVal = fc.showOpenDialog(null);
if(retVal == JFileChooser.APPROVE_OPTION){
File file = fc.getSelectedFile();
try {
image = ImageIO.read(file);
height = image.getHeight();
width = image.getWidth();
int[][] pixelData = new int[height * width][3];
int[] rgb;
int counter = 0;
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
rgb = getPixelData(image, i, j);
for(int k = 0; k < rgb.length; k++){
pixelData[counter][k] = rgb[k];
}
counter++;
}
}
for(int m=pixelData.length-10; m < pixelData.length; m++){
System.out.println(m);
int[] pix = new int[width*height*3];
for(int i=0;i< width*height*3; i+=3){
pix[i] = pixelData[m][0];
pix[i+1] = pixelData[m][1];
pix[i+2] = pixelData[m][2];
}
JLabel createImageLabel = createImageLabel(pix);
panel.add(createImageLabel);
// panel.revalidate();panel.repaint();
contentPane.revalidate();contentPane.repaint();
Thread.sleep(2000);
}
} catch (IOException e1) {
System.out.println("IO::"+e1.getMessage());
}catch(Exception e1){
System.out.println("Exception::"+e1.getMessage());
}
}
}
if(e.getSource() == item2){
System.exit(0);
}
}
private int[] getPixelData(BufferedImage image, int x, int y) {
int argb = image.getRGB(y, x);
int rgb[] = new int[] {
(argb & 0x00ff0000) >> 16 , //red
(argb & 0x0000ff00) >> 8, //green
argb & 0x000000ff //blue
};
return rgb;
}
private JLabel createImageLabel(int[] pixels){
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = image.getRaster();
raster.setPixels(0, 0, width, height, pixels);
JLabel label = new JLabel(new ImageIcon(image));
return label;
}
}
please advice.
Thanks in advance.

Please check for similar questions and answers on this site about not calling Thread.sleep(...) inside of the Swing event thread. As they state, calling this will put your entire Swing GUI to sleep which is not your intention, I'm sure. Since your problem is no different from all the rest, the solution is the same as well: use a Swing Timer for intermittent actions, and use a background thread such as that generated by a SwingWorker for long-running background actions -- such as reading in images.
Also, if all you're doing is swapping images, then one JLabel should work fine. Just swap the ImageIcon that it displays in your Swing Timer.
Edit
You state:
I am not sure how to iterate my 2D array with swing Timer, every 2 sec I want to iterate my array and perform some action.
Suggestions:
Give your timer a delay of 2000 (for milliseconds)
Give the Timer's ActionListener one or two int counter fields that are initialized to 0.
In the actionPerformed method, use the counter to get the item of interest, and then advance the counter(s).
Read the Swing Timer Tutorial.

Related

Rotating Poly with transformation matrix.Figure is getting deformed

I'm relatively new in Java and I have a task to realize the rotation of a figure drawn from random points. The realization has to be written by means of "naked logic", so AffineTransform tools is not an option in this case. And I got stuck in a moment where I suppose to translate shape to origin in order to perform rotation. I racked my brains, surfed on the internet but couldn't succeed with the solution. There is already one topic with a similar issue, tho there it was about rectangles translation, so it hasn't worked for me. Maybe someone could help with this.
public class Frame extends JFrame {
private JButton polyBtn = new JButton("Draw/Redraw Poly");
private JButton rotationBtn = new JButton("Rotate");
private JSpinner polySpn = new JSpinner(new SpinnerNumberModel(3,3,10,1));
private JSpinner angleSpn = new JSpinner(new SpinnerNumberModel(0,0,360,1));
private JPanel panel = new JPanel();
private JPanel controlPanel = new JPanel();
private JLabel polyLbl = new JLabel("Choose number of corners");
private JLabel angleLbl = new JLabel("Choose angle of rotation");
private int cornerAmount , degree ;
private boolean figureIsDrawed = false;
Random r = new Random();
Polygon poly = new Polygon();
Polygon editedPoly = new Polygon();
public Frame() {
super("Rotate Object");
setBounds(100, 100, 500, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = this.getContentPane();
container.setLayout(new BorderLayout());
setVisible(true);
setLocationRelativeTo(null);
setResizable(false);
polyBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cornerAmount = (int) polySpn.getValue();
drawPoly(cornerAmount);
}});
rotationBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
degree = (int) angleSpn.getValue();
rotateShape(degree);
}});
panel.setPreferredSize(new Dimension(350,250));
panel.setBackground(Color.ORANGE);
panel.setBorder(BorderFactory.createLineBorder(Color.black,3));
controlPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE, 2));
controlPanel.setLayout(new GridLayout(6,0,0,0));
polyLbl.setFont(polyLbl.getFont().deriveFont(10.0f));
angleLbl.setFont(angleLbl.getFont().deriveFont(10.0f));
controlPanel.add(polyLbl);
controlPanel.add(polySpn);
controlPanel.add(polyBtn);
controlPanel.add(angleLbl);
controlPanel.add(angleSpn);
controlPanel.add(rotationBtn);
container.add(controlPanel,BorderLayout.CENTER);
container.add(panel,BorderLayout.EAST);
}
private void drawPoly(int corners) {
Graphics g = panel.getGraphics();
int panelWidth = panel.getWidth();
int panelHeight = panel.getHeight();
if(figureIsDrawed) {
poly.reset();
repaint();
figureIsDrawed = false;
}else {
poly.addPoint(panelWidth/2, panelHeight/2);
System.out.println(poly.xpoints[0]);
System.out.println(poly.ypoints[0]);
for(int i = 0 ; i < corners-1 ; i++) {
poly.addPoint(r.nextInt(panelWidth), r.nextInt(panelHeight));
}
g.drawPolygon(poly);
figureIsDrawed = true;
}
}
private void rotateShape(int degree) {
Graphics g = panel.getGraphics();
int[] xCord = poly.xpoints;
int[] yCord = poly.ypoints;
double rads = degree * (Math.PI/180);
double sin = Math.sin(rads);
double cos = Math.cos(rads);
double[][] transform = new double[3][3];
int panelW = this.getWidth();
int panelH = this.getHeight();
transform[0][0] = cos;
transform[0][1] = -sin;
transform[1][0] = sin;
transform[1][1] = cos;
double[] transformedX = new double[xCord.length];
double[] transformedY = new double[yCord.length];
int[] updatedX = new int[xCord.length];
int[] updatedY = new int[yCord.length];
for(int i = 0;i<updatedX.length;i++) {
updatedX[i] = xCord[i];
updatedY[i] = yCord[i];
transformedX[i] = Math.round(updatedX[i] * transform[0][0] + updatedY[i] * transform[0][1] + transform[0][2]);
transformedY[i] = Math.round( updatedX[i] * transform[1][0] + updatedY[i] * transform[1][1] + transform[1][2]);
updatedX[i] = (int)transformedX[i];
updatedY[i] = (int)transformedY[i];
}
g.setColor(Color.orange);
g.fillRect(0, 0, panelW, panelH);
g.setColor(Color.black);
g.drawPolygon(updatedX, updatedY, updatedX.length);
}
}
The main problem is in "RotateShape" method.I just can't figure out,how to make it work right.
Your rotation code is correct. But you are trying to transform more points than there are in the polygon. The internal xpoints and ypoints arrays are not necessarily filled completely. Replace all occurences of xCord.length and yCord.length with poly.npoints and you are good to go.

How to add multiple rectangles to a jframe(trying to code 2048 in an easy way)

I made the game already and wanted to make my GUI look better with rectangles not with jlabels and now I´ve come to realize that only the last rectangle that is drawn is shown on the GUI
I already tried it with different layouts
my GUI class:
public class GUI_N
{
private Spiel spiel;
private KeyEvent e;
private String beste;
private int beste1;
private DrawingComponent[][] feld;
GUI_N(){
feld = new DrawingComponent[4][4];
spiel = new Spiel();
beste1 = 0;
beste = "Highscore: "+beste1;
JFrame g=new JFrame("2048 - Main");
g.setSize(500,500);
g.setFocusable(true); //wichtig für KeyListener
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int i = 0;
int j = 0;
int h = 0;
int l = 0;
while(i<4)
{
while(j<4)
{
if(i==0){
h = 50;
}else if(i==1){
h = 100;
}else if(i==2){
h = 150;
}else if(i==3){
h = 200;
}
if(j==0){
l = 50;
}else if(j==1){
l = 100;
}else if(j==2){
l = 150;
}else if(j==3){
l = 200;
}
feld[i][j] = new DrawingComponent(l,h,50,50);
feld[i][j].setBounds(l,h,50,50);
j++;
}
j=0;
i++;
}
i = 0;
j = 0;
while(i<4)
{
while(j<4)
{
g.add(feld[i][j]);
j++;
}
j=0;
i++;
}
//g.getContentPane().setBackground(new Color(20, 40, 50));
g.setVisible(true);
}
public static void main(String[] args) {
new GUI_N();
}
}
my rectangle class:
public class DrawingComponent extends JComponent
{
private Graphics2D g2;
private int wert;
private int x;
private int y;
private int w;
private int h;
public DrawingComponent(int px,int py,int pw,int ph)
{
x=px;
y=py;
w=pw;
h=ph;
}
public void paintComponent(Graphics g)
{
g2 = (Graphics2D) g;
Rectangle rect1 = new Rectangle(x,y,w,h);
g2.setColor(Color.RED);
g2.fill(rect1);
}
public void setWert(int x)
{
wert = x;
}
public int getWert()
{
return wert;
}
}
as I said only the last drawn rectangle is shown.
How do I achieve this?
Right now you're adding the rectangles directly to your frame. You should have a JPanel layer in between, to which you can give a LayoutManager (GridLayout would be a good one to look at) to arrange all your rectangles.
So you would have something like this:
JFrame g = new JFrame("2048 - Main");
// GridLayout (on next line) takes number of rows and columns
JPanel panel = new JPanel(new GridLayout(4, 4));
// ... add all the rectangles to the panel here
g.add(panel);
And then you would add your rectangles to the panel, not the frame. As you add them, they will automatically go into place in the grid.
panel.add(feld[i][j]);
Also, if you use GridLayout, it will resize and fit the components to the grid dynamically, so it may save you some code as well, since you wouldn't need to hardcode their sizes in the GUI class.

Setting a label text in Swing undos all button location movements

I have the weirdest bug ever.
I have this puzzle game that moves puzzle pieces (which really are buttons with images attached to them).
Everything worked fine until I tried to change the text of some label (to indicate how many steps the player has done).
Everytime I call someControl.setText("text");, the puzzle pieces that moved are set back to the their first position. I have no idea why, but they just do.
Here's my window:
It consists of two panels, each uses a GridBagLayout.
The main frame uses a gridBagLayout as well, which consists of the two panels.
I know it's weird as hell, but I can't figure out what may cause this GUI bug. Any idea?
The pieces of code:
increaseSteps which is called everytime I click a puzzle button
void increaseSteps() {
_steps++;
_lblSteps.setText("Steps: " + _steps);
}
Creation of the puzzle panel (the left panel)
private JPanel puzzlePanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int i = 0; i < _splitImage.getSize(); i++)
for (int j = 0; j < _splitImage.getSize(); j++) {
int valueAtPos = _board.getMatrix()[i][j];
if (valueAtPos == 0)
continue;
int imageRow = _board.getImageRowFromValue(valueAtPos);
int imageCol = _board.getImageColFromValue(valueAtPos);
ImageIcon imageIcon = new ImageIcon(_splitImage.getImages()[imageRow][imageCol]);
JButton btn = new JButton(imageIcon);
_tileButtons[i][j] = new TileButton(btn, i, j);
btn.setPreferredSize(new Dimension(_splitImage.getImages()[i][j].getWidth(null),
_splitImage.getImages()[i][j].getHeight(null)));
// add action listener
btn.addActionListener(this);
btn.addKeyListener(this);
gbc.gridx = j;
gbc.gridy = i;
panel.add(_tileButtons[i][j].getButton(), gbc);
}
return panel;
}
actionPerformed:
#Override
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JButton))
return;
JButton btn = (JButton) e.getSource();
TileButton tile = getTileButtonFromBtn(btn);
if (tile == null)
return;
// check if we can move the tile
String moveDir = _board.canMoveTile(tile.getRow(), tile.getCol());
if (moveDir.equals("no"))
return;
increaseSteps();
int dirx = 0;
int diry = 0;
if (moveDir.equals("left")) {
dirx = -1;
_board.move("left", true);
tile.setCol(tile.getCol() - 1);
} else if (moveDir.equals("right")) {
dirx = 1;
_board.move("right", true);
tile.setCol(tile.getCol() + 1);
} else if (moveDir.equals("up")) {
diry = -1;
_board.move("up", true);
tile.setRow(tile.getRow() - 1);
} else { // down
diry = 1;
_board.move("down", true);
tile.setRow(tile.getRow() + 1);
}
moveButton(btn, dirx, diry, MOVE_SPEED);
if (_board.hasWon())
win();
}
moveButton: (moves the button in a seperate thread, calling btn.setLocation())
private void moveButton(JButton btn, int dirx, int diry, int speed) {
Point loc = btn.getLocation();
// get start ticks, calculate distance etc...
StopWatch stopper = new StopWatch();
int distance;
if (dirx != 0)
distance = _splitImage.getImages()[0][0].getWidth(null) * dirx;
else
distance = _splitImage.getImages()[0][0].getHeight(null) * diry;
if (speed > 0) {
// run the animation in a new thread
Thread thread = new Thread() {
public void run() {
int currentTicks;
int elapsed;
do {
int newX = loc.x;
int newY = loc.y;
elapsed = stopper.getElapsed();
int moved = (int) ((double) distance * (double) (elapsed / (double) speed));
if (dirx != 0)
newX += moved;
else
newY += moved;
btn.setLocation(newX, newY);
} while (elapsed <= MOVE_SPEED);
// make sure the last location is exact
btn.setLocation(loc.x + (dirx == 0 ? 0 : distance), loc.y + (diry == 0 ? 0 : distance));
}
};
thread.start();
}
else
btn.setLocation(loc.x + (dirx == 0 ? 0 : distance), loc.y + (diry == 0 ? 0 : distance));
}
You're trying to set the absolute position of a component via setLocation(...) or setBounds(...), one that is held by a container that uses a layout manager. This may work temporarily, but will fail if the container's layout manager is triggered to re-do the layout of its contained components. When that happens, the GridBagConstraints will take over and the components will move to their gridbag constraints assigned location.
The solution is to not do this, and instead to place the location of your components in concert with the layout managers used.
Another problem is that your current code is not Swing thread-safe since you're making Swing state changes from within a background thread. This won't always cause problems, but since it's a threading issue, risks causing intermittent hard to debug problems (ones that usually only occur when your boss or instructor are trying to run your code).
Possible solutions:
For a grid of images, you could use a grid of JLabels (or JButtons if you must) held in a container that uses GridLayout. When you need to reposition components, remove all components held by that JPanel, and then re-add, using the order of addition to help you position the components.
Easiest though would be to use a grid of non-moving JLabels, give them MouseListeners, and instead of moving the JLabels, remove and add Icons to them, including a blank Icon.
If you need to do Swing animation, use a Swing Timer to drive the animation. This will allow your code to make repetitive calls with delay between the calls, and with these calls being made on the Swing event thread, the EDT (event dispatch thread).
Demo proof of concept example code that shows swapping icons, but without animation, and without test of solution yet:
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ImageShuffle extends JPanel {
private static final int SIDES = 3;
public static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/5/5a/Hurricane_Kiko_Sep_3_1983_1915Z.jpg/"
+ "600px-Hurricane_Kiko_Sep_3_1983_1915Z.jpg";
private List<Icon> iconList = new ArrayList<>(); // shuffled icons
private List<Icon> solutionList = new ArrayList<>(); // in order
private List<JLabel> labelList = new ArrayList<>(); // holds JLabel grid
private Icon blankIcon;
public ImageShuffle(BufferedImage img) {
setLayout(new GridLayout(SIDES, SIDES, 1, 1));
fillIconList(img); // fill array list with icons and one blank one
Collections.shuffle(iconList);
MyMouseListener myMouse = new MyMouseListener();
for (Icon icon : iconList) {
JLabel label = new JLabel(icon);
label.addMouseListener(myMouse);
add(label);
labelList.add(label);
}
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
JLabel selectedLabel = (JLabel) e.getSource();
if (selectedLabel.getIcon() == blankIcon) {
return; // don't want to move the blank icon
}
// index variables to hold selected and blank JLabel's index location
int selectedIndex = -1;
int blankIndex = -1;
for (int i = 0; i < labelList.size(); i++) {
if (selectedLabel == labelList.get(i)) {
selectedIndex = i;
} else if (labelList.get(i).getIcon() == blankIcon) {
blankIndex = i;
}
}
// get row and column of selected JLabel
int row = selectedIndex / SIDES;
int col = selectedIndex % SIDES;
// get row and column of blank JLabel
int blankRow = blankIndex / SIDES;
int blankCol = blankIndex % SIDES;
if (isMoveValid(row, col, blankRow, blankCol)) {
Icon selectedIcon = selectedLabel.getIcon();
labelList.get(selectedIndex).setIcon(blankIcon);
labelList.get(blankIndex).setIcon(selectedIcon);
// test for win here by comparing icons held by labelList
// with the solutionList
}
}
private boolean isMoveValid(int row, int col, int blankRow, int blankCol) {
// has to be on either same row or same column
if (row != blankRow && col != blankCol) {
return false;
}
// if same row
if (row == blankRow) {
// then columns must be off by 1 -- they're next to each other
return Math.abs(col - blankCol) == 1;
} else {
// or else rows off by 1 -- above or below each other
return Math.abs(row - blankRow) == 1;
}
}
public void shuffle() {
Collections.shuffle(iconList);
for (int i = 0; i < labelList.size(); i++) {
labelList.get(i).setIcon(iconList.get(i));
}
}
}
private void fillIconList(BufferedImage img) {
// get the width and height of each individual icon
// which is 1/3 the image width and height
int w = img.getWidth() / SIDES;
int h = img.getHeight() / SIDES;
for (int row = 0; row < SIDES; row++) {
int y = (row * img.getWidth()) / SIDES;
for (int col = 0; col < SIDES; col++) {
int x = (col * img.getHeight()) / SIDES;
// create a sub image
BufferedImage subImg = img.getSubimage(x, y, w, h);
// create icon from the image
Icon icon = new ImageIcon(subImg);
// add to both icon lists
iconList.add(icon);
solutionList.add(icon);
}
}
// create a blank image and corresponding icon as well.
BufferedImage blankImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
blankIcon = new ImageIcon(blankImg);
iconList.remove(iconList.size() - 1); // remove last icon from list
iconList.add(blankIcon); // and swap in the blank one
solutionList.remove(iconList.size() - 1); // same for the solution list
solutionList.add(blankIcon);
}
private static void createAndShowGui(BufferedImage img) {
JFrame frame = new JFrame("ImageShuffle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ImageShuffle(img));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
URL imgUrl = null;
BufferedImage img;
try {
imgUrl = new URL(IMG_PATH);
img = ImageIO.read(imgUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
}
}
}
If I wanted animation, again, I'd raise the icon into the JFrame's glasspane, animate it to the new position using a Swing Timer, and then place the icon into the new JLabel. I'd also disable the MouseListener using a boolean field, a "flag", until the animation had completed its move.

Double dimensional array with colours doesn't paint in paintComponent

I've been working on a dots look-a-like, but I'm having trouble painting the dots on the board. The array seems to work but it doesn't want to paint it.
Sorry, some of my variables are in Dutch but that shouldn't really pose too many confusion.
public class Bord extends JFrame{
Slang slang = new Slang();
Tile[][] tile = new Tile[6][6];
private JPanel menuPanel;
private JPanel gridPanel;
private JLabel levelTitel;
private JLabel levelNummer;
private JLabel scoreTitel;
private JLabel scoreNummer;
private JLabel targetTitel;
private JLabel targetNummer;
private JLabel timeTitel;
private JLabel timeNummer;
private JLabel pauzeKnop;
public Bord() {
super("Dots");
//setLocationRelativeTo(this);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
maakAttributen();
maakListeners();
maakLayout();
pack();
setSize(650, 750);
setVisible(true);
getContentPane();
repaint();
//TODO automatic size
}
public void maakAttributen() {
levelTitel = new JLabel("level");
levelNummer = new JLabel("1");
scoreTitel = new JLabel("score");
scoreNummer = new JLabel("2");
targetTitel = new JLabel("target");
targetNummer = new JLabel("3");
timeTitel = new JLabel("time");
timeNummer = new JLabel("4");
//TODO image in knop zetten
pauzeKnop = new JLabel("PAUZE");
}
public void maakListeners() {
}
public void maakLayout() {
JPanel menuPanel = new JPanel(new GridLayout(0, 5, 5, 5));
JPanel gridPanel = new JPanel(new GridLayout(0, 7, 5, 5));
add(menuPanel, BorderLayout.PAGE_START);
add(gridPanel, BorderLayout.CENTER);
//menu attributen aan menu toevoegen
menuPanel.add(levelTitel);
menuPanel.add(scoreTitel);
menuPanel.add(targetTitel);
menuPanel.add(timeTitel);
menuPanel.add(pauzeKnop);
menuPanel.add(levelNummer);
menuPanel.add(scoreNummer);
menuPanel.add(targetNummer);
menuPanel.add(timeNummer);
//grid met dots toevoegen
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
RandomKleur kleur = new RandomKleur();
tile[x][y] = new Tile(kleur.getKleur());
gridPanel.add(new myDots());
}
}
}
private class myDots extends JPanel {
#Override
protected void paintComponent(Graphics g) {
int h = getHeight();
int w = getWidth();
super.paintComponent(g);
for (int x = 0; x < 6; x++) {
for (int y =0; y < 6; y++) {
g.setColor(tile[x][y].getKleur());
g.fillOval(h / 2, w / 2, 33, 33);
}
}
}
}
}
I've tried debugging it and it gives some kind of null pointer exception sometimes.
You basic painting logic is wrong. You are adding 36 Dot panels to the frame, but then in the painting logic you are repainting all 36 dots on top of one another so only the last dot painted will display. The paintComponent() method should only be painting a single dot.
You need to change your MyDots class to accept a Tile as a parameter and then save the Tile object as an instance variable of the class. Then the code would be something like:
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 6; y++) {
RandomKleur kleur = new RandomKleur();
tile[x][y] = new Tile(kleur.getKleur());
//gridPanel.add(new myDots());
gridPanel.add(new myDots(tile[x][y]));
}
}
I don't know if you even need the tile array, because now the MyDots class has the tile information.
Then Your painting logic should be something like:
//for (int x = 0; x < 6; x++) {
//for (int y =0; y < 6; y++) {
//g.setColor(tile[x][y].getKleur());
g.setColor(tile.getKleur()); // where "tile" is the instance variable
g.fillOval(h / 2, w / 2, 33, 33);
//}
//}
Who knows why you get the NPE, because the exception is not related to the code you posted.
By the way class name should start with an upper case character. It should be "MyDot".
Edit:
Do I have to create a new method in MyDots?
You need to create a constructor for your class:
public class MyDots
{
private Tile tile;
public MyDots(Tile tile)
{
this.tile = tile;
}
#Override
protectect paintComponent(Graphics g)
...
}

How to implement actionListener on BufferedImage multiple times

I am currently designing an image editor in a GUI which has several buttons which, when clicked, should apply different effects on the loaded image. I have the effects working with an ActionListener but if I try to click an effect after already clicking another effect, the image turns black instead of applying the desired effect. How do I apply multiple effects to the same image? Here is my code for the ButtonPanel class, which includes the ActionListener and code for the effects(only three of the effects have been implemented as of yet):
class ButtonPanel extends JPanel
{
//JButton makeBlue;
BufferedImage img;
ImagePanel ip = new ImagePanel();
ButtonPanel(ImagePanel x)
{
final JButton makeBlue = new JButton ("Make Blue");
final JButton makeRed = new JButton ("Make Red");
final JButton makeGreen = new JButton ("Make Green");
final JButton invertColors = new JButton ("Invert Colors");
final JButton makeGreyscale = new JButton ("Greyscale");
final JButton makeWarhol = new JButton ("Warhol");
final JButton flipVertical = new JButton ("Flip Vertical");
final JButton flipHorizontal = new JButton ("Flip Horizontal");
final JButton rotateClockwise = new JButton ("Rotate Clockwise");
setBackground(Color.RED);
ip = x;
//int width, height;
//setBackground(Color.RED);
//int height = 0;
add(makeBlue);
add(makeRed);
add(makeGreen);
add(invertColors);
add(makeGreyscale);
add(makeWarhol);
add(flipVertical);
add(flipHorizontal);
add(rotateClockwise);
ActionListener action =
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
BufferedImage img = ip.getImg();
if (e.getSource()== makeBlue)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
int value = img.getRGB(i,j);
int y = 0xFF0000FF;
value = value & y;
img.setRGB(i,j,value);
}
}
ip.setImage(img);
setBackground(Color.GREEN);
repaint();
}
else if(e.getSource()== makeRed)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
//fill in code here
int value = img.getRGB(i,j);
int y = 0xFFFF0000;
value = value & y;
//System.out.println(value);
img.setRGB(i,j,value);
}
}
ip.setImage(img);
repaint();
}
else if(e.getSource()== makeGreen)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
//fill in code here
int value = img.getRGB(i,j);
int y = 0xFF00FF00;
value = value & y;
img.setRGB(i,j,value);
}
}
ip.setImage(img);
repaint();
}
}
};
makeBlue.addActionListener(action);
makeRed.addActionListener(action);
makeGreen.addActionListener(action);
makeWarhol.addActionListener(action);
flipVertical.addActionListener(action);
flipHorizontal.addActionListener(action);
rotateClockwise.addActionListener(action);
makeGreyscale.addActionListener(action);
invertColors.addActionListener(action);
}
}
Any help would be appreciated. Thanks.
Your problem is that you're extracting all of one color out of the image, and then replacing the original image in your ImagePanel with the new extracted image that is, say if the green button is pressed, all green. Then when you try to extract red from the ImagePanel's image, you get all black because the image is now only green.
You need to save the original image somewhere if you want to extract the original colors. Perhaps you should give ImagePanel a method, getOriginalImage() or some such, and have it store two images, one the displayed image and one the changed one.
Better still, use an Model-View-Control pattern and store your images elsewhere off the GUI.
There are two ways to accomplish this. You can either have your class be the ActionListener (which is the way you have it set up now), or you can have a unique ActionListener for each button. As a design decision I prefer the latter, as you can have more precise control and easier to read code this way.
Each of your buttons, menu items, and any other Object you want to have a unique effect should each have it's own ActionListener. You can either write a new class file for each ActionListener, an inner class, or an anonymous inner class for each. I prefer anonymous inner classes placed in line of your constructor or setup method like this:
JButton testButton = new JButton("Test");
testButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here
System.out.println("You clicked me!");
}
});
This method allows you to ignore huge conditional branches and unnecessary comparisons. Implement the interface uniquely for each component that needs the listener.

Categories

Resources