How to prevent a custom view to draw over itself? - java

I'm developing a Sudoku app on Android and I can't prevent my custom view (the sudoku board) to draw over itself. I'm quite new to app development, so I can't understand what's happening. Basically when I pass a board to the GameActivity the custom view in there draws the new board over the older ones. This should not happen. Any help would be appriciated.
This is my custom View.
public class SudokuBoardView extends View {
private static final String TAG = "SUDOKUVIEWGRID";
//Paints
private Paint thinPaint;
private Paint thickPaint;
private Paint selectedCellPaint;
private Paint textPaint;
//Values
private static int width;
private static int height;
private static final int padding = 64;
private static final int SIZE = 9;
private static final int SQRT_SIZE = 3;
private float cellSizePixels;
//Model
private SudokuModel sudokuModel = null;
public SudokuBoardView(Context context) {
super(context);
init(null);
}
public SudokuBoardView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public SudokuBoardView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
public SudokuBoardView(Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
public void init(#Nullable AttributeSet attributeSet) {
//Paint più sottile per celle
thinPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thinPaint.setStrokeWidth(2);
thinPaint.setStyle(Paint.Style.STROKE);
thinPaint.setColor(Color.BLACK);
//Paint più spesso per contorni
thickPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thickPaint.setStrokeWidth(10);
thickPaint.setStyle(Paint.Style.STROKE);
thickPaint.setColor(Color.BLACK);
//Paint per celle selezionate
selectedCellPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
selectedCellPaint.setColor(Color.BLUE);
selectedCellPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//Paint per numeri
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(32);
textPaint.setColor(Color.BLACK);
//Dimensioni della griglia e delle celle
width = getResources().getDisplayMetrics().widthPixels; //Dim. assoluta dello schermo
height = getResources().getDisplayMetrics().heightPixels;
cellSizePixels = (float) ((width - 2*padding)/ SIZE);
}
public void setSudokuModel(SudokuModel model) {
this.sudokuModel = model;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Outside Border
canvas.drawRoundRect(padding,padding, width - padding, width - padding, 20, 20, thickPaint);
//Cells
drawLines(canvas);
if (sudokuModel.isNewGame()) {
drawInitialBoard(canvas, sudokuModel.getBoard());
}
}
public void cleanCells() {
invalidate();
}
protected void drawLines(Canvas canvas){
//Linee Verticali
for (int i = 0; i < SIZE; i++) {
//Linea più spessa ogni 3 linee (la prima viene saltata perché c'è già il bordo)
if (i == 0) continue;
if (i % SQRT_SIZE == 0) {
canvas.drawLine( i*cellSizePixels + padding, padding, i*cellSizePixels + padding, width - padding, thickPaint);
} else {
canvas.drawLine( i*cellSizePixels + padding, padding, i*cellSizePixels + padding, width - padding, thinPaint);
}
}
//Linee Orizzontali
for (int i = 0; i < SIZE; i++) {
//Linea più spessa ogni 3 linee (la prima viene saltata perché c'è già il bordo)
if (i == 0) continue;
if (i % SQRT_SIZE == 0) {
canvas.drawLine( padding, i*cellSizePixels + padding, width - padding, i*cellSizePixels + padding, thickPaint);
} else {
canvas.drawLine(padding, i * cellSizePixels + padding, width - padding, i * cellSizePixels + padding, thinPaint);
}
}
}
public void drawInitialBoard(Canvas canvas, Board board) {
for (Cell cell: board.getCellList()) {
int value = cell.getValue();
String valueText = Integer.toString(value);
int row = cell.getRow();
int col = cell.getCol();
Rect textBounds = new Rect();
textPaint.getTextBounds(valueText, 0, valueText.length(), textBounds);
float textWidth = textPaint.measureText(valueText);
float textHeight = textBounds.height();
canvas.drawText((value == 0 ? "" : valueText), (row * cellSizePixels + cellSizePixels/2 - textWidth/2 + padding), (col*cellSizePixels + cellSizePixels/2 + thickPaint.getStrokeWidth() + padding), textPaint);
}
}
}
And this is the GameActivity where the view is.
public class GameActivity extends AppCompatActivity {
//Controls Buttons
Button[] buttons = new Button[10];
private static final int[] BUTTON_IDS = {
R.id.button1,
R.id.button2,
R.id.button3,
R.id.button4,
R.id.button5,
R.id.button6,
R.id.button7,
R.id.button8,
R.id.button9,
R.id.buttonCancel
};
NumbersOnClickListener numbersOnClickListener;
private Board board;
private SudokuModel sudokuModel;
private SudokuBoardView sudokuBoardView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
/*
* NEW GAME
*
* Board Setup
* */
Intent gameIntent = getIntent();
boolean isNewGame = gameIntent.getBooleanExtra("new game", false);
if (isNewGame) {
board = gameIntent.getParcelableExtra("Board");
sudokuModel = new SudokuModel(board, isNewGame);
sudokuModel.getBoard().printBoard();
sudokuBoardView = findViewById(R.id.sudokuView);
sudokuBoardView.setSudokuModel(sudokuModel);
}
//Controls Setup
numbersOnClickListener = new NumbersOnClickListener();
for (int i = 0; i < 10; i++) {
buttons[i] = findViewById(BUTTON_IDS[i]);
buttons[i].setOnClickListener(numbersOnClickListener);
GridLayout.LayoutParams params = (GridLayout.LayoutParams) buttons[i].getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 7;
params.height = params.width;
buttons[i].setLayoutParams(params);
}
}
#Override
protected void onPause() {
super.onPause();
}
}
The SudokuModel class.
public class SudokuModel {
private Board board;
private boolean isNewGame;
private int selectedRow = -1;
private int selectedCol = -1;
public SudokuModel(Board board, boolean isNewGame) {
this.board = board;
this.isNewGame = isNewGame;
}
public Board getBoard() {
return board;
}
public void setBoard(Board board) {
this.board = board;
}
public boolean isNewGame() {
return isNewGame;
}
public int getSelectedRow() {
return selectedRow;
}
public int getSelectedCol() {
return selectedCol;
}
public void setSelectedRow(int selectedRow) {
this.selectedRow = selectedRow;
}
public void setSelectedCol(int selectedCol) {
this.selectedCol = selectedCol;
}
}
The Board class.
public class Board implements Parcelable {
private static final int SIZE = 9;
private ArrayList<Cell> cellList = new ArrayList<>();
public Board(ArrayList<Cell> cellList) {
this.cellList = cellList;
}
public ArrayList<Cell> getCellList() {
return cellList;
}
public void setCellList(ArrayList<Cell> cellList) {
this.cellList = cellList;
}
public void printBoard () {
for (Cell cell: cellList) {
System.out.println("Cell " + cell.getRow() + ":" + cell.getCol() + " VALUE: " + cell.getValue());
}
}
protected Board(Parcel in) {
if (in.readByte() == 0x01) {
cellList = new ArrayList<Cell>();
in.readList(cellList, Cell.class.getClassLoader());
} else {
cellList = null;
}
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
if (cellList == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(cellList);
}
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Board> CREATOR = new Parcelable.Creator<Board>() {
#Override
public Board createFromParcel(Parcel in) {
return new Board(in);
}
#Override
public Board[] newArray(int size) {
return new Board[size];
}
};
}
The Cell class.
public class Cell implements Parcelable {
private int row;
private int col;
private int value;
public Cell(int row, int col, int value) {
this.row = row;
this.col = col;
this.value = value;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
protected Cell(Parcel in) {
row = in.readInt();
col = in.readInt();
value = in.readInt();
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(row);
dest.writeInt(col);
dest.writeInt(value);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<Cell> CREATOR = new Parcelable.Creator<Cell>() {
#Override
public Cell createFromParcel(Parcel in) {
return new Cell(in);
}
#Override
public Cell[] newArray(int size) {
return new Cell[size];
}
};
}
Here is where the board is generated and passed to the game activity.
public class SudokuGenerator implements Response.ErrorListener, Response.Listener<JSONObject> {
private static final String TAG = "SUDOKU_GENERATOR";
private String url = "https://sugoku.herokuapp.com/board?difficulty=";
public int[][] puzzle = new int[9][9];
ArrayList<Cell> generatedPuzzleCells = new ArrayList<>();
private RequestQueue requestQueue;
private Context context;
LoadingDialog loadingDialog;
NewGameErrorDialog newGameErrorDialog;
public SudokuGenerator(Context context) {
requestQueue = Volley.newRequestQueue(context);
this.context = context;
this.loadingDialog = new LoadingDialog((Activity) context);
this.newGameErrorDialog = new NewGameErrorDialog((Activity) context);
}
public int[][] getPuzzle() {
return puzzle;
}
public void setPuzzle(int[][] puzzle) {
this.puzzle = puzzle;
}
public void setDifficulty(int difficulty) {
switch (difficulty){
case Globals.EASY:
url = url.concat("easy");
break;
case Globals.MEDIUM:
url = url.concat("medium");
break;
case Globals.HARD:
url = url.concat("hard");
break;
default:
url = url.concat("random");
break;
}
}
public void puzzleGenerator (int difficulty) {
loadingDialog.startLoadingDialog();
setDifficulty(difficulty);
System.out.println("Set Difficulty");
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url,null,this, this);
requestQueue.add(request);
System.out.println("Made request");
url = "https://sugoku.herokuapp.com/board?difficulty=";
}
#Override
public void onErrorResponse(VolleyError error) {
System.out.println("ERROR Response");
newGameErrorDialog.startErrorDialog();
loadingDialog.dismissDialog();
}
#Override
public void onResponse(JSONObject response) {
System.out.println("Response");
//Check if not empty
if (response.length() == 0){
} //Error Handling
try {
JSONArray board = response.getJSONArray("board");
System.out.println("Board " + board);
for (int i = 0; i < board.length(); i++) {
JSONArray box = board.getJSONArray(i);
for (int j = 0; j < box.length(); j++) {
int k = box.getInt(j);
Cell cell;
if (k == 0) {
cell = new Cell(i, j, k, 0);
} else {
cell = new Cell(i, j, k, 1);
}
Log.d(TAG, "onResponse: GENERATED CELL: " + i +" "+j+" : "+k+" "+cell.isStartingCell());
generatedPuzzleCells.add(cell);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
Board generatedBoard = new Board(generatedPuzzleCells);
generatedBoard.printBoard();
loadingDialog.dismissDialog();
Intent gameIntent = new Intent(context, GameActivity.class);
gameIntent.putExtra("Board", generatedBoard);
gameIntent.putExtra("new game",true);
context.startActivity(gameIntent);
}
}
Here are two screenshots of what happens on the first tap of the new game (how it should be) and what happens after going back to main activity (where the new game button is) and pressing the button again.

Related

How can I Resize a JScrollPane with JTable on it?

I created a JTable with some nice functions. My problem is, that it does not resize when I size the frame where it is on. Can someone help me with my Code so it does resize like it should? I alaready tryed some ideas of posts I found but it did not rly help me. So I have tryed to add the JPanel on another one with some Layout ideas. I have also tryed to use ComponentListeners and setSize on resizeaction.
Code:
public class TableyTable extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public JTableHeader header;
public JTable table;
public JScrollPane scrollPane;
public JPopupMenu renamePopup;
public JTextField text;
public TableColumn column;
private boolean headerEditable = false;
private boolean tableEditable = false;
public static final Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
public static final int MIN_ROW_HEIGHT = (int)SCREEN_SIZE.getHeight()/36;
public static final int MIN_ROW_WIDTH = (int)SCREEN_SIZE.getWidth()/108;
public TableyTable(int row, int column) {
init(row, column);
}
public void init(int row, int column) {
table = new JTable(row, column) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
if (tableEditable) return true;
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.changeSelection(0, 0, false, false);
header = table.getTableHeader();
header.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent event) {
if (event.getClickCount() == 2 && headerEditable) {
editColumnAt(event.getPoint());
}
}
});
text = new JTextField();
text.setBorder(null);
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (headerEditable) renameColumn();
}
});
table.setRowSelectionAllowed(false);
table.setCellSelectionEnabled(true);
renamePopup = new JPopupMenu();
renamePopup.setBorder(new MatteBorder(0, 1, 1, 1, Color.DARK_GRAY));
renamePopup.add(text);
scrollPane = new JScrollPane( table );
scrollPane.setRowHeaderView(buildRowHeader(table));
table.setRowHeight(MIN_ROW_HEIGHT);
TableColumnModel cm = table.getColumnModel();
for(int i = 0; i < table.getColumnModel().getColumnCount(); i++)
cm.getColumn(i).setWidth(200);
table.setColumnModel(cm);
add(scrollPane);
}
public void setHeaderEditable(boolean b) {
headerEditable = b;
}
public boolean isHeaderEditable() {
return headerEditable;
}
public void setTableEditable(boolean b) {
tableEditable = b;
}
public boolean isTableEditable() {
return tableEditable;
}
private void editColumnAt(Point p) {
int columnIndex = header.columnAtPoint(p);
if (columnIndex != -1) {
column = header.getColumnModel().getColumn(columnIndex);
Rectangle columnRectangle = header.getHeaderRect(columnIndex);
text.setText(column.getHeaderValue().toString());
renamePopup.setPreferredSize(new Dimension(columnRectangle.width, columnRectangle.height - 1));
renamePopup.show(header, columnRectangle.x, 0);
text.requestFocusInWindow();
text.selectAll();
}
}
private void renameColumn() {
column.setHeaderValue(text.getText());
renamePopup.setVisible(false);
header.repaint();
}
private static JList<Object> buildRowHeader(JTable table) {
final Vector<String> headers = new Vector<String>();
for (int i = 0; i < table.getRowCount(); i++) {
String name = "";
if (i < 10) {
name += "0";
}
if (i < 100) {
name += "0";
}
name += i;
headers.add(name);
}
ListModel<Object> lm = new AbstractListModel<Object>() {
/**
*
*/
private static final long serialVersionUID = 1L;
public int getSize() {
return headers.size();
}
public Object getElementAt(int index) {
return headers.get(index);
}
};
final JList<Object> rowHeader = new JList<>(lm);
rowHeader.setOpaque(false);
rowHeader.setFixedCellWidth(TableyTable.MIN_ROW_HEIGHT);
MouseInputAdapter mouseAdapter = new MouseInputAdapter() {
Cursor oldCursor;
Cursor RESIZE_CURSOR = Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
int index = -1;
int oldY = -1;
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
int previ = getLocationToIndex(new Point(e.getX(), e.getY() - 3));
int nexti = getLocationToIndex(new Point(e.getX(), e.getY() + 3));
if (previ != -1 && previ != nexti) {
if (!isResizeCursor()) {
oldCursor = rowHeader.getCursor();
rowHeader.setCursor(RESIZE_CURSOR);
index = previ;
}
} else if (isResizeCursor()) {
rowHeader.setCursor(oldCursor);
}
}
private int getLocationToIndex(Point point) {
int i = rowHeader.locationToIndex(point);
if (!rowHeader.getCellBounds(i, i).contains(point)) {
i = -1;
}
return i;
}
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (isResizeCursor()) {
rowHeader.setCursor(oldCursor);
index = -1;
oldY = -1;
}
}
#Override
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
if (isResizeCursor() && index != -1) {
int y = e.getY();
if (oldY != -1) {
int inc = y - oldY;
int oldRowHeight = table.getRowHeight(index);
int oldNextRowHeight = table.getRowHeight(index+1);
if (oldRowHeight > MIN_ROW_HEIGHT || inc > 0) {
int rowHeight = Math.max(MIN_ROW_HEIGHT, oldRowHeight + inc);
table.setRowHeight(index, rowHeight);
if (rowHeader.getModel().getSize() > index + 1) {
int rowHeight1 = table.getRowHeight(index + 1) - inc;
rowHeight1 = Math.max(MIN_ROW_HEIGHT, rowHeight1);
table.setRowHeight(index + 1, rowHeight1);
}
}
if (table.getRowCount()>index+1)
table.setRowHeight(1+index, oldNextRowHeight);
else System.out.println("HI");
}
oldY = y;
}
}
private boolean isResizeCursor() {
return rowHeader.getCursor() == RESIZE_CURSOR;
}
};
rowHeader.addMouseListener(mouseAdapter);
rowHeader.addMouseMotionListener(mouseAdapter);
rowHeader.addMouseWheelListener(mouseAdapter);
rowHeader.setCellRenderer(new RowHeaderRenderer(table));
rowHeader.setBackground(table.getBackground());
rowHeader.setForeground(table.getForeground());
return rowHeader;
}
static class RowHeaderRenderer extends JLabel implements ListCellRenderer<Object> {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTable table;
RowHeaderRenderer(JTable table) {
this.table = table;
JTableHeader header = this.table.getTableHeader();
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
setDoubleBuffered(true);
}
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
setText((value == null) ? "" : value.toString());
setPreferredSize(null);
setPreferredSize(new Dimension((int) getPreferredSize().getWidth(), table.getRowHeight(index)));
list.firePropertyChange("cellRenderer", 0, 1);
return this;
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Tabley");
TableyTable table = new TableyTable(1000, 18278);
table.setHeaderEditable(true);
table.setTableEditable(true);
frame.add(table);
frame.setSize(new Dimension(700, 500));
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
As in the tutorial described, you need to set a LayoutManager and add the JScrollPane accordingly:
setLayout(new BorderLayout());
add(scrollPane,BorderLayout.CENTER);

Exoplayer getting Warning "SimpleExoPlayer: Player is accessed on the wrong thread." How to solved?

In mainThread of Activity my image handler and Exo player (for play music)
used. Nut in OS-9 (Nokia) Device Not Working properly imageHandler -> that is connected to Workhandler.
below the code: WorkHandler
public class WorkHandler extends android.os.HandlerThread {
private Handler workHandler = null;
private volatile List<WorkMessageProxy> messageProxyList;
public WorkHandler() {
super("WorkHandler", Process.THREAD_PRIORITY_BACKGROUND);
start();
workHandler = new Handler(getLooper()) {
#Override
public void handleMessage(Message msg) {
if (messageProxyList != null) {
for (WorkMessageProxy workMessageProxy : messageProxyList) {
Log.i("workHandler", "handleMessage: Message: " + msg.toString());
workMessageProxy.handleMessage(msg);
}
}
}
};
}
public void post(Runnable run) {
workHandler.post(run);
}
public void postAtFrontOfQueue(Runnable runnable) {
workHandler.postAtFrontOfQueue(runnable);
}
public void postDelayed(Runnable runnable, long delay) {
workHandler.postDelayed(runnable, delay);
}
public void postAtTime(Runnable runnable, long time) {
workHandler.postAtTime(runnable, time);
}
public void addMessageProxy(WorkMessageProxy proxy) {
initMessageProxyList();
messageProxyList.add(proxy);
}
public void removeMessageProxy(WorkMessageProxy proxy) {
initMessageProxyList();
messageProxyList.remove(proxy);
}
private void initMessageProxyList() {
if (messageProxyList == null) {
messageProxyList = new ArrayList<>();
}
}
public Handler getHandler() {
return workHandler;
}
public interface WorkMessageProxy {
void handleMessage(Message msg);
}
}
ImageHandler
public class ImageFrameHandler implements WorkHandler.WorkMessageProxy {
private static final String TAG = "ImageFrameHandler";
private Resources resources;
private int[] resArray;
private int width;
private int height;
public boolean isRunning;
public final WorkHandler workHandler;
private File[] files;
private static final int FILE = 0;
private static final int RES = 1;
private int type;
private boolean isOpenCache;
#Retention(RetentionPolicy.SOURCE)
#IntDef({FILE, RES})
public #interface Operation {
}
ImageFrameHandler(#Operation int type) {
this.type = type;
imageCache = new ImageCache();
workHandler = new WorkHandler();
}
#Deprecated
public ImageFrameHandler() {
imageCache = new ImageCache();
workHandler = new WorkHandler();
}
private ImageCache imageCache;
private Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
if (onImageLoadListener != null) {
onImageLoadListener.onImageLoad(bitmapDrawable);
}
switch (msg.what) {
case RES:
load((int[]) msg.obj);
break;
case FILE:
load((File[]) msg.obj);
break;
}
}
};
private volatile float frameTime;
private volatile float delayTime;//in millisecond
private volatile int index = 0;
private volatile BitmapDrawable bitmapDrawable;
private OnImageLoadListener onImageLoadListener;
private boolean loop;
/**
* load frame form file directory;
*
* #param width request width
* #param height request height
* #param fileDir file directory
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(final String fileDir, int width, int height, int fps,
OnImageLoadListener onPlayFinish) {
if (!isRunning) {
isRunning = true;
this.width = width;
this.height = height;
loadImage(fileDir, fps, onPlayFinish);
}
}
/**
* load frame form file directory;
*
* #param fileDir file directory
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(final String fileDir, int fps, OnImageLoadListener onPlayFinish) {
if (!isRunning && !TextUtils.isEmpty(fileDir) && fps > 0) {
isRunning = true;
File dir = new File(fileDir);
if (dir.exists() && dir.isDirectory()) {
File[] files = dir.listFiles();
loadImage(files, width, height, fps, onPlayFinish);
}
}
}
/**
* load frame form file files Array;
*
* #param width request width
* #param height request height
* #param files files Array
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(final File[] files, int width, int height, int fps,
OnImageLoadListener onPlayFinish) {
if (!isRunning) {
setImageFrame(files, width, height, fps, onPlayFinish);
load(files);
}
}
/**
* load frame form file files Array;
*
* #param files files Array
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(final File[] files, int fps, OnImageLoadListener onPlayFinish) {
loadImage(files, width, height, fps, onPlayFinish);
}
private void setImageFrame(final File[] files, int width, int height, float fps,
OnImageLoadListener onPlayFinish) {
this.width = width;
this.height = height;
if (imageCache == null) {
imageCache = new ImageCache();
}
this.onImageLoadListener = onPlayFinish;
frameTime = 1000f / fps + 0.5f;
workHandler.addMessageProxy(this);
this.files = files;
}
/**
* load frame form file resources Array;
*
* #param resArray resources Array
* #param width request width
* #param height request height
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(Resources resources, #RawRes int[] resArray, int width, int height, int fps,
OnImageLoadListener onPlayFinish) {
loadImage(resources, resArray, width, height, fps, onPlayFinish);
}
private void setImageFrame(Resources resources, #RawRes int[] resArray, int width, int height,
float fps,
OnImageLoadListener onPlayFinish) {
this.width = width;
this.height = height;
this.resources = resources;
if (imageCache == null) {
imageCache = new ImageCache();
}
this.onImageLoadListener = onPlayFinish;
frameTime = 1000f / fps + 0.5f;
workHandler.addMessageProxy(this);
this.resArray = resArray;
}
/**
* load frame form file resources Array;
*
* #param resArray resources Array
* #param fps The number of broadcast images per second
* #param onPlayFinish finish callback
*/
#Deprecated
public void loadImage(Resources resources, #RawRes int[] resArray, int fps,
OnImageLoadListener onPlayFinish) {
if (!isRunning) {
setImageFrame(resources, resArray, width, height, fps, onPlayFinish);
load(resArray);
}
}
/**
* loop play frame
*
* #param loop true is loop
*/
public ImageFrameHandler setLoop(boolean loop) {
if (!isRunning) {
this.loop = loop;
}
return this;
}
/**
* stop play frame
*/
public void stop() {
workHandler.getHandler().removeCallbacksAndMessages(null);
workHandler.removeMessageProxy(this);
handler.removeCallbacksAndMessages(null);
resources = null;
isRunning = false;
if (onImageLoadListener != null) {
onImageLoadListener.onPlayStop();
}
}
public void pause() {
isRunning = false;
workHandler.getHandler().removeCallbacksAndMessages(null);
// workHandler.removeMessageProxy(this);
handler.removeCallbacksAndMessages(null);
}
public void start() {
if (!isRunning) {
isRunning = true;
switch (type) {
case FILE:
load(files);
break;
case RES:
load(resArray);
break;
}
}
}
private void load(final File[] files) {
Log.i(TAG, "load: files");
Message message = Message.obtain();
message.obj = files;
message.what = FILE;
workHandler.getHandler().sendMessage(message);
workHandler.postDelayed(this::start, 10000);
}
private void load(#RawRes int[] res) {
Message message = Message.obtain();
message.obj = res;
message.what = RES;
workHandler.getHandler().sendMessage(message);
}
private void loadInThreadFromFile(final File[] files) {
Log.i(TAG, "loadInThreadFromFile: " + files.length);
Log.i(TAG, "loadInThreadFromFile: " + index);
if (index < files.length) {
File file = files[index];
//Log.i(TAG, "loadInThreadFromFile: " + file != null ? file.getAbsolutePath() : "");
if (file.isFile() && file.exists() && isPicture(file)) {
if (bitmapDrawable != null) {
imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap()));
}
long start = System.currentTimeMillis();
bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromFile(file.getAbsolutePath(), width, height, imageCache, isOpenCache);
long end = System.currentTimeMillis();
long diff = end - start;
//Log.i(TAG, "loadInThreadFromFile: frameTime: " + frameTime + "\tdelayTime: " + delayTime + "\tdiff=" + diff);
//Log.i(TAG, "loadInThreadFromFile: mod:" + ANIMATED_FRAME + "~" + Math.round(ANIMATED_FRAME));
float time = 0;
Log.i(TAG, "loadInThreadFromFile: ANIMATED_FRAME: " + (index % Math.round(ANIMATED_FRAME)));
if (index % Math.round(ANIMATED_FRAME) != 0) {
time = frameTime;
} else {
Log.e(TAG, "Have delay #" + index);
time = delayTime;
}
float updateTime = (time - diff) > 0 ? (time - diff) : 0;
Message message = Message.obtain();
message.what = FILE;
message.obj = files;
handler.sendMessageAtTime(message, (int) (SystemClock.uptimeMillis() + updateTime));
//Log.i(TAG, "loadInThreadFromFile: updateTime:" + updateTime + "\tindex:" + index + "\tlength:" + files.length);
index++;
} else {
index++;
loadInThreadFromFile(files);
}
} else {
if (loop) {
Log.i(TAG, "loadInThreadFromFile: loop: IF");
index = 0;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
loadInThreadFromFile(files);
}
}, (long) delayTime);
} else {
Log.i(TAG, "loadInThreadFromFile: loop=> " + loop);
index++;
bitmapDrawable = null;
frameTime = 0;
if (onImageLoadListener != null) {
onImageLoadListener.onPlayFinish();
}
isRunning = false;
onImageLoadListener = null;
}
}
if (onImageLoadListener != null) {
Log.i(TAG, "loadInThreadFromFile: index: " + index);
onImageLoadListener.onIndexChange(index);
}
}
private void loadInThreadFromRes(final int[] resIds) {
if (index < resIds.length) {
int resId = resIds[index];
if (bitmapDrawable != null) {
imageCache.mReusableBitmaps.add(new SoftReference<>(bitmapDrawable.getBitmap()));
}
long start = System.currentTimeMillis();
bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromRes(resources, resId, width, height, imageCache, isOpenCache);
long end = System.currentTimeMillis();
float updateTime = (frameTime - (end - start)) > 0 ? (frameTime - (end - start)) : 0;
Message message = Message.obtain();
message.what = RES;
message.obj = resIds;
handler.sendMessageAtTime(message, index == 0 ? 0 : (int) (SystemClock.uptimeMillis() + updateTime));
index++;
} else {
if (loop) {
index = 0;
loadInThreadFromRes(resIds);
} else {
index++;
bitmapDrawable = null;
frameTime = 0;
if (onImageLoadListener != null) {
onImageLoadListener.onPlayFinish();
}
isRunning = false;
onImageLoadListener = null;
}
}
}
private boolean isPicture(File file) {
return file.getName().endsWith("png") || file.getName().endsWith("jpg");
}
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RES:
loadInThreadFromRes((int[]) msg.obj);
break;
case FILE:
Log.i("ImageFrameHandler", "msg.obj; " + msg.obj.toString());
loadInThreadFromFile((File[]) msg.obj);
break;
}
}
public void setFps(float fps) {
Log.e(TAG, "setFps: " + fps);
//frameTime = 1000f / fps + 0.5f;
frameTime = 1000f / fps;
}
/**
* #param dps seconds in Sec
*/
public void setDelays(float dps) {
Log.e(TAG, "setDelays: " + dps);
delayTime = dps * 1000.0f;
}
public void setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
this.onImageLoadListener = onPlayFinish;
}
public interface OnImageLoadListener {
void onImageLoad(BitmapDrawable drawable);
void onPlayStop();
void onPlayFinish();
void onIndexChange(int index);
}
public static class FileHandlerBuilder implements FrameBuild {
private int width;
private int height;
private float fps = 30;
private float delays = 2;
private File[] files;
private OnImageLoadListener onPlayFinish;
private ImageFrameHandler imageFrameHandler;
private int startIndex;
private int endIndex;
public FileHandlerBuilder(#NonNull File[] files) {
if (files.length == 0) {
throw new IllegalArgumentException("fileDir is not empty");
}
this.files = files;
createHandler();
}
public FileHandlerBuilder(#NonNull String fileDir) {
Log.i(TAG, "FileHandlerBuilder: fileDir");
if (TextUtils.isEmpty(fileDir)) {
throw new IllegalArgumentException("fileDir is not empty");
}
File dir = new File(fileDir);
if (dir.exists() && dir.isDirectory()) {
files = dir.listFiles();
}
createHandler();
}
#Override
public FrameBuild setLoop(boolean loop) {
imageFrameHandler.setLoop(loop);
return this;
}
#Override
public FrameBuild stop() {
imageFrameHandler.stop();
return this;
}
// Just change the length of the array
#Override
public FrameBuild setStartIndex(int startIndex) {
if (startIndex >= files.length) {
throw new IllegalArgumentException("startIndex is not big to files length");
}
this.startIndex = startIndex;
return this;
}
#Override
public FrameBuild setEndIndex(int endIndex) {
if (endIndex > files.length) {
throw new IllegalArgumentException("endIndex is not big to files length");
}
if (endIndex <= startIndex) {
throw new IllegalArgumentException("endIndex is not to small startIndex");
}
this.endIndex = endIndex;
return this;
}
#Override
public FrameBuild setWidth(int width) {
this.width = width;
return this;
}
#Override
public FrameBuild setHeight(int height) {
this.height = height;
return this;
}
#Override
public FrameBuild setFps(float fps) {
this.fps = fps;
imageFrameHandler.setFps(fps);
return this;
}
#Override
public FrameBuild setDelays(float dps) {
this.delays = dps;
imageFrameHandler.setDelays(dps);
return this;
}
#Override
public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
this.onPlayFinish = onPlayFinish;
return this;
}
#Override
public FrameBuild openLruCache(boolean isOpenCache) {
imageFrameHandler.openLruCache(isOpenCache);
return this;
}
#Override
public ImageFrameHandler build() {
if (!imageFrameHandler.isRunning) {
clip();
imageFrameHandler.setImageFrame(files, width, height, fps, onPlayFinish);
}
return imageFrameHandler;
}
private void createHandler() {
if (imageFrameHandler == null) {
Log.i(TAG, "createHandler: ");
imageFrameHandler = new ImageFrameHandler(FILE);
}
}
#Override
public FrameBuild clip() {
if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) {
files = split(files, startIndex, endIndex);
}
return this;
}
File[] split(File[] resArray, int start, int end) {
File[] ints = new File[end - start];
int index = 0;
for (int i = start; i < end; i++) {
ints[index] = resArray[i];
index++;
}
return ints;
}
}
private void openLruCache(boolean isOpenCache) {
this.isOpenCache = isOpenCache;
}
/**
* Transform into build builder mode
* <p>
* Two kinds are file
* Resource
*/
public static class ResourceHandlerBuilder implements FrameBuild {
#NonNull
private final Resources resources;
private int width;
private int height;
private float fps = 30;
private int[] resArray;
private OnImageLoadListener onPlayFinish;
private ImageFrameHandler imageFrameHandler;
private int startIndex;
private int endIndex;
public ResourceHandlerBuilder(#NonNull Resources resources, #NonNull #RawRes int[] resArray) {
if (resArray.length == 0) {
throw new IllegalArgumentException("resArray is not empty");
}
this.resources = resources;
this.resArray = resArray;
createHandler();
}
#Override
public FrameBuild setLoop(boolean loop) {
imageFrameHandler.setLoop(loop);
return this;
}
#Override
public FrameBuild stop() {
imageFrameHandler.stop();
return this;
}
#Override
public FrameBuild setStartIndex(int startIndex) {
if (startIndex >= resArray.length) {
throw new IllegalArgumentException("startIndex is not to big resArray length");
}
this.startIndex = startIndex;
return this;
}
#Override
public FrameBuild setEndIndex(int endIndex) {
if (endIndex > resArray.length) {
throw new IllegalArgumentException("endIndex is not big to resArray length");
}
if (endIndex <= startIndex) {
throw new IllegalArgumentException("endIndex is not to small startIndex");
}
this.endIndex = endIndex;
return this;
}
#Override
public FrameBuild clip() {
if (startIndex >= 0 && endIndex > 0 && startIndex < endIndex) {
resArray = split(resArray, startIndex, endIndex);
}
return this;
}
#Override
public FrameBuild setWidth(int width) {
this.width = width;
return this;
}
#Override
public FrameBuild setHeight(int height) {
this.height = height;
return this;
}
#Override
public FrameBuild setFps(float fps) {
this.fps = fps;
imageFrameHandler.setFps(fps);// There is a double calculation here. I want a better way to support dynamic change later.
return this;
}
#Override
public FrameBuild setDelays(float dps) {
return null;
}
#Override
public FrameBuild openLruCache(boolean isOpenCache) {
imageFrameHandler.openLruCache(isOpenCache);
return this;
}
#Override
public FrameBuild setOnImageLoaderListener(OnImageLoadListener onPlayFinish) {
this.onPlayFinish = onPlayFinish;
return this;
}
#Override
public ImageFrameHandler build() {
if (!imageFrameHandler.isRunning) {
clip();
imageFrameHandler.setImageFrame(resources, resArray, width, height, fps,
onPlayFinish);
}
return imageFrameHandler;
}
private void createHandler() {
if (imageFrameHandler == null) {
imageFrameHandler = new ImageFrameHandler(RES);
}
}
int[] split(int[] resArray, int start, int end) {
int[] ints = new int[end - start];
int index = 0;
for (int i = start; i < end; i++) {
ints[index] = resArray[i];
index++;
}
return ints;
}
}
}
I have used both as below in Activity:
Exoplayer init:
private void prepareExoPlayerFromURL() {
Log.i(TAG, "prepareExoPlayerFromURL: musicFilePath: " + musicFilePath);
try {
if (!FileUtils.createValidFile(musicFilePath).exists()) {
Log.i(TAG, "[prepareExoPlayerFromURL] is not Valid File URL");
Snackbar.make(toolbar, R.string.err_failed_to_pick_audio, Snackbar.LENGTH_LONG).show();
onAudioRemove();
return;
}
if (exoPlayer != null) {
MediaSource mediaSource = audioSource.createMediaSource(Uri.fromFile(FileUtils.createValidFile(musicFilePath)));
ClippingMediaSource clippingMediaSource = new ClippingMediaSource(mediaSource, 0, (long) totalDurationInSec * 1000 * 1000);
exoPlayer.prepare(clippingMediaSource);
btnMute.setVisibility(View.VISIBLE);
if (exoPlayer.getVolume() > 0) {
btnMute.setImageResource(R.drawable.ic_unmute);
}
/* TODO Write Permission */
joinAudio();
}
} catch (Throwable e) {
e.printStackTrace();
}
//initMediaControls();
}
**Play Music **
private void playMusic() {
Log.i(TAG, "playMusic: isForeGround: " + isForeGround);
if (isForeGround && this.layLoad.getVisibility() != View.VISIBLE && this.errorView.getVisibility() != View.VISIBLE &&
this.exoPlayer != null && !this.exoPlayer.isLoading()) {
Log.i(TAG, "playMusic: TRUE");
exoPlayer.seekTo(0);
exoPlayer.setPlayWhenReady(true);
} else {
Log.i(TAG, "playMusic: exoPlayer is null");
}
}
ResetMusic When One time ImageHandler is completed:
private void resetMusic() {
Log.i(TAG, "resetMusic: " + musicFilePath);
if (isForeGround && this.layLoad.getVisibility() != View.VISIBLE && this.errorView.getVisibility() != View.VISIBLE &&
this.exoPlayer != null) {
Log.i(TAG, "resetMusic: getApplicationLooper: "+exoPlayer.getApplicationLooper().getThread().getName());
Log.i(TAG, "resetMusic: getPlaybackLooper: "+exoPlayer.getPlaybackLooper().getThread().getName());
Log.i(TAG, "resetMusic: TRUE");
exoPlayer.seekTo(0);
exoPlayer.setPlayWhenReady(true);
} else {
Log.i(TAG, "resetMusic: exoPlayer is null");
}
}
Image handler used in Acvitiy in onCreate() method
imageFrameHandler = new ImageFrameHandler.FileHandlerBuilder(SlideShowUtility.getTempDirPath(this))
// .setFps((slideShowUtility.getVideoImages().size() - selectedImages.size()) * 1.0f / (selectedImages.size() - 1) * 1.0f)
.setFps(frameRate)
.setDelays(seconds)
.setWidth((int) (mWidth * mulX))
.setHeight((int) (mHeight * mulY))
.setLoop(true)
.build();
->Warning has Arrived in ResetMusic method when Exo player reset at position 0.

Update JProgressbar in JTable if JCheckbox is checked

I have problem with updating progressbar. If I check checkbox, file is automaticaly copied but progress is still 0. I use SwingWokrer, but I don't know how I can progressbar updating.
I tried many combinations, but it does not work.
This code is responsible for downloading the file from the selected row.
jTable.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
TableModel tableModel = (TableModel) e.getSource();
Boolean dataObject = (Boolean) tableModel.getValueAt(row,column);
String fileNameToCopy = (String) tableModel.getValueAt(row, 0);
Long fileSize = (Long) tableModel.getValueAt(row, 1);
Float progress = (Float) tableModel.getValueAt(row, 3);
if (dataObject == true) {
customTableData.setFile(new File(fileNameToCopy));
customTableData.setFileSize(fileSize);
customTableData.setProgress(progress);;
copyFiles = new CopyFiles(customTableData);
}
}
});
CustomTableData.java
public class CustomTableData {
private File file;
private long fileSize;
private Boolean edit = false;
private float progress;
public CustomTableData() {}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public long getFileSize() {
return fileSize;
}
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
public Boolean isEdit() {
return edit;
}
public void setEdit(Boolean edit) {
this.edit = edit;
}
public float getProgress() {
return progress;
}
public void setProgress(float progress) {
this.progress = progress;
}
}
My CopyFiles.java class
private String fileName;
private long fileSize;
private float progress;
private CustomTableData data;
public CopyFiles(CustomTableData data) {
this.data = new CustomTableData();
this.fileName = data.getFile().getName();
this.fileSize = data.getFileSize();
this.progress = data.getProgress();
worker.execute();
}
SwingWorker<Void, Float> worker = new SwingWorker<Void, Float>(){
#Override
protected Void doInBackground() throws Exception {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(source + fileName);
os = new FileOutputStream(destination + fileName);
byte[] buffer = new byte[BUFFER];
int length = 0;
float pro = 0;
while((length = is.read(buffer)) != -1) {
publish(pro += length);
os.write(buffer, 0, length);
}
} catch (Exception e) {
e.getMessage();
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
e.getMessage();
}
}
return null;
}
protected void process(java.util.List<Float> chunks) {
for (Float f : chunks) {
progress = (f*100) / fileSize;
System.out.println("Percentage progress: " + progress + " >>> file size: " + f);
}
};
protected void done() {
System.out.println("FILE: " + fileName + " SIZE: " + fileSize);
};
};
}
And my CustomTableModel.java class
public class CustomTableModel extends AbstractTableModel {
private static final long serialVersionUID = -2929662905556163705L;
#SuppressWarnings("unused")
private File dir;
private File[] fileArray;
private List<CustomTableData> filesList;
private CustomTableData fileRow;
public CustomTableModel(File dir) {
this.dir = dir;
this.filesList = new ArrayList<CustomTableData>();
this.fileArray = dir.listFiles();
fileLoop();
}
private void fileLoop() {
for (int i = 0; i < fileArray.length; i++) {
this.fileRow = new CustomTableData();
if (fileArray[i].isFile()) {
fileRow.setFile(fileArray[i]);
fileRow.isEdit();
fileRow.getProgress();
filesList.add(fileRow);
}
}
}
private ResourceBundle resourceBundle = ResourceBundle.getBundle("MessageBundle", Locale.forLanguageTag("pl"));
protected String[] columns = new String[] {
resourceBundle.getString("fileName"),
resourceBundle.getString("fileSize") + " [byte]",
resourceBundle.getString("getFile"),
resourceBundle.getString("progress")};
#SuppressWarnings("rawtypes")
protected Class[] columnClasses = {String.class , Long.class, JCheckBox.class, JProgressBar.class};
public int getColumnCount() {
return columns.length;
}
public int getRowCount() {
return filesList.size();
}
public String getColumnName(int col) {
return columns[col].toString();
}
public Class<?> getColumnClass(int c) {
switch (c) {
case 0:
return String.class;
case 1:
return Long.class;
case 2:
return Boolean.class;
case 3:
return Float.class;
default:
return null;
}
}
public Object getValueAt(int row, int col) {
fileRow = filesList.get(row);
switch (col) {
case 0:
return fileRow.getFile().getName();
case 1:
return fileRow.getFile().length();
case 2:
return fileRow.isEdit();
case 3:
return fileRow.getProgress();
default:
return null;
}
}
public boolean isCellEditable(int row, int col) {
switch (col) {
case 0:
return false;
case 1:
return false;
case 2:
return true;
case 3:
return false;
default:
return false;
}
}
public void setValueAt(Object aValue, int row, int column) {
fileRow = filesList.get(row);
if (column == 2) {
fileRow.setEdit((Boolean)aValue);
fireTableCellUpdated(row, column);
}
}
}
This is my ProgressBarRenderer.java class
public class ProgressBarRenderer extends JProgressBar implements TableCellRenderer {
private static final long serialVersionUID = 551156559687881082L;
public ProgressBarRenderer() {
super();
}
public ProgressBarRenderer(int min, int max) {
super(min, max);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setValue((int) ((Float) value).floatValue());
return this;
}
}
My table view
Rozwiązanie
Progressbar jest prawidłowo aktualizowany w metodzie process()
public class CopyFiles {
private static final int BUFFER = 1024;
private int row;
private CustomTableModel customTableModel;
private String fileName;
private File file;
public CopyFiles(String fileName, CustomTableModel customTableModel, int row) {
this.fileName = fileName;
this.file = new File(PathEnum.SOURCE.getPath() + fileName);
this.customTableModel = customTableModel;
this.row = row;
worker.execute();
}
public String getFile() {
return file.getName();
}
public long getFileSize() {
return file.length();
}
public SwingWorker<Void, Float> getWorker() {
return worker;
}
SwingWorker<Void, Float> worker = new SwingWorker<Void, Float>() {
#Override
protected Void doInBackground() throws Exception {
InputStream is = null;
OutputStream os = null;
float progress = 0;
try {
is = new FileInputStream(PathEnum.SOURCE.getPath() + getFile());
os = new FileOutputStream(PathEnum.DESTINATION.getPath() + getFile());
byte[] buffer = new byte[BUFFER];
long count = 0;
int bufferLength;
while ((bufferLength = is.read(buffer)) != -1) {
count += bufferLength;
os.write(buffer, 0, bufferLength);
progress = (int) ((count * 100) / getFileSize());
publish(progress);
}
} catch (Exception e) {
e.getMessage();
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
e.getMessage();
}
}
return null;
}
protected void process(List<Float> chunks) {
float currentProgress = chunks.get(chunks.size()-1);
customTableModel.setValueAt(currentProgress, row, 3);
};
protected void done() {
System.out.println("FILE: " + getFile() + " SIZE: " + getFileSize());
};
};

ImageViewer image loop from json codenameone

I have edited the question as your suggestions but null pointer exception is caught.I used connectionRequest instead of multipartRequest since i dont need to upload(just need to read the value frm json). All my codes below, please have a look.
Edited: exception
java.lang.NullPointerException
at userclasses.StateMachine$16.readResponse(StateMachine.java:1834)
at com.codename1.io.ConnectionRequest.performOperation(ConnectionRequest.java:438)
at com.codename1.io.NetworkManager$NetworkThread.run(NetworkManager.java:263)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
Code:
#Override
protected void beforeImgGallery(Form f) {
int iter = 0;
GridLayout gr = new GridLayout(1, 1);
Container grid = new Container(gr);
gr.setAutoFit(true);
grid.setScrollableY(true);
grid.addComponent(new InfiniteProgress());
f.addComponent(BorderLayout.CENTER, grid);
f.removeAllCommands();
f.setBackCommand(null);
createPictureCommand(grid);
}
private static boolean animating;
private Vector<Map<String, Object>> responsesgallery;
String galleryPhotoUrl;
private void createPictureCommand(final Container grid) {
ConnectionRequest mp = new ConnectionRequest(){
#Override
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
results = p.parse(new InputStreamReader(input));
responsesgallery = (Vector<Map<String, Object>>) results.get("data");
//i've kept this for loop in postResponse but same error
for (int i = 0; i < responsesgallery.size(); i++) {
//null pointer exception in this line
final Button btn = createImageButton(i, grid, imageList.getSize());
//if i simply create a btn like below, it works
// final Button btn = new Button((URLImage.createToStorage(placeholder, token, galleryPhotoUrl, URLImage.RESIZE_SCALE_TO_FILL)));
imageList.addImageId(i);
grid.addComponent(i, btn);
Hashtable hm = (Hashtable) responsesgallery.get(i);
String galleryImgId = (String) hm.get("news_id");
galleryPhotoUrl = (String) hm.get("photo");
}
}
};
mp.setUrl("http://capitaleyedevelopment.com/~admin/traffic/api/news/getLatestNews");
NetworkManager.getInstance().addToQueueAndWait(mp);
}
ImageList imageList;
Button createImageButton(final int imageId, final Container grid, final int offset) {
final Button btn = new Button(URLImage.createToStorage(placeholder, token, galleryPhotoUrl, URLImage.RESIZE_SCALE_TO_FILL));
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
imageList.setSelectedIndex(offset);
final Container viewerParent = new Container(new LayeredLayout());
ImageViewer viewer = new ImageViewer(imageList.getItemAt(offset));
viewerParent.addComponent(viewer);
Container parent = new Container(new BorderLayout());
viewerParent.addComponent(parent);
viewer.setImageList(imageList);
grid.getParent().replace(grid, viewerParent, CommonTransitions.createSlide(CommonTransitions.SLIDE_HORIZONTAL, false, 300));
Display.getInstance().getCurrent().setBackCommand(createBackCommand(viewerParent, grid));
}
});
return btn;
}
public static final String SERVER_URL = "http://capitaleyedevelopment.com/~admin/traffic/api/news/getLatestNews";
class ImageList implements ListModel<Image> {
private int selection;
private long[] imageIds;
private EncodedImage[] images;
private EventDispatcher listeners = new EventDispatcher();
public void addImageId(int id) {
long[] n = new long[imageIds.length + 1];
EncodedImage[] nImages = new EncodedImage[n.length];
System.arraycopy(imageIds, 0, n, 0, imageIds.length);
System.arraycopy(images, 0, nImages, 0, images.length);
n[imageIds.length] = id;
imageIds = n;
images = nImages;
listeners.fireDataChangeEvent(-1, DataChangedListener.ADDED);
}
public long getSelectedImageId() {
return imageIds[selection];
}
public ImageList(long[] images) {
this.imageIds = images;
this.images = new EncodedImage[images.length];
}
public Image getItemAt(final int index) {
if (images[index] == null) {
images[index] = placeholder;
Util.downloadUrlToStorageInBackground(IMAGE_URL_PREFIX + imageIds[index], "FullImage_" + imageIds[index], new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
images[index] = EncodedImage.create(Storage.getInstance().createInputStream("FullImage_" + imageIds[index]));
listeners.fireDataChangeEvent(index, DataChangedListener.CHANGED);
} catch (IOException err) {
err.printStackTrace();
}
}
});
}
return images[index];
}
public int getSize() {
return imageIds.length;
}
public int getSelectedIndex() {
return selection;
}
public void setSelectedIndex(int index) {
WebServiceProxy.getPhotoLikesAsync(imageIds[selection], new Callback<Integer>() {
public void onSucess(Integer value) {
}
public void onError(Object sender, Throwable err, int errorCode, String errorMessage) {
}
});
selection = index;
}
public void addDataChangedListener(DataChangedListener l) {
listeners.addListener(l);
}
public void removeDataChangedListener(DataChangedListener l) {
listeners.removeListener(l);
}
public void addSelectionListener(SelectionListener l) {
}
public void removeSelectionListener(SelectionListener l) {
}
public void addItem(Image item) {
}
public void removeItem(int index) {
}
}
In the Photo Share demo (that's on github) I demonstrate something pretty similar. I used a custom list model that fetches the images to the ImageViewer dynamically.
The interesting bit is this list model where the images are downloaded dynamically as needed:
class ImageList implements ListModel<Image> {
private int selection;
private long[] imageIds;
private EncodedImage[] images;
private EventDispatcher listeners = new EventDispatcher();
public void addImageId(long id) {
long[] n = new long[imageIds.length + 1];
EncodedImage[] nImages = new EncodedImage[n.length];
System.arraycopy(imageIds, 0, n, 0, imageIds.length);
System.arraycopy(images, 0, nImages, 0, images.length);
n[imageIds.length] = id;
imageIds = n;
images = nImages;
listeners.fireDataChangeEvent(-1, DataChangedListener.ADDED);
}
public long getSelectedImageId() {
return imageIds[selection];
}
public ImageList(long[] images) {
this.imageIds = images;
this.images = new EncodedImage[images.length];
}
public Image getItemAt(final int index) {
if(images[index] == null) {
images[index] = placeholder;
Util.downloadUrlToStorageInBackground(IMAGE_URL_PREFIX + imageIds[index], "FullImage_" + imageIds[index], new ActionListener() {
public void actionPerformed(ActionEvent evt) {
try {
images[index] = EncodedImage.create(Storage.getInstance().createInputStream("FullImage_" + imageIds[index]));
listeners.fireDataChangeEvent(index, DataChangedListener.CHANGED);
} catch(IOException err) {
err.printStackTrace();
}
}
});
}
return images[index];
}
public int getSize() {
return imageIds.length;
}
public int getSelectedIndex() {
return selection;
}
public void setSelectedIndex(int index) {
WebServiceProxy.getPhotoLikesAsync(imageIds[selection], new Callback<Integer>() {
public void onSucess(Integer value) {
if(likeCount != null) {
likeCount.setText("" + value);
likeCount.getParent().revalidate();
}
}
public void onError(Object sender, Throwable err, int errorCode, String errorMessage) {
}
});
selection = index;
}
public void addDataChangedListener(DataChangedListener l) {
listeners.addListener(l);
}
public void removeDataChangedListener(DataChangedListener l) {
listeners.removeListener(l);
}
public void addSelectionListener(SelectionListener l) {
}
public void removeSelectionListener(SelectionListener l) {
}
public void addItem(Image item) {
}
public void removeItem(int index) {
}
}

Minesweeper Action Events

Is there a way to make certain event actions specific to left and right mouse clicks?
I'm creating a minesweeper gui, so when a square is left-clicked it will be uncovered, & when it's right-clicked it will be flagged.
I wasn't sure how to syntactically check for this & couldn't find it on the tut.
Thanks for the help!
I decided to give it a go, to try to create a simple Mine Sweeper application, one without a timer or reset (yet), but that is functional and uses both a GUI cell class and a non-GUI model class (it can't be copied and used in for intro to Java homework).
Edit 1: now has reset capability:
MineSweeper.java: holds the main method and starts the JFrame
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel(){{add(resetButton);}});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
//frame.getContentPane().add(new MineSweeper(20, 20, 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
MineCellGrid.java: the class that displays the grid of mine cells and times them all together.
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<MineCell>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
MineCellGridModel.java: the non-GUI model for the MineCellGrid
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JOptionPane;
public class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r
* cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements
PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations", JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
MineCell.java: the class that I started on. Uses the model class as its non-GUI nucleus.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
/**
* http://stackoverflow.com/questions/7006029/minesweeper-action-events
*
* #author Pete
*/
#SuppressWarnings("serial")
public class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? "" : String
.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
MineCellModel.java: the non-GUI model for the mine cell
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED,
-1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE,
oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Here's the whole program combined into a single MCVE file, MineSweeper.java:
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel() {
{
add(resetButton);
}
});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
// frame.getContentPane().add(new MineSweeper(20, 20,
// 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r * cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations",
JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
#SuppressWarnings("serial")
class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? ""
: String.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE, oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
If you are using swing then
Is there a way to make certain event actions specific to left and
right mouse clicks?
Implement a MouseListener no component. Then in implemented method you have a MouseEvent object which has a getButton() method which tells you which mouse is pressed.
Edit
OP has asked following question but now removed it.
Is this gui nested inside the other in an action event, when
game_lost becomes true?
You can open a JDialog for this.
You may be interested in the MouseEvent Class of java.awt.event. here

Categories