Undesirable repaint of a JPanel when dynamically updated - java

I have a window that dynamically updates the buffered image set on a JPanel using javax.swing.Timer
Everything works as expected but every time I invoke the dynamic update there seems to be another buffered image displayed below the currently updating one.
The image of the window before and after clicking the train button (which triggers the dynamic update) is given below.
Since the image below the dynamically updating image looks like the initial screen. I rechecked the following
Whether I'm adding two dynamic lattice objects to the same panel
Multiple calls of repaint()
Unwanted initialization of the dynamic lattice
I could not find any of these in my code. I cannot post the code since it is huge and whenever I'm creating a minimal set to reproduce the same behavior it is not there. So I'm sure I'm missing something or doing something on my project code which triggers this behavior. Any suggestions on how to debug this or why it is doing something like this?
Thank you
EDIT
SSCCE is give below. If executing, click the load button followed by the train button to get the error.
(MapScreen.java - Main Class)
package test;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import test.DisplayLattice;
import test.SelfOrganizingMap;
public class MapScreen extends JFrame {
private double NUM_ITERATIONS = 0.0;
private double ETA = 0.0;
private double SPREAD_FACTOR = 0.0;
private double RADIUS = 0.0;
private int WIDTH = 0;
private int HEIGHT = 0;
private SelfOrganizingMap SOM = null;
private Timer REFRESH_TIMER = null;
private JPanel pnlMap;
private JButton btnLoadParameters;
private JButton btnTrain;
private DisplayLattice displayScreen;
public MapScreen(double iterations, double learningRate, double spreadFactor, double radius, int option, int width, int height, int mapOption) {
NUM_ITERATIONS = iterations;
ETA = learningRate;
SPREAD_FACTOR = spreadFactor;
RADIUS = radius;
WIDTH = width;
HEIGHT = height;
setType(Type.UTILITY);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Map");
setSize(650, 800);
setLocation(150,150);
getContentPane().setLayout(null);
displayScreen = new DisplayLattice();
pnlMap = displayScreen;
pnlMap.setBounds(6, 130, 600, 600);
getContentPane().add(pnlMap);
btnLoadParameters = new JButton("Load Parameters");
btnLoadParameters.setFont(new Font("Tahoma", Font.PLAIN, 11));
btnLoadParameters.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
SOM = new SelfOrganizingMap(10000,0,0,13,displayScreen);
}
});
btnLoadParameters.setBounds(192, 46, 126, 23);
getContentPane().add(btnLoadParameters);
btnTrain = new JButton("Train");
btnTrain.setFont(new Font("Tahoma", Font.PLAIN, 11));
btnTrain.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
initialObjectSetUp();
}
});
btnTrain.setBounds(192, 72, 62, 23);
getContentPane().add(btnTrain);
}
private void initialObjectSetUp()
{
SOM.initTrainSOM(null, 100, 0.25);
REFRESH_TIMER = new Timer(100, SOM);
REFRESH_TIMER.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
MapScreen frame = new MapScreen(100,0.25,0.0,0.0,1,100,0,0);
frame.setVisible(true);
}
});
}
}
(SelfOrganizingMap.java)
package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SelfOrganizingMap implements ActionListener {
private Node[][] SOM = null;
private double[][] NORM_MAP = null; //holds the L2 norm of each vector in the SOM[][].
#SuppressWarnings("unused")
private int GRID_OPTION = 0;
private int INPUT_DIMENSION = 0;
private int NUMER_OF_ITERATIONS = 0;
private int CURRENT_ITERATION=0;
private int SOM_HORIZONTAL_LENGTH = 0;
private int SOM_VERTICAL_LENGTH = 0;
private double INITIAL_LEARNING_RATE = 0.0;
private double LEARNING_RATE = 0.0;
private double MAX_RADIUS = 0.0; //radius at first epoch (t = 0)
private double RADIUS = 0.0;
private double TIME_STEP = 0.0; //lambda of X(t) = t0 * exp(-t/lambda)
private String INPUT_SAMPLES = null;
private DisplayLattice DISPLAY_SCREEN = null;
public SelfOrganizingMap(int numberOfNodes, int depth, int grid, int inputDimensison, DisplayLattice screen)
{
INPUT_DIMENSION = inputDimensison;
if(grid == 0)
{
int side = (int)Math.sqrt(numberOfNodes);
SOM = new Node[side][side];
NORM_MAP = new double[side][side];
GRID_OPTION = grid;
MAX_RADIUS = side/2;
DISPLAY_SCREEN = screen;
}
RADIUS = MAX_RADIUS;
}
public void initTrainSOM(String input, int iterations, double learningRate)
{
NUMER_OF_ITERATIONS = iterations;
INITIAL_LEARNING_RATE = learningRate;
LEARNING_RATE = INITIAL_LEARNING_RATE;
TIME_STEP = NUMER_OF_ITERATIONS/Math.log(MAX_RADIUS);
INPUT_SAMPLES = input;
}
private void singleCompleteRun()
{
DISPLAY_SCREEN.render();
System.out.println(CURRENT_ITERATION);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(CURRENT_ITERATION <= NUMER_OF_ITERATIONS)
{
singleCompleteRun();
CURRENT_ITERATION++;
}
}
}
(DisplayLattice.java)
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DisplayLattice extends JPanel {
private BufferedImage img = new BufferedImage(500, 500, 1);
public void paintComponent(Graphics g) {
if (img == null)
super.paintComponents(g);
else
g.drawImage(img, 0, 0, this);
}
public void render() {
float cellWidth = 100;
float cellHeight = 100;
int imgW = img.getWidth();
int imgH = img.getHeight();
float r, g, b;
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.black);
g2.clearRect(0,0,imgW,imgH);
for (int x=0; x<100; x++) {
for (int y=0; y<100; y++) {
r = (float)Math.random();
g = (float)Math.random();
b = (float)Math.random();
g2.setColor(new Color(r,g,b));
g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
(int)cellWidth+1, (int)cellHeight+1);
}
}
g2.setColor(Color.black);
g2.dispose();
repaint();
}
public BufferedImage getImage() {
if (img == null)
img = (BufferedImage)createImage(500, 500);
return img;
}
public void setImage(BufferedImage bimg) {
img = bimg;
}
}
(Node.java - Structure class for the SOM)
package test;
public class Node {
private int DIMENSION = 0;
private int POSITION_X = 0;
private int POSITION_Y = 0;
private double ACTIVATION_VALUE = 0.0;
public Node(int Dimensions, int x, int y)
{
DIMENSION = Dimensions;
setWeightVector();
POSITION_X = x;
POSITION_Y = y;
}
public int getX() {
return POSITION_X;
}
public int getY() {
return POSITION_Y;
}
public double getACTIVATION_VALUE() {
return ACTIVATION_VALUE;
}
public void setPOSITION_X(int x) {
POSITION_X = x;
}
public void setPOSITION_Y(int y) {
POSITION_Y = y;
}
public void setACTIVATION_VALUE(double y) {
ACTIVATION_VALUE= y;
}
private void setWeightVector()
{
double temp[] = new double[DIMENSION];
for(int i = 0; i<temp.length ; i++)
{
temp[i] = Math.random();
}
}
}

The problem is your DiaplyLattice class.
You overrode paintComponent but you invoke super.paintComponents(g). Notice the extra s you have at the end of paintComponents! This of course is unwanted and should be super.paintComponent(g);
I would have you method as follow:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
Now, just as a good advice/tip to give, don't use null layout and rather use LayoutManager's and possibly use several level of nesting. It's always easier.
Also, you missed an important thing in SSCCE: the SHORT part. Meaning that you should remove anything unnecessary and have a single file to copy/paste.

Related

I can't get paintComponent() on JButton to work properly

I'm having a problem with the paintComponent() method of my JButton. I want to program my own Minesweeper game and when I try to repaint my Tiles(which extend JButton) they don't seem to update. Here is my Tile class:
package mineSweeper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Tile extends JButton{
/**
*
*/
private static final long serialVersionUID = 5476927382697663397L;
public static final int UNPRESSED = 0;
public static final int PRESSED = 1;
public static final int FLAG = 2;
public static final int BOMB = 3;
public static final int XBOMB = 4;
public static final int HEIGHT = 16;
public static final int WIDTH = 16;
private int paintMode = UNPRESSED;
public Tile(int x, int y){
super();
setBounds(x*WIDTH, y*HEIGHT, WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setMargin(new Insets(0, 0, 0, 0));
setBorder(BorderFactory.createEmptyBorder());
addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
setEnabled(false);
setPaintMode(PRESSED);
repaint();
}
});
}
public void reset(){
setEnabled(true);
setPaintMode(UNPRESSED);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if (getPaintMode()==UNPRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.setColor(Color.WHITE);
g.drawLine(0, 0, WIDTH-1, 0);
g.drawLine(0, 1, WIDTH-2, 1);
g.drawLine(0, 0, 0, HEIGHT-1);
g.drawLine(1, 0, 1, HEIGHT-2);
g.setColor(Color.GRAY);
g.drawLine(WIDTH, HEIGHT, 1, HEIGHT);
g.drawLine(WIDTH, HEIGHT-1, 2, HEIGHT-1);
g.drawLine(WIDTH, HEIGHT, WIDTH, 1);
g.drawLine(WIDTH-1, HEIGHT, WIDTH-1, 2);
}
if (getPaintMode()==PRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.drawLine(0, 0, WIDTH, 0);
g.drawLine(0, 0, 0, HEIGHT);
}
g.dispose();
}
public int getPaintMode() {
return paintMode;
}
public void setPaintMode(int mode) {
mode = paintMode;
}
}
and the class Board
package mineSweeper;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Board extends JFrame{
/**
*
*/
private static final long serialVersionUID = 2769769568511334271L;
public static Tile[][] tile;
public JPanel panel = new JPanel(null);
public JButton resetButton = new ResetButton("Click here to Reset");
String input;
private static int screenWidth = 400;
private static int screenHeight = 400;
private static final int MAXROWS = 60;
private static final int MAXCOLUMS = 60;
private static final int MINROWS = 2;
private static final int MINCOLUMS = 6;
private static final int RESETBUTTONSIZE = 40;
public Board(){
super("MineSweeper");
askForInputs();
resetButton.setBounds(0, screenHeight, screenWidth, RESETBUTTONSIZE);
tile = new Tile[getColums()][getRows()];
pack();
setSize(screenWidth + getInsets().left + getInsets().right, screenHeight + getInsets().top + getInsets().bottom + RESETBUTTONSIZE);
getContentPane().add(panel);
panel.add(resetButton);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y] = new Tile(x,y);
panel.add(tile[x][y]);
}
}
setVisible(true);
}
private void askForInputs() {
try{
input = JOptionPane.showInputDialog(null, "Enter number of rows ( Maximum " + MAXROWS + " / Minimum " + MINROWS +")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINROWS)){
if (Integer.parseInt(input) > MAXROWS)
screenHeight = MAXROWS * Tile.HEIGHT;
}
else input = String.valueOf(MAXROWS/4);
screenHeight = Integer.parseInt(input) * Tile.HEIGHT;
try{
input = JOptionPane.showInputDialog(null, "Enter number of colums ( Maximum " + MAXCOLUMS + " / Minimum " + MINCOLUMS + ")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINCOLUMS))
{
if (Integer.parseInt(input) > MAXCOLUMS)
screenWidth = MAXCOLUMS * Tile.WIDTH;
}
else input = String.valueOf(MAXCOLUMS/4);
screenWidth = Integer.parseInt(input) * Tile.WIDTH;
}
public static void reset(){
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y].reset();
}
}
}
public static int getScreenWidth() {
return screenWidth;
}
public static void setScreenWidth(int screenWidth) {
Board.screenWidth = screenWidth;
}
public static int getScreenHeight() {
return screenHeight;
}
public static void setScreenHeight(int screenHeight) {
Board.screenHeight = screenHeight;
}
public static int getColums(){
return getScreenWidth() / Tile.WIDTH;
}
public static int getRows(){
return getScreenHeight() / Tile.HEIGHT;
}
public static void main (String args[]){
new Board();
}
}
Don't mind the unused imports.
So my problem is: when I click a Tile I see I clicked it and I can't click it again but it looks the same like before.
What am I doing wrong please help.
There's a number of things pop out at me, but you're main problem is this...
public class Tile extends JButton {
//...
public void setPaintMode(int mode) {
mode = paintMode;
}
}
You never actually assign the current mode to the paintMode variable, the assignment is backwards.
I'd recommend using JFrame#setExtendedState to set the frame MAXIMIZED_BOTH state over the setSize hack you're currently using, it'll at least reduce the amount of code.
I'd also recommend using a GridLayout or GridBagLayout of a null layout any day.
Have you considered using a JToggleButton, it's basically what you're doing now?

Adding ViewPort to JPanel

I would like to achieve the following for my swing project,
I was able to get this by extending a JPanel and and using JLayer.
I event tried using AlphaComposite but it didn't work.
Edit1: I think JTable or JViewport might help me to get what I want but I don't know how to use them.
Edit2: Updated the SSCCE, thank you trashgod for the suggestion.
I have made use of the Scalr library because after using getScaledInstance method of Image class, if i tried to use the getSubImage method of BufferedImage,the following exception is thrown:
java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be
cast to java.awt.image.BufferedImage
since the Image generated by getScaledInstance method is a instance of ToolkitImage so, it cannot be cast into a BufferedImage.
If you don't want to use the Scalr library,you can use the code suggested in this post to scale the BufferedImage and than use getSubImage method.
SCSE.java
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import org.imgscalr.Scalr;
public class SCSE {
private JFrame mainFrame;
private JPanel mainPanel;
private GridView gridView;
private JButton imgBtn, shuffleBtn;
private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
private boolean isGridEmpty = false;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SCSE sc = new SCSE();
sc.createGUI();
});
}
private void createGUI() {
mainFrame = new JFrame();
mainFrame.setSize(500, 500);
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainPanel = new JPanel(new BorderLayout());
gridView = new GridView();
imgBtn = new JButton("Get-Image");
shuffleBtn = new JButton("Shuffle-ViewPort");
imgBtn.addActionListener((ActionEvent evt) -> {
try {
gridView.setImage(ImageIO.read(new URL("http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg")));
} catch (IOException ex) {
System.out.println(ex);
}
});
shuffleBtn.addActionListener((ActionEvent evt) -> {
gridView.startShuffle();
});
mainPanel.add(gridView.getComponent(), BorderLayout.CENTER);
mainPanel.add(imgBtn, BorderLayout.NORTH);
mainPanel.add(shuffleBtn, BorderLayout.SOUTH);
mainFrame.add(mainPanel);
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
class GridView {
private Random shuffleRandom;
private RegisterUI layerUi = null;
private JLayer<JPanel> gridLayer = null;
private ImagePanel mainPanel = null;
private int gridNos = 21; //number of grids
int digit[];
private int viewportDimensions = 4; //no of rows and columns in viewport
private JLabel gridLabel[][] = new JLabel[gridNos][gridNos];
private int gridX = -1, gridY = -1, gridWidth = -1, gridHeight = -1;
private boolean isGridInitialized = false;
public GridView() {
initPersuasive();
initPanel();
initGrids();
}
private void initPanel() {
mainPanel = new ImagePanel();
mainPanel.setLayout(new GridLayout(gridNos, gridNos, 0, 0)); //creates layout to place labels in grid form
layerUi = new RegisterUI();
gridLayer = new JLayer<>(mainPanel, layerUi);
}
private void initGrids() {
for (int i = 0; i < gridNos; i++) {
for (int j = 0; j < gridNos; j++) {
gridLabel[i][j] = new JLabel();
gridLabel[i][j].setOpaque(false);
gridLabel[i][j].setName("" + (i + 1)); // Since for loop index is 0 to 80, we add 1 to the name to make it 1 to 81
mainPanel.add(gridLabel[i][j]); //add it to mainPanel
}
}
}
private void initPersuasive() {
shuffleRandom = new Random();
digit = new int[2];
}
private void random() {
digit[0] = shuffleRandom.nextInt(gridNos - viewportDimensions);
digit[1] = shuffleRandom.nextInt(gridNos - viewportDimensions);
}
public void startShuffle() {
random();
int x = gridLabel[digit[0]][digit[1]].getX();
int y = gridLabel[digit[0]][digit[1]].getY();
layerUi.placeViewport(x, y);
}
public void stopShuffle() {
layerUi.removeViewPort();
}
public void setupGridView() {
gridX = gridLabel[0][0].getX();
gridY = gridLabel[0][0].getY();
gridWidth = gridLabel[0][0].getWidth();
gridHeight = gridLabel[0][0].getHeight();
mainPanel.setValues(gridX, gridY);
layerUi.setViewSize(gridWidth * viewportDimensions, gridHeight * viewportDimensions);
}
public void setImage(BufferedImage img) {
if (!isGridInitialized) {
setupGridView();
isGridInitialized = true;
}
BufferedImage sendImg = Scalr.resize(img, Scalr.Mode.FIT_EXACT, gridWidth * gridNos, gridHeight * gridNos, Scalr.OP_ANTIALIAS);
layerUi.setupViewport(img);
mainPanel.paintImage(img);
}
public JLayer<JPanel> getComponent() {
return gridLayer;
}
}
class RegisterUI extends LayerUI<JPanel> {
private int viewX, viewY, viewWidth, viewHeight;
private boolean shuffleIsRunning = false;
private BufferedImage viewportImage = null;
private void drawPCCP(Graphics g, int w, int h) {
Graphics2D g2 = ((Graphics2D) g);
Color c = new Color(1.0f, 1.0f, 1.0f, 0.7f);
g2.setPaint(c);
g2.fillRect(0, 0, w, h);
BufferedImage highlightGrid = Scalr.pad(Scalr.crop(viewportImage, viewX, viewY, viewWidth, viewHeight), 2, Color.BLACK, Scalr.OP_ANTIALIAS);
g2.drawImage(highlightGrid, viewX, viewY, null);
g2.dispose();
}
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
int w = c.getWidth();
int h = c.getHeight();
if (shuffleIsRunning) {
drawPCCP(g, w, h);
}
}
public void setupViewport(BufferedImage bi) {
viewportImage = bi;
}
public void setViewSize(int w, int h) {
viewWidth = w;
viewHeight = h;
}
public void placeViewport(int x, int y) {
viewX = x;
viewY = y;
if (!shuffleIsRunning) {
shuffleIsRunning = true;
}
firePropertyChange("shuffleui", 0, 1);
}
public void removeViewPort() {
if (!shuffleIsRunning) {
return;
}
viewX = 0;
viewY = 0;
viewWidth = 0;
viewHeight = 0;
shuffleIsRunning = false;
firePropertyChange("shuffleui", 0, 1);
}
#Override
public void applyPropertyChange(PropertyChangeEvent evt, JLayer<? extends JPanel> l) {
if ("disableui".equals(evt.getPropertyName()) || "shuffleui".equals(evt.getPropertyName())) {
l.repaint();
}
}
}
class ImagePanel extends JPanel {
private BufferedImage displayImage = null;
private int x, y;
public void setValues(int x, int y) {
this.x = x;
this.y = y;
}
public void paintImage(BufferedImage bi) {
System.out.print(bi);
displayImage = bi;
repaint(); // repaint calls paintComponent method internally
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(displayImage, x, y, this); // To Paint the image on the panel
}
}
}
Instead of using AlphaComposite directly, as shown here, try RescaleOp to alter the image's color/alpha bands, as shown in this example. This will allow you to mute the tone of the entire image as desired. Copy a portion of the original image using getSubimage() to restore the highlight.

Drawing on a Jframe from two different classes

I am trying to create a program that record mouse clicks, draw lines between those points and after some calculations display some circles through a button call. My problem is that I can display the lines or the circles, but not both.
I know there is something overlapping something else, but I am very new to Java and I don't know how to fix it. Here is the code:
package fempack;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.lang.Math;
public class MainFem extends JPanel {
final DrawPoints Npoints = new DrawPoints();
final DrawLines Nline = new DrawLines();
private static final long serialVersionUID = 1L;
private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
public int Xpoint[][] = new int[500][30];
public int Ypoint[][] = new int[500][30];
private double Xmpoint[][] = new double[500][1000]; // [i γραμμή][συντεταγμένη Χ]
private double Ympoint[][] = new double[500][1000];
private double Vec[][][] = new double[500][2][500]; // [i γραμμή][0,1][0α 1β]
private double dist[] = new double[10000];
private boolean drawing;
private int c1;
private int c2;
public MainFem() {
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
// -------------- Draw by clicking -----------------------
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if(SwingUtilities.isRightMouseButton(e)){
drawing=false;
c2++;
}
if(SwingUtilities.isLeftMouseButton(e)){
p1 = e.getPoint();
Xpoint[c1][c2] = p1.x;
Ypoint[c1][c2] = p1.y;
if (c1 > 3) {
for (int j = 0; j<c2+1; j++){
for (int i = 0; i<c1; i++){
if ((Math.abs(Xpoint[i][j]-Xpoint[c1][c2]) < 10) && (Math.abs(Ypoint[i][j]-Ypoint[c1][c2]) < 10)) {
Xpoint[c1][c2] = Xpoint[i][j];
Ypoint[c1][c2] = Ypoint[i][j];
System.out.println(Xpoint[i][j]);
}
}
}
}
if (drawing == true){
Nline.addLine(Xpoint[c1][c2], Ypoint[c1][c2], Xpoint[c1-1][c2], Ypoint[c1-1][c2]);
}
c1++;
drawing = true;
}
}
}
// ---------------- Create Mesh Points --------------------------
public void createmesh() {
int mdi = 0;
for (int j = 0; j<=c2; j++){
for (int i = 0; i<c1-1; i++){
// Υπολογισμός a και b συνιστωσών της εξίσωσης της γραμμής
Vec[i][0][mdi] = (Ypoint[i+1][j] - Ypoint[i][j])/(Xpoint[i+1][j] - Xpoint[i][j]);
Vec[i][1][mdi] = Ypoint[i][j] - Xpoint[i][j]*Vec[i][1][mdi];
// Υπολογισμός μέτρου διανύσματος
dist[mdi] = Math.sqrt(Math.pow(Xpoint[i][j] - Xpoint[i+1][j], 2) + Math.pow(Ypoint[i][j] - Ypoint[i+1][j], 2) );
// Υπολογισμός ενδιάμεσον σημείων
int nkom = 3;
double xa = Xpoint[i][j];
double ya = Ypoint[i][j];
for (int ii = 0; ii <nkom; ii++) {
double a = Vec[i][0][mdi];
double b = Vec[i][1][mdi];
Xmpoint[i][ii] = (-((2*a)*(b - ya) - 2*xa) + Math.sqrt(Math.abs(Math.pow(((2*a)*(b - ya) - 2*xa), 2) - 4*(1 + a*a)*(xa*xa + Math.pow((b - ya),2) - Math.pow(dist[mdi]/nkom,2)))))/(2 + 2*a*a);
Ympoint[i][ii] = a*Xmpoint[i][ii] + b;
double xm11 = Xmpoint[i][ii];
double ym11 = Ympoint[i][ii];
int xm1 = (int) xm11;
int ym1 = (int) ym11;
Npoints.addPoint(xm1, ym1);
System.out.println("i:" + ym11 + "...ii:" + ym1 );
xa = Xmpoint[i][ii];
ya = Ympoint[i][ii];
}
mdi++;
}
}
}
//------------------------- Display ---------------------------
private void display() {
JFrame f = new JFrame("LinePanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setPreferredSize(new Dimension(500, 600));
f.setLocationRelativeTo(null);
f.add(Npoints);
f.add(Nline);
JPanel buttonsPanel = new JPanel();
//-----------------Complete---------------
JButton dcomp = new JButton("Complete");
buttonsPanel.add(dcomp);
dcomp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
createmesh();
}
});
//------------------Clean-------------------
JButton clearButton = new JButton("Clear");
buttonsPanel.setBorder(BorderFactory.createLineBorder(Color.black));
buttonsPanel.setPreferredSize(new Dimension(500, 100));
f.add(buttonsPanel, BorderLayout.SOUTH);
buttonsPanel.add(clearButton);
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Nline.clearLines();
}
});
f.pack();
f.setVisible(true);
f.add(this);
}
//---------------------------------------------------------
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MainFem().display();
}
});
}
}
Class to draw lines:
package fempack;
import java.awt.Graphics;
import java.util.LinkedList;
import javax.swing.JPanel;
public class DrawLines extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public DrawLines() {
}
private static class Line{
final int x1;
final int y1;
final int x2;
final int y2;
public Line(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
private final LinkedList<Line> lines = new LinkedList<Line>();
public void addLine(int x1, int x2, int x3, int x4) {
lines.add(new Line(x1,x2,x3,x4));
repaint();
}
public void clearLines() {
lines.clear();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lines) {
// System.out.println(line);
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
And class to draw Circles:
package fempack;
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.LinkedList;
public class DrawPoints extends JPanel {
private static final long serialVersionUID = 1L;
public DrawPoints() {
}
private static class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
private final LinkedList<Point> points = new LinkedList<Point>();
public void addPoint(int x, int y) {
points.add(new Point(x,y));
// System.out.println(x);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : points) {
// System.out.println(point);
g.drawOval(point.x, point.y, 5, 5);
}
}
}
Here is my solution to draw the points added in the createmesh(). I did not modify any handling of the points you got from the mouse position. I just tried to refactor and clean up your code.
Now DrawLine and DrawPoint are no more JPanel's they just hold the data you give them and draw to the Graphics-Object you pass to them in public void draw(Graphics g) method, which is called on paint in the DrawPanel-Class. DrawPanel inherits from JPanel and overrides void PaintComponent(Graphics g); to realize this (Thanks to MadProgrammer ;). Also DrawPanel handels the MouseEvents to put the mouse-positions into DrawLines- and DrawPoints-objects.
MainWindow inherits from JFrame and is the MainWindow. It creates all GUI-elements and calls the DrawPanel if necessary.
MainWindow:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainWindow extends JFrame {
private static final long serialVersionUID = 6755417048009930291L;
// begin gui components
JButton clearButton = null;
JButton dcomp = null;
JPanel buttonsPanel = null;
DrawPanel drawPanel = null;
// end gui components
public MainWindow(){
// Add ButtonPanel
add(getDrawPanel(), BorderLayout.CENTER);
add(getButtonPanel(), BorderLayout.SOUTH);
// Add Buttons
getButtonPanel().add(getDcomp());
getButtonPanel().add(getClearButton());
addMouseListener(getDrawPanel());
}
// begin getters and setters for gui components
private DrawPanel getDrawPanel(){
if(drawPanel == null){
drawPanel = new DrawPanel();
drawPanel.setVisible(true);
}
return drawPanel;
}
private JPanel getButtonPanel() {
if(buttonsPanel == null){
buttonsPanel = new JPanel();
buttonsPanel.setBorder(BorderFactory.createLineBorder(Color.black));
buttonsPanel.setPreferredSize(new Dimension(500, 100));
}
return buttonsPanel;
}
private JButton getClearButton() {
if(clearButton == null){
clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getDrawPanel().clearLines();
}
});
}
return clearButton;
}
private JButton getDcomp() {
if(dcomp == null){
dcomp = new JButton("Complete");
dcomp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getDrawPanel().createmesh();
getDrawPanel().repaint();
}
});
}
return dcomp;
}
// end begin getters and setters for gui components
//as always program entry-point
public static void main(String[] args) {
MainWindow wnd = new MainWindow();
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wnd.setPreferredSize(new Dimension(500, 600));
wnd.setLocationRelativeTo(null);
wnd.pack();
wnd.setVisible(true);
}
}
DrawPanel:
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawPanel extends JPanel implements MouseListener {
private static final long serialVersionUID = -7726303639184194659L;
// begin members
private DrawLines dlines;
private DrawPoints dpoints;
// dont know what these members do
private Point p1 = new Point(100, 100);
public int Xpoint[][] = new int[500][30];
public int Ypoint[][] = new int[500][30];
private double Xmpoint[][] = new double[500][1000]; // [i
// γραμμή][συντεταγμένη
// Χ]
private double Ympoint[][] = new double[500][1000];
private double Vec[][][] = new double[500][2][500]; // [i γραμμή][0,1][0α
// 1β]
private double dist[] = new double[10000];
private boolean drawing;
private int c1;
private int c2;
// end members
public DrawPanel() {
dlines = new DrawLines();
dpoints = new DrawPoints();
addMouseListener(this);
}
// begin class logic
public void clearLines(){
dlines.clearLines();
repaint();
}
// dont know what this does
public void createmesh() {
int mdi = 0;
for (int j = 0; j <= c2; j++) {
for (int i = 0; i < c1 - 1; i++) {
// Υπολογισμός a και b συνιστωσών της εξίσωσης της γραμμής
Vec[i][0][mdi] = (Ypoint[i + 1][j] - Ypoint[i][j])
/ (Xpoint[i + 1][j] - Xpoint[i][j]);
Vec[i][1][mdi] = Ypoint[i][j] - Xpoint[i][j] * Vec[i][1][mdi];
// Υπολογισμός μέτρου διανύσματος
dist[mdi] = Math.sqrt(Math.pow(Xpoint[i][j] - Xpoint[i + 1][j],
2) + Math.pow(Ypoint[i][j] - Ypoint[i + 1][j], 2));
// Υπολογισμός ενδιάμεσον σημείων
int nkom = 3;
double xa = Xpoint[i][j];
double ya = Ypoint[i][j];
for (int ii = 0; ii < nkom; ii++) {
double a = Vec[i][0][mdi];
double b = Vec[i][1][mdi];
Xmpoint[i][ii] = (-((2 * a) * (b - ya) - 2 * xa) + Math
.sqrt(Math.abs(Math.pow(
((2 * a) * (b - ya) - 2 * xa), 2)
- 4
* (1 + a * a)
* (xa * xa + Math.pow((b - ya), 2) - Math
.pow(dist[mdi] / nkom, 2)))))
/ (2 + 2 * a * a);
Ympoint[i][ii] = a * Xmpoint[i][ii] + b;
double xm11 = Xmpoint[i][ii];
double ym11 = Ympoint[i][ii];
int xm1 = (int) xm11;
int ym1 = (int) ym11;
dpoints.addPoint(xm1, ym1);
System.out.println("i:" + ym11 + "...ii:" + ym1);
xa = Xmpoint[i][ii];
ya = Ympoint[i][ii];
}
mdi++;
}
}
}
// end class logic
// begin MouseListener implementation
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
drawing = false;
c2++;
}
if (SwingUtilities.isLeftMouseButton(e)) {
p1 = e.getPoint();
Xpoint[c1][c2] = p1.x;
Ypoint[c1][c2] = p1.y;
if (c1 > 3) {
for (int j = 0; j < c2 + 1; j++) {
for (int i = 0; i < c1; i++) {
if ((Math.abs(Xpoint[i][j] - Xpoint[c1][c2]) < 10)
&& (Math.abs(Ypoint[i][j] - Ypoint[c1][c2]) < 10)) {
Xpoint[c1][c2] = Xpoint[i][j];
Ypoint[c1][c2] = Ypoint[i][j];
System.out.println(Xpoint[i][j]);
}
}
}
}
if (drawing == true) {
dlines.addLine(Xpoint[c1][c2], Ypoint[c1][c2],
Xpoint[c1 - 1][c2], Ypoint[c1 - 1][c2]);
}
c1++;
drawing = true;
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
// end MouseListener implementation
// beging PAINTING
#Override
protected void paintComponent(Graphics g) {
System.out.println("paintComponent");
super.paintComponent(g);
dlines.draw(g);
dpoints.draw(g);
}
// end PAINTING
}
DrawPoints:
import java.awt.Graphics;
import java.util.LinkedList;
public class DrawPoints {
public DrawPoints() {
}
private static class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
private final LinkedList<Point> points = new LinkedList<Point>();
public void addPoint(int x, int y) {
points.add(new Point(x, y));
}
public void draw(Graphics g){
for (Point point : points) {
g.drawOval(point.x, point.y, 5, 5);
}
}
}
DrawLines:
import java.awt.Graphics;
import java.util.LinkedList;
public class DrawLines{
public DrawLines() {
}
private static class Line {
final int x1;
final int y1;
final int x2;
final int y2;
public Line(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
private final LinkedList<Line> lines = new LinkedList<Line>();
public void addLine(int x1, int x2, int x3, int x4) {
lines.add(new Line(x1, x2, x3, x4));
}
public void clearLines() {
lines.clear();
}
public void draw(Graphics g){
for (Line line : lines) {
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
I think its a good idea to handle things like this. You want to paint on a Panel or something so pass it to the object which hold your data and let them draw to their common canvas like I did with the void draw(Graphics g) method in DrawPoints- and DrawLines-class.
I hope this will help you.
Fell free to ask if something is unclear.

JLabel won't display image - NullPointerException

this is my first Java GUI program, and really only my second java program, so take it easy on me :) My program is a result of a lot of googling and reading java docs. My problem is that I have a sprite sheet of 52 cards, and am attempting to save these cards individually to a Buffered Image array using subImage, and just for testing purposes, display all 52 in a window. The File is in the correct directory I made sure of that. I believe that my problem lies with my use of Jlabels, or simply a foolish mistake. Anyways, here is my class that does the sprite sheet splitting
package gui;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class crdimgs extends JPanel {/**
*
*/
static final long serialVersionUID = 1L;
public final int width = 10;
public final int height = 20;
public int rows = 13;
public int cols = 5;
public BufferedImage image;
File cardimg = new File("Cards.jpg");
BufferedImage cards[];
public void loadsplit(File loadimage){
try{
image = ImageIO.read(loadimage);
} catch(Exception error){
System.out.print("error");
}
cards = new BufferedImage[cols*rows];
}
public crdimgs() {
loadsplit(cardimg);
setLayout(new GridLayout(rows, cols, 1, 1));
int x = 0;
int y = 0;
int subimg = 0;
for( int i = 0; i < rows; i++)
{
JPanel panel = new JPanel();
cards[subimg] = new BufferedImage(width, height, 5);
cards[subimg] = image.getSubimage(x, y, width, height);
panel.add(new JLabel(new ImageIcon(cards[subimg])));
add(panel);
x+=width;
subimg++;
}
y+=height;
x=0;
}
}
}
And my Main class
package gui;
import javax.swing.JFrame;
import java.awt.Color;
public class cards extends JFrame {
private static final long serialVersionUID = 1L;
public cards(){
setTitle("Poker");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1000, 700);
setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.GREEN);
setVisible(true);
setResizable(false);
add(new crdimgs());
}
public static void main(String[] args){
new cards();
}
}
Errors I receive at the moment are:
errorException in thread "main" java.lang.NullPointerException
at gui.crdimgs.<init>(crdimgs.java:53)
at gui.cards.<init>(cards.java:22)
at gui.cards.main(cards.java:28)
Likely your image is null, possibly because you're looking in the wrong place for it, but to find out, check out which line is 53.
Suggestions:
Start small and then build on. Don't try to do complex image manipulation until you first successfully read and show a single image.
Check where Java is looking for the image, because likely it isn't where you think it is. Put System.out.println(System.getProperty("user.dir")); in your code to find out.
Call setVisible(true) after adding all components to the JFrame.
Improve your exception display code by printing the stack trace: error.printStackTrace() (thanks Mad!).
For example:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class PlayingCardTest {
public static void main(String[] args) {
String pathToDeck = "http://www.jfitz.com/cards/classic-playing-cards.png";
try {
final List<ImageIcon> cardImgList = CreateCards.createCardIconList(pathToDeck);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Moving Cards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CardGameTable(cardImgList, frame));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
#SuppressWarnings("serial")
class CardGameTable extends JLayeredPane {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color BASE_COLOR = new Color(0, 80, 0);
private static final int CARD_COUNT = 20;
private static final int WIDTH_SHOWING = 20;
private JPanel basePane = new JPanel(null);
public CardGameTable(List<ImageIcon> cardImgList, final JFrame frame) {
basePane.setSize(getPreferredSize());
basePane.setBackground(BASE_COLOR);
add(basePane, JLayeredPane.DEFAULT_LAYER);
final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane);
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
for (int i = 0; i < CARD_COUNT; i++) {
JLabel card = new JLabel(cardImgList.remove(0));
card.setSize(card.getPreferredSize());
int x = (PREF_W / 2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i) / 2 -
card.getPreferredSize().width / 2;
int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2;
card.setLocation(x, y);
basePane.add(card);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
class MyMouseAdapter extends MouseAdapter {
private JLabel selectedCard = null;
private JLayeredPane cardGameTable = null;
private JPanel basePane = null;
private int deltaX = 0;
private int deltaY = 0;
public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) {
this.cardGameTable = gameTable;
this.basePane = basePane;
}
#Override
public void mousePressed(MouseEvent mEvt) {
Component comp = basePane.getComponentAt(mEvt.getPoint());
if (comp != null && comp instanceof JLabel) {
selectedCard = (JLabel) comp;
basePane.remove(selectedCard);
basePane.revalidate();
basePane.repaint();
cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER);
cardGameTable.revalidate();
cardGameTable.repaint();
deltaX = mEvt.getX() - selectedCard.getX();
deltaY = mEvt.getY() - selectedCard.getY();
}
}
#Override
public void mouseReleased(MouseEvent mEvt) {
if (selectedCard != null) {
cardGameTable.remove(selectedCard);
cardGameTable.revalidate();
cardGameTable.repaint();
basePane.add(selectedCard, 0);
basePane.revalidate();
basePane.repaint();
selectedCard = null;
}
}
#Override
public void mouseDragged(MouseEvent mEvt) {
if (selectedCard != null) {
int x = mEvt.getX() - deltaX;
int y = mEvt.getY() - deltaY;
selectedCard.setLocation(x, y);
cardGameTable.revalidate();
cardGameTable.repaint();
}
}
}
class CreateCards {
private static final int SUIT_COUNT = 4;
private static final int RANK_COUNT = 13;
public static List<ImageIcon> createCardIconList(String pathToDeck)
throws MalformedURLException, IOException {
BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck));
int width = fullDeckImg.getWidth();
int height = fullDeckImg.getHeight();
List<ImageIcon> iconList = new ArrayList<ImageIcon>();
for (int suit = 0; suit < SUIT_COUNT; suit++) {
for (int rank = 0; rank < RANK_COUNT; rank++) {
int x = (rank * width) / RANK_COUNT;
int y = (suit * height) / SUIT_COUNT;
int w = width / RANK_COUNT;
int h = height / SUIT_COUNT;
BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h);
iconList.add(new ImageIcon(cardImg));
}
}
Collections.shuffle(iconList);
return iconList;
}
}
Which shows:

JXMultiSplitPane causes repaint during slider adjustment?

I seem to be getting frequent repaint requests during adjustment of the splitter in JXMultiSplitPane. (see program below)
Why?
I have setContinuousLayout(false).
Just to clarify: I understand the repaint should occur after the split-panes are resized. But during splitter adjustment, nothing is being resized; the splitter is moving around on the screen.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jdesktop.swingx.JXMultiSplitPane;
import org.jdesktop.swingx.MultiSplitLayout;
public class MultiVerticalPane<T extends Component> extends JPanel
{
final private List<T> components;
public MultiVerticalPane(List<? extends T> components,
List<Double> weights)
{
this.components = new ArrayList<T>(components);
final int n = this.components.size();
if (weights != null && weights.size() != n)
throw new IllegalArgumentException(
"weights and components should have same length");
JXMultiSplitPane msp = new JXMultiSplitPane();
msp.setContinuousLayout(false);
msp.getMultiSplitLayout().setModel(createSplitModel(weights));
int i = 0;
for (T component : components)
{
msp.add(component, nodeTitle(i++));
}
setLayout(new BorderLayout());
add(msp, BorderLayout.CENTER);
}
private MultiSplitLayout.Split createSplitModel(
List<Double> weights)
{
LinkedList<MultiSplitLayout.Node> nodes =
new LinkedList<MultiSplitLayout.Node>();
int i = 0;
double wtot = 0;
for (double w : weights)
{
wtot += w;
}
for (double w : weights)
{
if (i > 0)
nodes.addFirst(new MultiSplitLayout.Divider());
MultiSplitLayout.Leaf leaf =
new MultiSplitLayout.Leaf(nodeTitle(i++));
leaf.setWeight(w/wtot);
nodes.addFirst(leaf);
}
MultiSplitLayout.Split split =
new MultiSplitLayout.Split();
split.setRowLayout(false);
split.setChildren(nodes);
return split;
}
private String nodeTitle(int i) {
return String.format("%02d", i);
}
/************ test methods *************/
private interface Painter
{
public void paint(Graphics g, Rectangle bounds);
}
static private class RelativeGraphics
{
final private Graphics g;
final private double xofs;
final private double yofs;
final private double xscale;
final private double yscale;
private double cx;
private double cy;
public RelativeGraphics(Graphics g, Rectangle bounds)
{
this.g = g;
this.cx = 0;
this.cy = 0;
this.xofs = bounds.getMinX();
this.yofs = bounds.getMaxY();
this.xscale = bounds.getWidth();
this.yscale = -bounds.getHeight();
}
public void moveTo(double x, double y)
{
this.cx = x;
this.cy = y;
}
public void lineTo(double x, double y)
{
this.g.drawLine(
(int)(this.cx*this.xscale+this.xofs),
(int)(this.cy*this.yscale+this.yofs),
(int)(x*this.xscale+this.xofs),
(int)(y*this.yscale+this.yofs)
);
moveTo(x,y);
}
public void rmoveTo(double dx, double dy)
{
moveTo(this.cx+dx, this.cy+dy);
}
public void rlineTo(double dx, double dy)
{
lineTo(this.cx+dx, this.cy+dy);
}
}
// adapted from http://en.wikipedia.org/wiki/Hilbert_curve#Java
static private class HilbertCurve
{
final private RelativeGraphics rg;
final private double d;
public HilbertCurve(RelativeGraphics rg, int level)
{
this.rg = rg;
double d0 = 1.0;
for (int i = level; i > 0; i--)
d0 /= 2;
this.d = d0;
rg.rmoveTo(d0/2, d0/2);
drawCurveUp(level);
}
private void drawCurveUp(int n)
{
if (n > 0) {
drawCurveLeft(n-1); this.rg.rlineTo(0, this.d);
drawCurveUp(n-1); this.rg.rlineTo(this.d, 0);
drawCurveUp(n-1); this.rg.rlineTo(0, -this.d);
drawCurveRight(n-1);
}
}
private void drawCurveLeft(int n)
{
if (n > 0) {
drawCurveUp(n-1); this.rg.rlineTo(this.d, 0);
drawCurveLeft(n-1); this.rg.rlineTo(0, this.d);
drawCurveLeft(n-1); this.rg.rlineTo(-this.d, 0);
drawCurveDown(n-1);
}
}
private void drawCurveRight(int n)
{
if (n > 0) {
drawCurveDown(n-1); this.rg.rlineTo(-this.d, 0);
drawCurveRight(n-1); this.rg.rlineTo(0, -this.d);
drawCurveRight(n-1); this.rg.rlineTo(this.d, 0);
drawCurveUp(n-1);
}
}
private void drawCurveDown(int n)
{
if (n > 0) {
drawCurveRight(n-1); this.rg.rlineTo(0, -this.d);
drawCurveDown(n-1); this.rg.rlineTo(-this.d, 0);
drawCurveDown(n-1); this.rg.rlineTo(0, this.d);
drawCurveLeft(n-1);
}
}
}
static private class HilbertPainter implements Painter
{
final private int level;
public HilbertPainter(int level) { this.level = level; }
#Override public void paint(Graphics g, Rectangle bounds) {
new HilbertCurve(
new RelativeGraphics(g,
new Rectangle(new Point(0,0),bounds.getSize())),
this.level);
}
}
static private class PainterPanel extends JPanel
{
final private Painter painter;
public PainterPanel(Painter painter)
{
this.painter = painter;
setBackground(Color.WHITE);
setForeground(Color.RED);
}
#Override public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.painter.paint(g, getBounds());
}
}
public static void main(String[] args) { test(); }
private static void test()
{
JFrame frame = new JFrame("MultiVerticalPane test");
List<JPanel> panels = new ArrayList<JPanel>();
List<Double> weights = Arrays.asList(1.0,1.0,2.0,4.0,8.0);
for (int i = 0; i < 5; ++i)
{
panels.add(new PainterPanel(new HilbertPainter(i+4)
{
int count = 0;
#Override public void paint(Graphics g,
Rectangle bounds)
{
super.paint(g,
new Rectangle(bounds.getLocation(),
new Dimension(bounds.width,
bounds.height-10)));
g.drawString(String.format("%d", this.count++),
0, bounds.height);
}
}
));
}
MultiVerticalPane<Component> mvp =
new MultiVerticalPane<Component>(panels, weights);
mvp.setPreferredSize(new Dimension(360,720));
frame.setContentPane(mvp);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
It looks like setContinuousLayout() affects revalidate(), not repaint().
Its not a 'direct' answer. I just put it here since I run out of space in a comment.
I do not think it is too frequent? Why would you think that did you compare it with any other component?
What I think is that every resize a component detects it calls repaint. On top of it goes how a layout manager handles resizing. Please observe that when, for example, you resize the top most panel and are dragging it down it is very rarely repainted, which you cannot say about his neighbour. The situation is reversed when you drag the slider up.
BTW: Might I ask why would you worry about how often and which part of the split pane is repainted?
Please bear in mind that I am not an expert on the internals of the repaint mechanism of this component but I would doubt that SwingX guys would step away from the defaults in this regards.

Categories